Man*_*har 30 c linux linker gcc shared-libraries
glibc提供backtrace()并backtrace_symbols()获取正在运行的程序的堆栈跟踪.但为了实现这一点,程序必须使用链接器的-rdynamic标志构建.
-g传递给gcc和链接器-rdynamic标志的标志有什么区别?对于示例代码,我做了readelf来比较输出.-rdynamic似乎产生了更多的信息Symbol table '.dynsym'但我不太清楚附加信息是什么.
即使我strip使用的二进制程序-rdynamic,backtrace_symbols()继续工作.
当strip去除它为什么留下任何被加入该二进制所有符号-rdynamic标志?
编辑:基于Mat的回复的后续问题如下..
对于相同的示例代码,您使用的是我看到的差异-g&-rdynamic
没有任何选择..
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 70 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
2: 000000000040021c 0 SECTION LOCAL DEFAULT 2
Run Code Online (Sandbox Code Playgroud)
与-g有多个部分,在多个条目.symtab表,但.dynsym保持不变..
[26] .debug_aranges PROGBITS 0000000000000000 0000095c
0000000000000030 0000000000000000 0 0 1
[27] .debug_pubnames PROGBITS 0000000000000000 0000098c
0000000000000023 0000000000000000 0 0 1
[28] .debug_info PROGBITS 0000000000000000 000009af
00000000000000a9 0000000000000000 0 0 1
[29] .debug_abbrev PROGBITS 0000000000000000 00000a58
0000000000000047 0000000000000000 0 0 1
[30] .debug_line PROGBITS 0000000000000000 00000a9f
0000000000000038 0000000000000000 0 0 1
[31] .debug_frame PROGBITS 0000000000000000 00000ad8
0000000000000058 0000000000000000 0 0 8
[32] .debug_loc PROGBITS 0000000000000000 00000b30
0000000000000098 0000000000000000 0 0 1
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 77 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
Run Code Online (Sandbox Code Playgroud)
与-rdynamic没有附加的调试节,的.symtab条目是70(同香草GCC调用),但更多的.dynsym条目..
Symbol table '.dynsym' contains 19 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 00000000005008e8 0 OBJECT GLOBAL DEFAULT ABS _DYNAMIC
3: 0000000000400750 57 FUNC GLOBAL DEFAULT 12 __libc_csu_fini
4: 00000000004005e0 0 FUNC GLOBAL DEFAULT 10 _init
5: 0000000000400620 0 FUNC GLOBAL DEFAULT 12 _start
6: 00000000004006f0 86 FUNC GLOBAL DEFAULT 12 __libc_csu_init
7: 0000000000500ab8 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
8: 00000000004006de 16 FUNC GLOBAL DEFAULT 12 main
9: 0000000000500aa0 0 NOTYPE WEAK DEFAULT 23 data_start
10: 00000000004007c8 0 FUNC GLOBAL DEFAULT 13 _fini
11: 00000000004006d8 6 FUNC GLOBAL DEFAULT 12 foo
12: 0000000000500ab8 0 NOTYPE GLOBAL DEFAULT ABS _edata
13: 0000000000500a80 0 OBJECT GLOBAL DEFAULT ABS _GLOBAL_OFFSET_TABLE_
14: 0000000000500ac0 0 NOTYPE GLOBAL DEFAULT ABS _end
15: 00000000004007d8 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
16: 0000000000500aa0 0 NOTYPE GLOBAL DEFAULT 23 __data_start
17: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
18: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 70 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
2: 000000000040021c 0 SECTION LOCAL DEFAULT 2
Run Code Online (Sandbox Code Playgroud)
现在这些是我的问题..
在gdb中你可以做bt来获得bactrace.如果这只是-g为什么我们需要-rdynamicbacktrace_symbols才能工作?
在增加的比较.symtab与-g和补充,.dynsym与-rdynamic他们是不完全一样的..没有比其他任何一个提供更好的调试信息?FWIW,产生的输出大小如下:使用-g> with -rdynamic>且没有选项
.dynsym的用途究竟是什么?是这个二进制文件导出的所有符号吗?在那种情况下,为什么foo会进入.dynsym,因为我们没有将代码编译为库.
如果我使用所有静态库链接我的代码,那么backtrace_symbols不需要-rdynamic吗?
Mat*_*Mat 40
根据文件:
这指示链接器将所有符号(不仅是已使用的符号)添加到动态符号表中.
那些不是调试符号,它们是动态链接器符号.这些不会被删除,strip因为它(在大多数情况下)会破坏可执行文件 - 运行时链接程序使用它们来执行可执行文件的最后链接阶段.
例:
$ cat t.c
void foo() {}
int main() { foo(); return 0; }
Run Code Online (Sandbox Code Playgroud)
没有编译和链接-rdynamic(显然没有优化)
$ gcc -O0 -o t t.c
$ readelf -s t
Symbol table '.dynsym' contains 3 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
Symbol table '.symtab' contains 50 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400270 0 SECTION LOCAL DEFAULT 1
....
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c
28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
Run Code Online (Sandbox Code Playgroud)
所以可执行文件.symtab包含所有内容.但是请注意,.dynsym根本没有提及foo- 它有完整的基本要素.这不足以backtrace_symbols使用.它依赖于该部分中的信息来匹配代码地址和函数名称.
现在编译-rdynamic:
$ gcc -O0 -o t t.c -rdynamic
$ readelf -s t
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata
5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start
6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo
7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end
8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start
9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init
11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start
12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main
14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init
15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini
Symbol table '.symtab' contains 50 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400270 0 SECTION LOCAL DEFAULT 1
....
27: 0000000000000000 0 FILE LOCAL DEFAULT ABS t.c
28: 0000000000600e14 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
29: 0000000000600e40 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
Run Code Online (Sandbox Code Playgroud)
符号中的符号相同.symtab,但现在foo在动态符号部分中有一个符号(现在也出现了一堆其他符号).这使得backtrace_symbols工作 - 它现在有足够的信息(在大多数情况下)用函数名映射代码地址.
除去:
$ strip --strip-all t
$ readelf -s t
Symbol table '.dynsym' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata
5: 0000000000601008 0 NOTYPE GLOBAL DEFAULT 24 __data_start
6: 0000000000400734 6 FUNC GLOBAL DEFAULT 13 foo
7: 0000000000601028 0 NOTYPE GLOBAL DEFAULT ABS _end
8: 0000000000601008 0 NOTYPE WEAK DEFAULT 24 data_start
9: 0000000000400838 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init
11: 0000000000400650 0 FUNC GLOBAL DEFAULT 13 _start
12: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main
14: 0000000000400618 0 FUNC GLOBAL DEFAULT 11 _init
15: 00000000004007e0 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
16: 0000000000400828 0 FUNC GLOBAL DEFAULT 14 _fini
$ ./t
$
Run Code Online (Sandbox Code Playgroud)
没有.symtab消失,但动态符号表仍然存在,可执行文件运行.所以backtrace_symbols仍然有效.
剥离动态符号表:
$ strip -R .dynsym t
$ ./t
./t: relocation error: ./t: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference
Run Code Online (Sandbox Code Playgroud)
......你得到一个破碎的可执行文件.
有关什么.symtab和.dynsym用于的有趣读物在这里:内部ELF符号表.需要注意的一点.symtab是在运行时不需要,因此加载器会将其丢弃.该部分不会留在进程的内存中..dynsym,在otherhand,是需要在运行时,因此它保持在处理图像英寸 因此,它可用于backtrace_symbols从内部收集有关当前进程的信息.
简而言之:
strip因为这会使可执行文件不可加载backtrace_symbols 需要动态符号来确定哪些代码属于哪个函数backtrace_symbols 不使用调试符号因此你注意到的行为.
针对您的具体问题:
gdb是一个调试器.它使用可执行文件和库中的调试信息来显示相关信息.除了实时进程之外,它比驱动器上的实际文件要复杂得多backtrace_symbols,并检查它们.backtrace_symbols不,它完全在进程中 - 因此它无法访问未加载到可执行映像中的部分.调试部分未加载到运行时映像中,因此无法使用它们..dynsym不是调试部分.它是动态链接器使用的部分..symbtab也不是调试部分,但可以由可以访问可执行(和库)文件的调试器使用它.-rdynamic 不会生成调试部分,只会生成扩展的动态符号表.可执行文件的增长-rdynamic完全取决于该可执行文件中的符号数(以及对齐/填充注意事项).它应该远远小于-g.printf和C库中的一些应用程序启动过程.必须在可执行文件的某处指示这些外部符号:这是.dynsym用于的内容,这就是为什么.dynsym即使你没有指定,exe也有-rdynamic.当您指定它时,链接器会添加其他符号,这些符号对于该过程不起作用是必需的,但可以被类似的东西使用backtrace_symbols.backtrace_symbols如果您静态链接,将不会解析任何函数名称.即使您指定-rdynamic,该.dynsym部分也不会发送到可执行文件.没有符号表被加载到可执行映像中,因此backtrace_symbols无法将代码映射映射到符号.