如何确定在哪个.SO库中给定了C函数

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

本文关键字:函数 何确定 SO      更新时间:2023-10-16

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

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

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

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

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

有没有简单的方法可以使用提供的C手册和参考资料来确定图书馆的秘密真实名称?

这是另一种不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虚拟机上),例如,libglfw-dev包含libglfw.so符号链接,而libglfw2则包含实际的libglfw.so.2对象。


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

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

请注意,我从上一个问题的评论中提取了最后一步,但并没有完全理解。也许你甚至可以跳过前面的步骤,只依靠nmgrep

这不是一种可靠的方法,但在许多情况下都会有所帮助。

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

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

另一个例子,man XShm在底部显示libXext。等等。

更新

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

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

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

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

正如我所评论的,您可以使用gcc来链接您的程序,然后它应该能够接受-lX11;通过使用gcc -v而不是gcc,您将了解实际链接的内容以及链接方式。

然而,您有一个比查找lib*.so.*更重要的问题;大多数C或C++API都是在头文件中描述的,这些C或C++头文件还包含符号常量(如用于open(2)…的O_RDONLY)或宏(如POSIX wait…中的WIFEXITED),其值或扩展应该在头文件或文档中手动找到。(通常,这样的常数要么是预处理器#define-d常数,要么是enum值)。此外,一些头文件(尤其是C++中的头文件)包含大量inline-d函数(或宏)!

一种可能的方法是生成一些C文件来查找所有这些常量、枚举、宏、内联函数。。。,和/或定制GCC编译器(例如使用MELT…)以找到它们。

因此,我要传达的信息是,无论好坏,C语言都与Linux&POSIX。

您可能会限制自己只能使用汇编代码中的系统调用(2)。那么就不需要使用libX11,也不需要任何头或常量(除了从<asm/unistd.h>开始用于系统调用的头或常量)。

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

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

另请阅读程序库HowTo&Linux程序集HowTo