2

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

使用 Xlinker -M 选项,我可以获得一个包含很多我不认识的东西的大内存映射。

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

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

谢谢你的帮助。

4

3 回答 3

5

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

使用 Xlinker -M 选项,我可以获得一个包含很多我不认识的东西的大内存映射。

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

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

标题是查看的好地方。

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

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

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

于 2009-03-31T17:24:01.047 回答
1

使用动态链接, 1. 您的可执行文件对所有外部调用(PLT 表)有一个特殊的位置。2. 你的可执行文件有一个它依赖的库列表

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

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

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

至于静态链接,我认为 libXXX.a 中给定目标文件中的所有符号都会被链接。例如,静态库 libXXX.a 由目标文件 ao、bo 和 co 组成,如果你需要一个函数 foo(),它驻留在在 ao 中,然后 ao 将链接到您的应用程序 - 连同函数 foo() 和其中定义的所有其他数据。这就是例如 C 库函数按文件拆分的原因。

于 2009-03-31T20:26:04.480 回答
1

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

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

假设您知道要调用的函数的名称,以及它们在哪个 .so 中。这相当简单。

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 ;)。

于 2009-05-16T20:12:52.900 回答