如何确定在哪个 .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 的评论中删除了这最后一步,但并不完全理解。也许您甚至可以跳过前面的步骤,只依赖nmgrep

【讨论】:

嗯,我用的是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 并使用nmreadelf 查看所有导出的函数。

另一个例子,man XShm 在底部说libXext。以此类推。

更新

如果该函数在手册页的第 (2) 部分中,则它是一个系统调用(请参阅man man)并且由 glibc 提供,即libc-2.??.so

最后(感谢Basile),如果函数没有提到库,也很可能是glibc提供的。

免责声明:同样,这不是 100% 准确的方法 - 但在大多数情况下应该会有所帮助。

【讨论】:

因为shmgetlibc 中并且手册页没有明确提及【参考方案3】:

您可以让gcc 告诉您它将使用哪个文件进行链接,如下所示:

gcc --print-file-name=libX11.so

示例输出:

/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libX11.so

这个文件通常是一个符号链接,所以你必须通过readlinkrealpath 来获取实际文件。例如:

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 函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何识别IDA反汇编中动态链接库中的函数

如何确定某个函数在Linux内核代码中的位置

如何从 lib .so 文件中查找函数?

c ++犰狳库中的sort_index()函数给出错误的结果

如何使用 .so 文件作为 c 中的主要参数?

如何查看DLL中的函数