如何获取库函数的内存位置?

时间:2009-03-31 17:16:00

标签: c memory-management linker sparc rtems

我正在使用SPARC RTEMS C编译器编译C程序。

使用Xlinker -M选项,我可以获得一个包含很多我无法识别的大型内存映射。

我也尝试使用RCC nm实用程序,它返回一个稍微更易读的符号表。我假设此实用程序为printf提供的位置是printf在内存中的位置,并且每个调用printf的程序都将在执行期间到达该位置。这是一个有效的假设吗?

有没有办法获取所有库/系统功能的位置列表?此外,当链接完成时,它是仅链接可执行文件调用的函数,还是库中的所有函数?考虑到我在符号表和内存映射中找到的数量,在我看来是后者。我可以只链接所需的功能吗?

感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

大多数情况下,使用动态库时,nm实用程序无法为您提供准确的答案。这些天的二进制文件使用所谓的可重定位地址。这些地址在映射到进程的地址空间时会发生更改。

  

使用Xlinker -M选项,我可以获得一个包含很多我无法识别的大型内存映射。

链接器映射通常包含所有符号 - 您的,标准库,运行时挂钩等。

  

有没有办法获取所有库/系统功能的位置列表?

标题是个好看的地方。

  

此外,当链接完成时,它是仅链接可执行文件调用的函数,还是库中的所有函数?

链接并不一定意味着将解析所有符号(即给定地址)。这取决于您正在创建的二进制类型。

然而,像gcc这样的一些编译器确实允许您创建不可重定位的二进制文件。 (对于gcc,您可以查看exp文件,dlltool等。)请查看相应的文档。

答案 1 :(得分:1)

通过动态链接,    1.您的可执行文件具有所有外部调用(PLT表)的特殊位置。    2.您的可执行文件具有依赖的库列表

这两件事是独立的。不可能说哪个外部函数存在于哪个库中。

当程序执行外部函数调用时,它实际发生了什么,它调用PLT表中的一个条目,该条目跳转到动态加载程序。动态加载器查看调用了哪个函数(通过PLT),查看其名称(通过可执行文件中的符号表),并在映射的所有库中查找该名称(所有给定的可执行文件都依赖于该名称)。找到名称后,相应函数的地址将被写回PLT,因此下次调用将直接绕过动态链接器。

要回答您的问题,您应该执行与动态链接器相同的工作:获取依赖库的列表,并查找其中的所有名称。这可以使用'nm'或'readelf'实用程序来完成。

对于静态链接,我认为libXXX.a中给定目标文件中的所有符号都被链接。例如,静态库libXXX.a由目标文件a.o,b.o和c.o组成。如果您需要一个函数foo(),并且它位于a.o中,那么a.o将链接到您的应用程序 - 与函数foo()以及其中定义的所有其他数据一起。这就是为什么例如每个文件拆分C库函数的原因。

答案 2 :(得分:1)

如果要动态链接,请使用dlopen / dlsym解析UNIX .so共享库入口点。

http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html

假设您知道要调用的函数的名称,以及它们所在的函数。这很简单。

void    *handle;
int     *iptr, (*fptr)(int);

/* open the needed object */
handle = dlopen("/usr/home/me/libfoo.so", RTLD_LOCAL | RTLD_LAZY);

/* find the address of function and data objects */
*(void **)(&fptr) = dlsym(handle, "my_function");
iptr = (int *)dlsym(handle, "my_object");

/* invoke function, passing value of integer as a parameter */
(*fptr)(*iptr);

如果你想获得所有动态符号的列表,objdump -T file.so是你最好的选择。 (objdump -t file.a如果你正在寻找静态绑定函数)。 Objdump是跨平台的,是binutils的一部分,所以在紧要关头,你可以将你的二进制文件复制到另一个系统,并在另一个平台上用objdump将它们隔离开来。

如果您希望动态链接最佳,您应该查看您的ld.so.conf,它指定了ld.so.cache的搜索顺序(so.cache right;)。