Using python script to find symbols in. so library file

Keywords: Linux shell Python Permission denied

Using python script to find symbols in. so library file


When writing a Makefile recently, you always report that you cannot find a symbol error, such as:

/usr/bin/ld: /tmp/ccnwoS4i.o: undefined reference to symbol '_ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE'
/usr/bin/ld: /usr/lib/libOgreRTShaderSystem.so.1.12.6: error adding symbols: DSO missing from command line

When encountering a long error, it is usually to link fewer library files when linking. As long as the corresponding library is linked, for example, this error can be fixed by adding - loggershadersystem at compile time.

Therefore, when such errors occur, it is necessary to find out which library file is less linked.

Preparatory knowledge

Naming rules and storage / search path of Linux dynamic link library

The dynamic link library in Linux system is a. so(Shared Object) file. Its default storage locations are / usr/lib / and / lib /.

Its naming rule is generally lib + library name +. So. For example, the library file corresponding to the library ogrrtshadersystem is L ib OgreRTShaderSystem.so . When gcc compiles, the library name is passed in instead of the library file name. For example, if you want to link the library ogrrtshadersystem at compile time, you need to call it in gcc in the following way:

g++ test.cpp -o test -lOgreRTShaderSystem

gcc will look for L in the following order ibOgreRTShaderSystem.so This library file:

  1. The dynamic library search path specified when compiling the target code;
  2. Environment variable LD_LIBRARY_PATH: the dynamic library search path specified by path;
  3. Configuration file / etc/ ld.so.conf Dynamic library search path specified in. D / *;
  4. Default dynamic library search path / lib;
  5. The default dynamic library search path is / usr/lib.

Search files in Linux

In Linux, you can use the find command to search for files. Here, take Manjaro system as an example.

The Linux find command is used to find files in the specified directory. Any string before the parameter will be treated as the name of the directory you want to find. If you use this command without setting any parameters, the find command looks for subdirectories and files in the current directory. All the subdirectories and files found will be displayed.

The general syntax is:

find   path   -option

Common parameters include:

  • -amin n: read in the last n minutes
  • -atime n: files read in the last n days
  • -ipath p, -path p: file whose path name matches p, and ipath ignores case
  • -name name, -iname name: the file whose name matches name. iname ignores case
  • -size n: file size is n unit, b represents 512 byte block, c represents number of characters, k represents kilo bytes, w is two bytes
  • -Type c: file of type c

Here we use the - name parameter. We use the following command to find the. so library file starting with libOgre:

find /usr/lib/ -name 'libOgre*.so'

Linux browsing symbol list in. so library file

In Linux, you can use the nm command to list the symbols in the specified library file.

nm is the abbreviation of names. nm command is mainly used to list symbols in some files (in other words, some functions, global variables, etc.).

Here we use the - D(– dynamic) parameter, which is used to display dynamic symbols. This option is only meaningful for dynamic targets, such as shared libraries of a specific type.

For example, find / usr/lib/libOgreBites.so Symbols in:

nm -D /usr/lib/libOgreBites.so

The results are similar to the following:

0000000000046020 B __bss_start
                 U commandWidgetClass
                 U __cxa_allocate_exception
                 U __cxa_atexit
                 U __cxa_begin_catch
                 U __cxa_call_unexpected
                 U __cxa_end_catch
                 w __cxa_finalize
                 U __cxa_free_exception
                 U __cxa_guard_abort
                 U __cxa_guard_acquire
                 U __cxa_guard_release
                 U __cxa_rethrow
                 U __cxa_throw
                 U __dynamic_cast
0000000000046020 D _edata
       ...
       ...
0000000000039160 u _ZZNSt8__detail18__to_chars_10_implIjEEvPcjT_E8__digits
00000000000380e0 u _ZZNSt8__detail18__to_chars_10_implImEEvPcjT_E8__digits

You can use grep to find the symbol (_ ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE)

nm -D /usr/lib/libOgreBites.so | grep _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE

The results are as follows:

e8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE
                 U _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE

Calling shell commands in Python

In Python, you can call shell commands through the subprocess module. The method is to call the Popen() function directly:

import subprocess
child = subprocess.Popen('ls ~ -a', shell=True)

When there is a sequence requirement for the front and back processes, the process of wait() needs to be added to ensure that the latter process starts after the completion of the previous process:

child.wait()

If you want to save the result of running the shell command in subprocess into a variable, you need to specify that the stdout parameter in Popen() is subprocess.PIPE . And use communicate() to get the subprocess.PIPE Read results in:

child = subprocess.Popen('ls ~ -a', shell=True, stdout=subprocess.PIPE)
child.wait()
result_binary = child.communicate()

The result here is a tuple, the first element of which is a binary string that holds the running result, so it needs to be decoded:

result = result_binary[0].decode("utf-8")

Complete procedure

import subprocess

sub = subprocess.Popen('find /usr/lib/ -name \'libOgre*.so\'', shell=True, stdout=subprocess.PIPE)
sub.wait()
out = sub.communicate()
res = out[0].decode("utf-8").split('\n')
for item in res:
    if len(item):
        tmp_sub = subprocess.Popen('nm -D {} | grep _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE'.format(item), shell=True, stdout=subprocess.PIPE)
        tmp_sub.wait()
        tmp = tmp_sub.communicate()[0]
        if tmp:
            print('file: {}'.format(item))
            print('\t{}'.format(tmp))

Operation result:

find: '/usr/lib/firmware/b43legacy': Permission denied
find: '/usr/lib/firmware/b43': Permission denied
file: /usr/lib/libOgreRTShaderSystem.so
        b'00000000000c6fa0 T _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE\n'
file: /usr/lib/libOgreBites.so
        b'                 U _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE\n'

The observation shows that there should be no link ibOgreRTShaderSystem.so .

Reference link:
Where gcc looks for header and library files
Linux find command
nm command in linux

Posted by sujithnair on Thu, 25 Jun 2020 20:43:02 -0700