【问题标题】:How do I list the symbols in a .so file如何列出 .so 文件中的符号
【发布时间】:2010-09-07 06:39:01
【问题描述】:

如何列出从 .so 文件中导出的符号?如果可能的话,我也想知道它们的来源(例如,如果它们是从静态库中提取的)。

我正在使用 gcc 4.0.2,如果这有影响的话。

【问题讨论】:

  • 平台与众不同。 Apple 提供了 GCC 4.0,但其 nm 不响应某些选项,例如 -D-g (IIRC)。
  • 这在 Mac OS 上不打印任何内容。
  • @jww 因为那是 BSD nm,而不是 GNU nm

标签: c++ c gcc symbols name-mangling


【解决方案1】:

列出符号的标准工具是nm,您可以像这样简单地使用它:

nm -gD yourLib.so

如果您想查看 C++ 库的符号,请添加“-C”选项来对符号进行解组(解组后更具可读性)。

nm -gDC yourLib.so

如果您的 .so 文件是 elf 格式,您有两种选择:

objdump-C 也可用于解构 C++):

$ objdump -TC libz.so

libz.so:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000002010 l    d  .init  0000000000000000              .init
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 free
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __errno_location
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable

或者使用readelf:

$ readelf -Ws libz.so
Symbol table '.dynsym' contains 112 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000002010     0 SECTION LOCAL  DEFAULT   10
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.2.5 (14)
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __errno_location@GLIBC_2.2.5 (14)
     4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable

【讨论】:

  • 不过,这并不总是适用于 .so 文件,因此您可能必须使用另一个答案中提到的“readelf”解决方案。
  • 请注意,OS X 版本的 nm 缺少用于消除符号的“-C”选项。可以使用 c++filt 代替。此处的示例脚本:v8.googlecode.com/svn/branches/bleeding_edge/tools/mac-nm nm -g /usr/lib/libstdc++.6.dylib | c++filt -p -i
  • 请注意,readelf -Ws 将向您显示所有 符号,而nm -g 仅显示外部可见的符号。如果您正在检查多个符号文件并开始交换命令,这可能会令人困惑。
  • 我还将objectdump -TC 添加到列表中。与readelf -Ws 不同,它不显示损坏的名称。
  • @BrooksMoses 对于.so 文件,您可能需要将--dynamic 添加到nm 命令行。
【解决方案2】:

如果你只是想知道是否有符号存在你可以使用

objdump -h /path/to/object

或列出调试信息

objdump -g /path/to/object

【讨论】:

    【解决方案3】:

    对于 C++ .so 文件,最终的nm 命令是nm --demangle --dynamic --defined-only --extern-only <my.so>

    # nm --demangle --dynamic --defined-only --extern-only /usr/lib64/libqpid-proton-cpp.so | grep work | grep add
    0000000000049500 T proton::work_queue::add(proton::internal::v03::work)
    0000000000049580 T proton::work_queue::add(proton::void_function0&)
    000000000002e7b0 W proton::work_queue::impl::add_void(proton::internal::v03::work)
    000000000002b1f0 T proton::container::impl::add_work_queue()
    000000000002dc50 T proton::container::impl::container_work_queue::add(proton::internal::v03::work)
    000000000002db60 T proton::container::impl::connection_work_queue::add(proton::internal::v03::work)
    

    来源:https://stackoverflow.com/a/43257338

    【讨论】:

    • 虽然看不到符号版本,不是吗?
    • @Treviño nm 在我的系统上有 --with-symbol-versions。我用glibc.so 尝试过,但无论有没有它,输出都是一样的......需要更多调查。 eidt:我也忘了用--dynamic。有了它,它就可以工作了。我得到例如iswupper 没有,iswupper@@GLIBC_2.2.5 有,在输出中。
    【解决方案4】:

    对于 Android .so 文件,NDK 工具链附带其他答案中提到的所需工具:readelfobjdumpnm

    【讨论】:

      【解决方案5】:

      对于共享库 libNAME.so,需要 -D 开关才能在我的 Linux 中查看符号

      nm -D libNAME.so
      

      对于其他人报告的静态库

      nm -g libNAME.a
      

      【讨论】:

        【解决方案6】:

        nm -g 列出extern 变量,这不是必须的导出符号。 任何非静态文件范围变量(在 C 中)都是外部变量。

        nm -D 会列出动态表中的符号,你可以通过 dlsym 找到它的地址。

        nm --版本

        GNU 纳米 2.17.50.0.6-12.el5 20061020

        【讨论】:

          【解决方案7】:

          我一直想知道为什么 -fvisibility=hidden#pragma GCC visibility 似乎没有任何影响,因为所有符号在 nm 中总是可见的 - 直到我发现这篇文章将我指向 readelfobjdump,这让我意识到实际上似乎有 两个符号表:

          • 你可以用 nm 列出的那个
          • 你可以用 readelfobjdump 列出一个

          我认为前者包含可以用 strip 或 -s 开关去除的调试符号,您可以将其提供给链接器或 install 命令。即使 nm 不再列出任何内容,您导出的符号仍然会被导出,因为它们位于 ELF“动态符号表”中,即后者。

          【讨论】:

          • 谢谢!这就解释了为什么有时“nm”不显示 .so 文件的任何符号。
          • nm -D - 让你列出动态符号表
          【解决方案8】:

          如果您的.so 文件是elf 格式,您可以使用readelf 程序从二进制文件中提取符号信息。此命令将为您提供符号表:

          readelf -Ws /usr/lib/libexample.so
          

          您应该只提取在此.so 文件中定义的那些,而不是在它引用的库中。在这种情况下,第七列应该包含一个数字。您可以使用简单的正则表达式来提取它:

          readelf -Ws /usr/lib/libstdc++.so.6 | grep '^\([[:space:]]\+[^[:space:]]\+\)\{6\}[[:space:]]\+[[:digit:]]\+'
          

          或者,如Caspin所提议的,:

          readelf -Ws /usr/lib/libstdc++.so.6 | awk '{print $8}';
          

          【讨论】:

          • readelf -Ws /usr/lib/libstdc++.so.6 | awk '{打印 $8}';正则表达式很棒,但有时一点 awk 也有很长的路要走。
          【解决方案9】:
          objdump -TC /usr/lib/libexample.so
          

          【讨论】:

            【解决方案10】:

            尝试将 -l 添加到 nm 标志以获取每个符号的来源。如果库是用调试信息(gcc -g)编译的,这应该是源文件和行号。正如 Konrad 所说,此时目标文件/静态库可能是未知的。

            【讨论】:

              【解决方案11】:

              您可以使用 binutils 工具链中的 nm -g 工具。但是,它们的来源并不总是很容易获得。而且我什至不确定是否始终可以检索到这些信息。也许objcopy 会透露更多信息。

              /EDIT: 工具的名字当然是nm。标志-g 用于仅显示导出的符号。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-10-26
                • 2018-11-11
                • 2013-12-27
                • 2014-12-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-07-30
                相关资源
                最近更新 更多