C/C++ -- Lib库文件nm调试之符号表

Linux库文件详解
本文介绍了在Linux环境下如何创建和使用C/C++库文件,包括静态库(.a)和动态库(.so)的区别及应用场景,同时提供了如何使用nm命令查看库文件信息的方法。
本文主要介绍了一下在Linux下开发c/c++时候,不可避免的会开发或者生成.o .a .so这种中间库状态的文件(可能是自己写了一个lib让别人调用,或者提供.c/.cpp文件嵌入别人的Makefile工程)。如何查看这些库文件的一些基本信息。有时候大家编译程序时候(确切的说是链接器链接的时候)很多错误例如"undefine reference",之类的常见错误,原因就是因为没有找到.o .a .so的库文件,导致链接失败。

        -------------------------------------------------------------------------------

        1、Linux库文件

        2、库文件的使用方式

        3、利用tar/nm查看库文件的信息

        -------------------------------------------------------------------------------

       1、库文件的定义之类的就不在此累赘了,有兴趣Google之。说白了就是我们写好一些对应的.h和.c(.cpp)文件,然后通过编译器的编译,生成中间代码供他人使用,他人只需要将你的中间代码include进自己的程序即可。注意,编译器编译成最终可执行的文件需要好几步,基本可以分为:文本解析->语法解析->此法分析->预处理分析->编译->连接。生成中间库是没有链接阶段的,在Linux Gcc下通过-C参数指定只编译不链接,所以如果写了一个.c文件用到了比如pthread_create之类的外部调用,在Gcc -C编译的时候不用-lpthread因为这个时候是不需要链接的。

      2、(对库文件熟悉话直接跳过)在各个系统平台上,库文件的格式和形式各不相同,Windows下就是如同xxx.dll或者xxx.lib,*inux下就是xxx.so或者xxx.a。两种分别对应的是静态库和动态库,静态库会连同编译器编译链接进入程序成为程序的一部分,好处是作为程序的一部分不用每次运行时都去load(弊端是可能很多进程都用到这个库但是每个进程中都有一份,动态库的话内存中只有一份,通过重定向来加载),而且不会导致因库的缺失而运行失败,坏处是会导致可执行文件偏大。动态库是程序运行时动态加载到进程里去的,而且可以多进程共,并且方便软件更新,直接替换老的库即可。

      到底使用静态还是动态库取决于程序的使用上下文环境,一般第三方库都提供了两种版本,系统库的话一般都是动态链接库,因为同样系统下的库都是一样的。用Linux的Gcc举例:

      一、写了一个.h声明一个foo()函数,然后在.c或者.cpp中实现foo()函数

      二、gcc(g++) -c -o foo.o foo.c (注意此处不需要.h头文件,头文件只是对库的对外接口描述)

      三、生成静态库: ar -r libfoo.a foo.o (静态库.a其实就是.o文件的压缩包,注意这里不支持把.a打入.a)

             生成动态库: gcc foo.c -fPIC -shared -o libfoo.so(-fPIC意思是生成位置无关代码,因为动态库是运行时加载的,需要对代码进行重定向,不清楚可以Google一下)

      四、写个含有main函数的文件,并调用foo()函数 : gcc(g++) -o test test.c -lfoo,这里-lfoo意思是去找以lib开头的某.so或.a文件,默认优先找.so动态库

      需要注意一下的是,如果是cpp引用了c的库或.c那么头文件里要用externc "C"关键字来指定按c的方式读取(根本上是因为c和c++的函数签名不一致,因为c++支持重载,所以按c++的方式是找不到同名的c函数的)。在使用动态库的情况下,程序回去一些预定义的地方找.so文件。比如/usr/lib/下,如果需要自己指定,请修改/etc/ld.so.conf文件。并用ldconfig来刷新cache。

 

      3、如果我们需要查看自己写的库的信息时可以用nm来查看,如查看库中有哪些函数,有哪些全局变量,有哪些依赖别的库的东西等等,下面我们写一个例子来说明一下:

  1. #include <stdio.h>  
  2.   
  3. int g1;   
  4. int g2 = 0;  
  5.   
  6. static int g3;   
  7. static int g4=0;  
  8.   
  9. const int g5=0;  
  10.   
  11. static const int g6 = 0;  
  12.   
  13. int main(int argc, char *argv[])  
  14. {  
  15.     static int st = 0;  
  16.   
  17.     int t1;   
  18.     int t2 = 0;  
  19.   
  20.     const int t3 = 0;  
  21.   
  22.     printf("printf-function");  
  23.   
  24.     return 0;  
  25. }  
  26.   
  27. void foo1(){}  
  28. static void foo2(){}  
  1. void overload(int i){}  
  1. void overload(float i){}  


        linux的nm命令可以一个文件中的符号列表,列出以上代码Gcc -c编译出的a.o(a.a a.so)可以通过nm命令来查看其中的符号信息:

  1. 0000000000000000 t   
  2. 0000000000000000 d   
  3. 0000000000000000 b   
  4. 0000000000000000 r   
  5. 0000000000000000 r   
  6. 0000000000000000 n   
  7. 0000000000000000 n   
  8. 0000000000000000 B g1  
  9. 0000000000000004 B g2  
  10. 0000000000000008 b g3  
  11. 000000000000000c b g4  
  12. 000000000000001c r g5  
  13. 0000000000000020 r g6  
  14.                  U __gxx_personality_v0  
  15. 0000000000000000 T main  
  16. 0000000000000000 a nm.cpp  
  17.                  U printf  
  18. 000000000000003e T _Z4foo1v  
  19. 0000000000000044 t _Z4foo2v  
  20. 0000000000000054 T _Z8overloadf  
  21. 000000000000004a T _Z8overloadi  
  22. 0000000000000010 b _ZZ4mainE2st  

        其中左边第一列是符号的地址值,对应源码可以看出递增的规律。第二列是该符号的类型,第三列是符号的名称(比如函数名,变量名):

        符号类型:介绍几个最常用的,其他的如果遇到了直接Google:

           B --- 全局非初始化数据段(BBS段)的符号,其值表示该符号在bss段中的偏移,如g1

           b --- 全局static的符号,如g3

           r --- const型只读的变量(readonly)

           N --- debug用的符号

           T --- 位于代码区的符号,比如本文件里的函数main foo

           t  --- 位于代码区的符号,一般是static函数

           U --- 位于本文件外的调用函数或变量符号,比如系统的printf()函数

       这里要注意的是,本人使用g++编译的,所以是按c++的支持重载的函数风格编译的,可以看到所有函数均带了前缀和后缀,前缀代表属于类的名字,后缀代表参数列表的类型缩写,因为重载必须是区分参数类型,这里也可以看出,为什么返回值不同的函数不是重载,因为符号表里没有返回值的记录。

       例如两个overload函数的后缀分别是f和i代表一个是float型一个是int型(上面还有v ->void型)。

       nm命令对大家调试多模块的程序很有用处,大部分情况下可以解决"undefined reference"的问题,如果大家发现nm的另类很好的用法,也可以留言哈!!!
g++ -fdiagnostics-color=always -g '/thfs1/home/test653/shengjh/exam of CSRf1.cpp' -o '/thfs1/home/test653/shengjh/exam of CSRf1' -DAdd_ -DUSE_FORTRAN_UNDERSCORE -I/thfs1/software/eigen3/3.4.90-gcc9.3/include/eigen3 -I/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/include -I/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/include -L/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/lib -L/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib -L/thfs1/software/scalapack/2.2.2-gcc9.3.0-mpi-x/lib -L/thfs1/software/metis/5.1.0-gcc9.3.0/lib -L/thfs1/software/lapack/3.8.0-gcc9.3.0/lib -L/thfs1/software/blas/3.8.0-gcc9.3.0/lib -L/thfs1/software/openblas/0.3.30-gcc9.3.0/lib -Wl,--start-group -ldmumps -lmumps_common -lpord -lscalapack -lmetis -lopenblas -llapack -lgfortran -lm -Wl,--end-group -lmpi -lstdc++fsg++ -fdiagnostics-color=always -g '/thfs1/home/test653/shengjh/exam of CSRf1.cpp' -o '/thfs1/home/test653/shengjh/exam of CSRf1' -DAdd_ -DUSE_FORTRAN_UNDERSCORE -I/thfs1/software/eigen3/3.4.90-gcc9.3/include/eigen3 -I/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/include -I/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/include -L/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/lib -L/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib -L/thfs1/software/scalapack/2.2.2-gcc9.3.0-mpi-x/lib -L/thfs1/software/metis/5.1.0-gcc9.3.0/lib -L/thfs1/software/lapack/3.8.0-gcc9.3.0/lib -L/thfs1/software/blas/3.8.0-gcc9.3.0/lib -L/thfs1/software/openblas/0.3.30-gcc9.3.0/lib -Wl,--start-group -ldmumps -lmumps_common -lpord -lscalapack -lmetis -lopenblas -llapack -lgfortran -lm -Wl,--end-group -lmpi -lstdc++fsg++ -fdiagnostics-color=always -g '/thfs1/home/test653/shengjh/exam of CSRf1.cpp' -o '/thfs1/home/test653/shengjh/exam of CSRf1' -DAdd_ -DUSE_FORTRAN_UNDERSCORE -I/thfs1/software/eigen3/3.4.90-gcc9.3/include/eigen3 -I/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/include -I/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/include -L/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/lib -L/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib -L/thfs1/software/scalapack/2.2.2-gcc9.3.0-mpi-x/lib -L/thfs1/software/metis/5.1.0-gcc9.3.0/lib -L/thfs1/software/lapack/3.8.0-gcc9.3.0/lib -L/thfs1/software/blas/3.8.0-gcc9.3.0/lib -L/thfs1/software/openblas/0.3.30-gcc9.3.0/lib -Wl,--start-group -ldmumps -lmumps_common -lpord -lscalapack -lmetis -lopenblas -llapack -lgfortran -lm -Wl,--end-group -lmpi -lstdc++fs /usr/bin/ld: /thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib/libdmumps.a(dmumps_c.o): in function `dmumps_set_tmp_ptr_c__': mumps_c.c:(.text+0x44): undefined reference to `dmumps_set_tmp_ptr__' /usr/bin/ld: /thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib/libdmumps.a(dmumps_c.o): in function `dmumps_c': mumps_c.c:(.text+0x1db4): undefined reference to `dmumps_f77__' collect2: error: ld returned 1 exit status在实际运行代码时出现了这些问题,头文件如下#include <iostream> #define MUMPS_CALL #define dmumps_set_tmp_ptr_ dmumps_set_tmp_ptr__ #define dmumps_f77_ dmumps_f77__ #include <vector> #include <cmath> #include <fstream> #include <sstream> #include <chrono> #include <Eigen/Dense> #include <Eigen/Sparse> extern "C" { #define MUMPS_CALL #include "dmumps_c.h" // 显式声明使用单下划线符号 void dmumps_f77_(DMUMPS_STRUC_C* id); void dmumps_set_tmp_ptr_(DMUMPS_STRUC_C* id); // 添加缺失的初始化函数声明 void dmumps_init_(DMUMPS_STRUC_C* id, int* comm_fortran); } using namespace std; using namespace chrono; using namespace Eigen; typedef SparseMatrix<double, RowMajor> SparseMatrixR; typedef complex<double> cd; typedef SparseMatrix<cd, RowMajor> SparseMatrixC; // MUMPS 预定义常量 #define JOB_INIT -1 #define JOB_ANALYZE -2 #define JOB_FACTORIZE -3 #define JOB_SOLVE -4 #define JOB_END -5 #ifndef USE_COMM_WORLD #define USE_COMM_WORLD (-987654) #endif,json如下{ "tasks": [ { "type": "cppbuild", "label": "C/C++: g++ MUMPS build", "command": "g++", "args": [ "-fdiagnostics-color=always", "-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}", "-DAdd_", "-DUSE_FORTRAN_UNDERSCORE", // 关键添加 "-I/thfs1/software/eigen3/3.4.90-gcc9.3/include/eigen3", "-I/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/include", "-I/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/include", "-L/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/lib", "-L/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib", "-L/thfs1/software/scalapack/2.2.2-gcc9.3.0-mpi-x/lib", "-L/thfs1/software/metis/5.1.0-gcc9.3.0/lib", "-L/thfs1/software/lapack/3.8.0-gcc9.3.0/lib", "-L/thfs1/software/blas/3.8.0-gcc9.3.0/lib", "-L/thfs1/software/openblas/0.3.30-gcc9.3.0/lib", "-Wl,--start-group", "-ldmumps", "-lmumps_common", "-lpord", "-lscalapack", "-lmetis", "-lopenblas", "-llapack", "-lgfortran", "-lm", "-Wl,--end-group", "-lmpi", "-lstdc++fs" // 可能需要添加 C++ 文件系统库 ], "options": { "cwd": "${fileDirname}", "env": { "PATH": "/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/bin:${env:PATH}", "LD_LIBRARY_PATH": "/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/lib:/thfs1/software/openblas/0.3.30-gcc9.3.0/lib:/thfs1/software/gcc/9.3.0/lib64:${env:LD_LIBRARY_PATH}" } }, "problemMatcher": ["$gcc"], "group": "build" } ], "version": "2.0.0" }{ "version": "0.2.0", "configurations": [ { "name": "C/C++ 调试", "type": "cppdbg", "request": "launch", "program": "${fileDirname}/${fileBasenameNoExtension}", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [], "externalConsole": false, "MIMode": "gdb", "preLaunchTask": "C/C++: g++ MUMPS build", "miDebuggerPath": "/usr/bin/gdb", "setupCommands": [ { "description": "启用整齐打印", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ] }{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/thfs1/software/eigen3/3.4.90-gcc9.3/include/eigen3", "/thfs1/software/mpich/4.0.2-mpi-x-gcc9.3.0/include", "/thfs1/software/mumps/5.5.1-gcc9.3.0-mpi-x/include" ], "defines": [], "cStandard": "c17", "cppStandard": "c++14", "intelliSenseMode": "linux-clang-arm64" } ], "version": 4 }同时加载的模块如下 module list Currently Loaded Modulefiles: 1) mpich/4.0.2-mpi-x-gcc9.3.0 3) openblas/0.3.30-gcc9.3.0 5) metis/5.1.0-gcc9.3.0 7) blas/3.8.0-gcc9.3.0 2) GCC/9.3.0(default) 4) scalapack/2.2.2-gcc9.3.0-mpi-x 6) lapack/3.8.0-gcc9.3.0 test653@ln0:~/shengjh$ which ld /usr/bin/ld解决问题
最新发布
08-16
[ 59%] Linking C executable CTRL_V1 /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld: /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a(libc_a-closer.o): in function `_close_r': closer.c:(.text._close_r+0xc): warning: _close is not implemented and will always fail /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld: /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a(libc_a-closer.o): note: the message above does not take linker garbage collection into account /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld: /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a(libc_a-fstatr.o): in function `_fstat_r': fstatr.c:(.text._fstat_r+0xe): warning: _fstat is not implemented and will always fail /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld: /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a(libc_a-fstatr.o): note: the message above does not take linker garbage collection into account /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld: /home/lz/github/stm32/tools/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc_nano.a(libc_a-signalr.o): in function `_getpid_r':
05-16
arm-seev300-linux-uclibcgnueabihf-g++ -fPIC -Wall -O2 -Drgn_private -g -I./ -I../../include -I../../include/common -I../../inc_drv -I../../inc_lib -fPIC -Wall -O2 -Drgn_private -g -I./ -I../../include -I../../include/common -I../../inc_drv -I../../inc_lib ./common.o ./FilterFunction.o ./HVM_MPI_IMG_Set+GetConnectMode.o ./HVM_MPI_IMG_Set+GetDdrMode.o ./HVM_MPI_VGP_CreatePipeTest.o ./main.o -L../../lib -L../../lib/gtest_lib -lvb -lpthread -lvmm -lbase -lm -losal -lgdma -limg -lvic -lcxm -lbind -lprint -lisp -lvdp -lhvm2a -lpqt -lhvm188 -lhvm187 -lge -lrgn -lvencrgn -lvenc -lvgp -lime -losal -lgtest -o run_img_test -Xlinker "-(" -L../../lib -L../../lib/gtest_lib -lvb -lpthread -lvmm -lbase -lm -losal -lgdma -limg -lvic -lcxm -lbind -lprint -lisp -lvdp -lhvm2a -lpqt -lhvm188 -lhvm187 -lge -lrgn -lvencrgn -lvenc -lvgp -lime -losal -Xlinker "-)" /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libimg.a(hvm_mpi_img.o): in function `_GLOBAL__sub_I_65535_0_hvm_mpi_img.c': /share/users/fanjiahe/svn/mars/btk_img/g2s/branches_v0.5/api/img/lib/mpi/hvm_mpi_img.c:141: undefined reference to `__gcov_init' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libimg.a(hvm_mpi_img.o):(.data.rel+0x10): undefined reference to `__gcov_merge_add' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libimg.a(pil_func_img.o): in function `_GLOBAL__sub_I_65535_0_pil_func_img.c': /share/users/fanjiahe/svn/mars/btk_img/g2s/branches_v0.5/api/img/lib/pil/pil_func_img.c:797: undefined reference to `__gcov_init' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libimg.a(pil_func_img.o):(.data.rel+0x10): undefined reference to `__gcov_merge_add' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libvic.a(hvm_mpi_vic.o): in function `_GLOBAL__sub_I_65535_0_hvm_mpi_vic.c': /share/users/fanjiahe/svn/mars/btk_img/g2s/branches_v0.5/api/vic/lib/mpi/hvm_mpi_vic.c:642: undefined reference to `__gcov_init' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libvic.a(hvm_mpi_vic.o):(.data.rel+0x10): undefined reference to `__gcov_merge_add' /share/eda/toolchains/arm-seev300-linux-uclibcgnueabihf/bin/../lib/gcc/arm-seev300-linux-uclibcgnueabihf/6.5.0/../../../../arm-seev300-linux-uclibcgnueabihf/bin/ld.bfd: ../../lib/libvic.a(pil_vic_sys.o): in function `_GLOBAL__sub_I_65535_0_pil_vic_sys.c': /share/users/fanjiahe/svn/mars/btk_img/g2s/branches_v0.5/api/vic/lib/pil/pil_vic_sys.c:1994: undefined reference to `__gcov_init'
08-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值