如何判断在哪个.SO库中赋予了C函数?

How to determine in which .SO library is given C function?

我在Linux编程中一直遇到这个问题。只要 Linux 的所有手册和几乎所有源代码都是以 C 为中心的,对某些函数的所有引用只需要一些 include <something.h> 行,并且可以从 C/C+ 访问该函数+代码。

但我是用汇编语言编程的,对C/C++几乎一无所知。

为了能够调用某些函数,我必须从相应的.so库中导入它。

如何确定库的文件名?它通常与库本身的名称不同,并且在手册中没有指定。

例如,XLib 的名称实际上是libX11.so.6。 XShm 扩展库的名字好像是libXext.so.6.

使用提供的 C 手册和参考资料,是否有简单的方法来确定库的秘密真实名称?

正如我评论的那样,您可以使用 gcc 来 link 您的程序,然后它应该能够接受 -lX11 ;通过使用 gcc -v 而不是 gcc 你会发现实际上是什么 linked 以及如何。

但是,您遇到的问题比找到 lib*.so.* 更重要;大多数 C 或 C++ API 在 header 文件中进行了描述,这些 C 或 C++ header 文件还包含 符号 常量(如 O_RDONLY for open(2)...) or macros (like WIFEXITED in POSIX wait ...) 您应该在 header 文件或文档中手动查找其值或扩展。 (通常,此类常量是预处理器 #define-d 常量或 enum 值)。此外,一些 headers - 特别是在 C++ 中 - 包含很多 inline-d 函数(或宏)!

一种可能的方法是生成一些 C 文件来查找所有这些常量、枚举、宏、内联函数...,and/or 自定义 GCC compiler (e.g. with MELT...) 来查找他们。

所以我想说的是,无论好坏,C 语言 深深地 与 Linux & POSIX.

联系在一起

您可以限制自己仅使用汇编代码中的 syscalls(2)。那么你就不会使用 libX11 并且你不需要任何 header 或常量(系统调用除外,从 <asm/unistd.h> 开始)。

顺便说一句,在 2015 年,出于性能原因 完全 在汇编程序中编码是一个错误。编译器生成的代码比你想象的要好(只要你有超过几百条机器指令)。实际上,您可以通过在 C 函数中使用扩展 asm 指令,使用 GCC 在汇编程序中进行编码。

或者您正在构建自己的编译器?那你应该在你的问题中这样说!

另请阅读Program Library HowTo & the Linux Assembly HowTo

您可以要求 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

这不是万无一失的方法,但在许多情况下它可以提供帮助。

基本上,您通常可以在man页面底部找到库名称。

例如,man XCreateWindow 在最后一行表示 libX11。然后查找 libX11.so 并使用 nmreadelf 查看所有导出的函数。

另一个例子,man XShm在底部写着libXext。等等。

更新

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

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

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

这是另一种并非 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

并且,如果需要,找到 link 指向的实际文件:

$ 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 symlink,而 libglfw2 包含实际的 libglfw.so.2 对象。


一旦你有了一组 .so 个文件,你可以检查它们是否有你感兴趣的功能:

$ nm -D /usr/lib/libglfw.so | grep "glfwCreateWindow"
0000000000007cd0 T glfwCreateWindow

请注意,我从 previous question 上的评论中提取了这最后一步,但并不完全理解它。也许您甚至可以跳过前面的步骤并单独依赖 nmgrep