一、nm 查看未定义符号
-
作用: 列出目标文件中的符号即其在内存中的位置(目标文件即编译器编译的文件:动态库、可执行程序、.o文件等)
-
nm输出 的常用符号说明:
b/B: 该符号在bss段,如未初始化的全局变量或0初始化的全局变量;
d/D: 该符号在初始化数据段,如已初始化的全局变量;
t/T: 改符号在代码段,一般是函数定义;
U: 该符号未定义, 一般直接使用nm -u xxx,即可列出未定义符号 -
举例:
int global_var;
int global_var_zero = 0;
int global_var_init = 26;
const int global_var_const = 0;
static int static_var;
static int static_var_init = 25;
extern int extern_var;
extern int extern_function(int);
static int static_function(int x, int y)
{
int local_automatic_var;
local_automatic_var = x + y;
return local_automatic_var;
}
int global_function(int p)
{
static int local_static_var;
static int local_static_var_init=5;
local_static_var = static_function(local_static_var_init, p);
return local_static_var;
}
int main(int argc, char** argv)
{
static_var = 1;
global_var = global_function(2);
extern_var = extern_function(3);
return 0;
}
编译指令:
只编译,不链接
[或者编译成动态库也可以,动态库可以有未定义的符号,在动态库被链接时能找到符号定义即可]
g++ -c test.cpp -o test.o
nm test.o 输出如下:
U extern_var
U _GLOBAL_OFFSET_TABLE_
0000000000000000 B global_var
0000000000000000 D global_var_init
0000000000000004 B global_var_zero
0000000000000045 T main
U _Z15extern_functioni
000000000000001a T _Z15global_functioni
0000000000000008 b _ZL10static_var
0000000000000000 t _ZL15static_functionii
0000000000000004 d _ZL15static_var_init
0000000000000000 r _ZL16global_var_const
000000000000000c b _ZZ15global_functioniE16local_static_var
0000000000000008 d _ZZ15global_functioniE21local_static_var_init
二、ldd 查询可执行程序、动态库 依赖关系
很简单,很常用
三、readelf 分析ELF(Executable and Linking Format)文件必备
参考: 官网说明
不是很常用,目前开发中用到以下几个选项:
- readelf -h testlib -h 显示ELF Header信息,可以看到文件类型,file 命令也可以
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x610
Start of program headers: 64 (bytes into file)
Start of section headers: 6536 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 7
Size of section headers: 64 (bytes)
Number of section headers: 26
Section header string table index: 25
- readelf -p .comment testlib 查看编译器
String dump of section '.comment':
[ 0] GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
四、objdump 查看目标文件信息,反汇编
参考: 官网说明
- 查看文件信息
root@923a3cd440e0:/workspace# objdump -a testlib
testlib: file format elf64-x86-64
- 反汇编
objdump -S testlib
五、gdb 调试,很香
参考: 说明
如果遇到程序莫名其妙的挂了,那就gdb吧,绝对有帮助,
程序crash之后,bt 查看堆栈调用信息,基本就能确定问题的根源了。
六、动态库的搜索顺序
动态库是有搜索顺序的,动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径, 所谓的rpath
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib