如何确定在哪个 .SO 库中给出了 C 函数?
Posted
技术标签:
【中文标题】如何确定在哪个 .SO 库中给出了 C 函数?【英文标题】:How to determine in which .SO library is given C function? 【发布时间】:2015-02-05 13:53:00 【问题描述】:我在 Linux 编程中一直有这个问题。只要 Linux 的所有手册和几乎所有源代码都是以 C 为中心的,所有对某些函数的引用只需要一些 include <something.h>
行,并且可以从 C/C++ 代码访问该函数。
但我是用汇编语言编程的,对 C/C++ 几乎一无所知。
为了能够调用某个函数,我必须从相应的.so库中导入它。
如何确定库的文件名?它通常与库本身的名称不同,并且在手册中未指定。
例如,XLib 的名称实际上是libX11.so.6
。 XShm 扩展库的名字好像是libXext.so.6
。
是否有简单的方法可以使用提供的 C 手册和参考来确定库的秘密真实名称?
【问题讨论】:
@BasileStarynkevitch 我不喜欢 C/C++ 语言的语法。组装对我来说更容易和可读。 :) 但不是在 Linux 中。 :( 为什么有这么多反对大会的人?...尊重你@johnfound @sashoalm - 不幸的是,这个问题中的所有答案都是无用的/不起作用。 :( 您可能需要注意 C/C++ 编码人员也需要链接到相应的库。这与包含它们各自的标题不同... @sashoalm:链接的问题是相关的,但不提供了有效的答案... 【参考方案1】:这是另一种并非 100% 准确的方法,它可能会给您一些关于如何缩小范围的想法。它不完全适合这个问题,因为它使用常见的 linux 实用程序而不是 man 文件,但它可能仍然有用。
使用您的发行版的包管理软件。
例如,在 Arch Linux 上,如果您对 GLFW/glfw3.h
中的函数感兴趣,您可以找出谁拥有该文件:
$ pacman -Qo /usr/include/GLFW/glfw3.h
/usr/include/GLFW/glfw3.h is owned by glfw 3.1-1
找出该包中有哪些.so
文件:
$ pacman -Ql glfw | grep 'so$'
glfw /usr/lib/libglfw.so
如果需要,找到链接指向的实际文件:
$ readlink -f /usr/lib/libglfw.so
/usr/lib/libglfw.so.3.1
这取决于您的发行版。我相信在 Ubuntu/Debian 上你会使用 dpkg-query
。
编辑: DevSolar 在评论中指出,您可以使用apt-file search <header>
和apt-file list <package>
代替dpkg-query -S <header>
和dpkg-query -L <package>
。 apt-file
似乎对未安装的软件包也有效(尽管它看起来更慢?)。
我还注意到(至少在我的 Ubuntu VM 上),例如,libglfw-dev 包含 libglfw.so
符号链接,而 libglfw2 包含实际的 @987654334 @对象。
一旦你有了一组.so
文件,你就可以检查它们是否有你感兴趣的任何功能:
$ nm -D /usr/lib/libglfw.so | grep "glfwCreateWindow"
0000000000007cd0 T glfwCreateWindow
请注意,我从previous question 的评论中删除了这最后一步,但并不完全理解。也许您甚至可以跳过前面的步骤,只依赖nm
和grep
?
【讨论】:
嗯,我用的是objdump而不是nm,但是思路是一样的。它确实有效,但是搜索所有 .so 文件非常慢。 是的,可能会将所有内容转储到单个文本文件中,例如nm -D /usr/lib/*.so > $HOME/sodb.txt
(或任何理智的东西)然后搜索?
对于 Debian / Ubuntu / Mint 你可以使用apt-file
工具。 apt-file search <header>
查找拥有该文件的包,apt-file list <package> | grep 'so$'
列出包中的所有 .so 文件。【参考方案2】:
这不是一个万无一失的方法,但在许多情况下它会有所帮助。
基本上,您通常可以在man
页面底部找到库名称。
例如,man XCreateWindow
在最后一行显示libX11
。然后查找libX11.so
并使用nm
或readelf
查看所有导出的函数。
另一个例子,man XShm
在底部说libXext
。以此类推。
更新
如果该函数在手册页的第 (2) 部分中,则它是一个系统调用(请参阅man man
)并且由 glibc 提供,即libc-2.??.so
。
最后(感谢Basile),如果函数没有提到库,也很可能是glibc提供的。
免责声明:同样,这不是 100% 准确的方法 - 但在大多数情况下应该会有所帮助。
【讨论】:
因为shmget
在libc
中并且手册页没有明确提及【参考方案3】:
您可以让gcc
告诉您它将使用哪个文件进行链接,如下所示:
gcc --print-file-name=libX11.so
示例输出:
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libX11.so
这个文件通常是一个符号链接,所以你必须通过readlink
或realpath
来获取实际文件。例如:
readlink -f $(gcc --print-file-name=libXext.so)
示例输出:
/usr/lib/x86_64-linux-gnu/libXext.so.6.4.0
【讨论】:
错了,--print-file-name
用于 GCC 内部文件,而不用于外部库!
@BasileStarynkevitch gcc
的手册页没有提到任何此类限制,这似乎适用于所有库。
@Wintermute 好吧,但是如果我只有函数名,例如XCreateWindow
,如何知道这个“libX11.so”?
啊。嗯...老实说,我会查看XCreateWindow
的文档。不过,我想您可以编写一个搜索脚本。按照find /usr/lib -name \*.so -exec nm -oD '' \; | grep ' T XCreateWindow'
的思路——尽管这个特殊的部分可能需要一些耐心。【参考方案4】:
正如我评论的那样,您可以使用 gcc
链接您的程序,然后它应该能够接受 -lX11
;通过使用gcc -v
而不是gcc
,您将了解实际链接的内容以及链接方式。
但是,您有一个比找到lib*.so.*
更重要的问题;大多数 C 或 C++ API 都在头文件中描述,并且这些 C 或 C++ 头文件还包含 symbolic 常量(如 open(2)... 的 O_RDONLY
)或宏(如 WIFEXITED
in POSIX wait ...) 您应该在头文件或文档中手动查找其值或扩展。 (很多时候,这样的常量要么是预处理器#define
-d 常量,要么是enum
值)。此外,一些头文件——特别是在 C++ 中——包含很多 inline
-d 函数(或宏)!
一种可能的方法是生成一些 C 文件来查找所有这些常量、枚举、宏、内联函数...,和/或自定义 GCC 编译器(例如,使用 MELT ...)以找到他们。
所以我的信息是,无论好坏,C 语言都深度与 Linux 和 POSIX 绑定。
您可能会限制自己仅使用汇编代码中的syscalls(2)。那么你就不会使用libX11
,也不需要任何头文件或常量(除了系统调用的那些,从<asm/unistd.h>
开始)。
顺便说一句,在 2015 年,出于性能原因,完全在汇编程序中编码是一个错误。编译器生成的代码比你合理的要好(只要你有超过几百条机器指令)。在实践中,您可以通过在 C 函数中使用扩展的 asm
指令来使用 GCC 编写汇编程序。
或者您正在构建自己的编译器?那么你应该在你的问题中这么说!
另请阅读Program Library HowTo 和Linux Assembly HowTo
【讨论】:
看,我根本不使用链接器。 FASM 不需要它并直接生成可执行文件。如果我想使用 C/C++,我根本不会问这个问题。 你无法避免链接器使用共享库。至少,您需要编写自己的动态链接器(替换ld.so
)
我说的是静态链接。动态链接是操作系统启动机制的一部分,而不是您的程序构建过程。
你的问题提到了libX11.so.6
而不是libX11.a
所以你想要动态链接
好吧,解释一下你是如何找到O_RDONLY
的数值或WIFEXITED
的扩展...换句话说,你如何在你的汇编代码!以上是关于如何确定在哪个 .SO 库中给出了 C 函数?的主要内容,如果未能解决你的问题,请参考以下文章