NM 和 addr2line

这是一个有趣的现象,可能是因为 nm 工具默认只会列出共享库中 公开的符号(即对外可见的符号),而 addr2line 是通过地址来定位代码的,它直接从符号地址中获取调试信息。所以,即使 nm 没能列出某个符号,addr2line 仍然能够通过地址找到相关的代码行。

可能的原因如下:

1. 符号表被剥离(Stripped Symbols)
  • 共享库可能在构建时被剥离了符号表,或者符号被隐藏了。通常情况下,使用 -sstrip 工具来去除符号表会减小库文件的大小,但这也意味着你无法使用 nm 等工具查看符号。

  • 如果使用 addr2line 能解出代码行,说明库在编译时带有调试信息(比如使用 -g 选项编译),或者符号没有完全剥离,依然包含了部分调试信息。

    如何确认是否剥离符号:
    你可以使用 file 命令查看共享库的详细信息。例如:

    file libc.so
    

    如果输出中包含类似 stripped 的信息,表示符号已被剥离。举个例子:

    libc.so:  ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), stripped
    

    如果没有被剥离,你应该能够使用 nm 查看到公开的符号。

2. 符号的可见性问题
  • 即使是非 static 的函数,也有可能被 gccclang 编译器处理为 局部符号,这通常是由于编译器优化或者特定的符号可见性设置(如 __attribute__((visibility("hidden"))))导致的。这意味着符号在共享库内是 “局部” 的,不会被 nm 工具列出。

    如何查看符号可见性:
    你可以使用 objdump 来检查符号表和符号的可见性,例如:

    objdump -T libc.so
    

    这将显示共享库中所有符号,并且会标明每个符号的可见性。

3. 函数地址未对齐
  • 如果你的代码中使用了内联函数(inline),编译器可能会将这些函数的实现直接嵌入到调用它们的地方,而不是作为独立的符号存在。这也可能导致 nm 无法列出这些符号。
4. 编译优化
  • 编译器优化(如 -O2, -O3)可能会将某些函数内联化或移除,从而导致 nm 看不到这些函数。即使你写的是一个非 static 函数,如果编译器认为它未被使用,它可能会完全优化掉。

    你可以尝试在编译时禁用优化,例如使用 -O0 来避免优化,并查看是否能看到符号。

为什么 addr2line 可以工作?

addr2line 是基于地址来解析代码的,它并不依赖于符号表。即使函数被编译器优化,或符号被隐藏,addr2line 依然可以通过地址信息查找源代码行,前提是该库还包含了调试信息。调试信息通常包含了从机器码地址到源代码行号的映射,即使符号表已被剥离,addr2line 仍然可以利用这些映射信息。

总结

  1. 如果你不能在 nm 中找到符号,可能是因为:

    • 库的符号被剥离或隐藏。
    • 编译器优化导致符号被内联或移除。
    • 使用了符号可见性属性,导致符号是局部的。
  2. 使用 addr2line 可以通过地址找到源代码行,即使符号不可见,这表明调试信息还存在于库中。

  3. 要确认符号是否被剥离或隐藏,使用 fileobjdump 检查库的符号表和符号可见性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ooo胡大侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值