我正在使用SPARC RTEMS C编译器编译C程序。
使用Xlinker -M选项,我可以获得一个包含很多我无法识别的大型内存映射。
我也尝试使用RCC nm实用程序,它返回一个稍微更易读的符号表。我假设此实用程序为printf提供的位置是printf在内存中的位置,并且每个调用printf的程序都将在执行期间到达该位置。这是一个有效的假设吗?
有没有办法获取所有库/系统功能的位置列表?此外,当链接完成时,它是仅链接可执行文件调用的函数,还是库中的所有函数?考虑到我在符号表和内存映射中找到的数量,在我看来是后者。我可以只链接所需的功能吗?
感谢您的帮助。
答案 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;)。