ELF 符号表使用

本文探讨了ELF文件中的符号表(.symtab和.dynsym)及其在调试中的作用,详细介绍了-rdynamic和-g编译选项的区别,以及如何使用addr2line、objdump和gdb等工具进行符号解析和源代码定位。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ELF 符号表
2018-01-06 Saturday linux , program
-rdynamic VS. -g
如果通过 readelf -s 查看,可以发现,使用 -rdynamic 选项后,在 .dynsym 段中增加了很多符号,包括本程序内定义的符号。

-g 会添加调试信息(.debug_xxx),通常被 gdb 使用,可以通过 strip 删除。
-rdynamic 是添加动态连接符号信息,用于动态连接功能,比如 dlopen()、backtrace() 系列函数使用,不能被 strip 掉。
在 ELF 文件中包含了 .symtab 和 .dynsym 符号表,前者包含的内容更多,通过 strip 会去掉 .symtab 而不会去掉 .dynsym。

addr2line
addr2line 常见的用处就是根据程序崩溃时候打印的堆栈地址,用来查看出错的源代码的行数。

其原理是,在通过 -g 参数编译生成 ELF 对象时,最终的生成文件包含有几个 .debug 段,例如,.debug_line 包含了每个汇编指令对应的地址和源代码行数源代码名字等信息。

objdump、gdb 都是可以解析这个 .debug_line 段,可以通过如下命令查看。

$ objdump -S -d test
如果通过 strip -d 把对应 ELF 文件的几个 debug 段都删除掉,那么 addr2line、objdump、gdb 都不能显示代码行数和汇编的关系了。

----- 查看ELF文件各个段的名称
$ readelf --sections test
$ objdump -x test

----- 查看调试段的内容
$ readelf -wl test
$ readelf --debug-dump test
其中 .symtab 段只保存函数名和变量名等基本的符号的地址和长度等信息的,所以 backtrace() 可以根据地址得到出错的是哪个函数和在函数中的偏移,但具体到源码的哪一行还是要靠 .debug_line 这里面的信息的。

gdb 里面可以通过 file 或者 add-symbol-file 来加载符号表的,如果需要源码行数信息就需要用 -g 重新编译程序以生成 .debug_line 段才能查看。

dmesg
在系统 dmesg 中可以发现系统日志的错误信息:

[54106.016179] test1[8352] trap divide error ip:400506 sp:7fff2add87e0 error:0 in test1[400000+1000]
这里的 IP 字段后面的数字就是程序出错时所程序执行的位置,可以使用 addr2line 将地址 400506 转换成出错程序的位置:

$ addr2line -e test 400506
/code/test/addr2line/test1.c:5
注意
通常在使用 -O1 或者 -O2 编译时会对代码进行优化,包括了 inline 方式,此时可能会忽略部分的函数。
总结
简单来说,如果需要在 Backtrace 中打印函数,需要添加 -rdynamic 参数,如果要通过 addr2line 显示行数则需要添加 -g 参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值