如何判断在哪个.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
此文件通常是一个符号链接,因此您必须通过 readlink
或 realpath
将其通过管道传输以获取实际文件。例如:
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
并使用 nm
或 readelf
查看所有导出的函数。
另一个例子,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 上的评论中提取了这最后一步,但并不完全理解它。也许您甚至可以跳过前面的步骤并单独依赖 nm
和 grep
?
我在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
此文件通常是一个符号链接,因此您必须通过 readlink
或 realpath
将其通过管道传输以获取实际文件。例如:
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
并使用 nm
或 readelf
查看所有导出的函数。
另一个例子,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 上的评论中提取了这最后一步,但并不完全理解它。也许您甚至可以跳过前面的步骤并单独依赖 nm
和 grep
?