【问题标题】:How to get memory locations of library functions?如何获取库函数的内存位置?
【发布时间】:2009-03-31 17:15:59
【问题描述】:

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

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

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

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

感谢您的帮助。

【问题讨论】:

    标签: c memory-management linker sparc rtems


    【解决方案1】:

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

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

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

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

    标题是一个很好的查看位置。

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

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

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

    【讨论】:

    • 如果我为链接器使用 -static 选项使其避免使用共享库,是否会避免与动态库相关的问题?
    • 什么问题?我假设您有重复的符号定义。在那种情况下没有。您必须隐藏/重命名以避免名称冲突。
    • 对不起,我的意思是 nm 会给我确切的答案还是地址仍然可以重新定位?
    • 没有。如果共享库将标准库的副本加载到您的进程空间中,而不是共享已经可用的副本(加载到内存中,因为某些其他程序使用 dll 版本)。
    【解决方案2】:

    使用动态链接, 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 库函数按文件拆分的原因。

    【讨论】:

      【解决方案3】:

      如果您想动态链接,请使用 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 ;)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-04-05
        • 1970-01-01
        • 2018-04-02
        • 2015-04-17
        • 1970-01-01
        • 1970-01-01
        • 2020-11-08
        相关资源
        最近更新 更多