【问题标题】:Creating a relocatable shared library with binutils使用 binutils 创建可重定位共享库
【发布时间】:2011-06-15 04:00:21
【问题描述】:

我有一个生成可重定位共享库的自定义工具链。这与一个同样定制的 ELF 加载器一起工作,它将这些加载到内存中,修复它们。我现在正试图说服 gcc 和 binutils 生成与此加载器兼容的 ELF 文件。

不幸的是,binutils 似乎拒绝生成 可重定位 共享对象。它会生成 PIC 共享对象,但我不想这样做,因为 GOT/PLT 的额外开销(此外,自定义 ELF 加载器不支持它)。它会生成可重定位的对象,但它们不是动态对象,因此没有 ELF 加载器希望能够加载它们的适当部分。

我不清楚为什么 GNU ld 拒绝允许我在同一命令行上指定 --relocatable 和 -shared。任何人都可以启发我吗?有没有人知道让 ld 生成我正在寻找的目标文件的咒语?

【问题讨论】:

    标签: shared-libraries elf ld binutils


    【解决方案1】:

    我看到没有人回答这个问题,所以我想我会尝试。

    我将尝试通过一个实际示例来说明这是如何工作的。下面是一些 C 代码,它人为但有目的地混合了外部全局函数和数据——重定位的基础。

    /* hello.c */
    char* hello = "hello";
    
    /* say.c */
    #include "stdio.h"
    extern char* hello;
    void say(void){
        printf(hello);
    }
    
    /* main.c */
    extern void say(void);
    void please_say(void){
        say();
    }
    int main(void){
        please_say();
        return 0;
    }
    

    现在获取共享对象/库的常用方法是使用 -fPIC 编译每个 C 文件,并使用 -shared 链接该批次。在我们这样做之后,我们可以使用 readelf 检查重定位。像这样的:

    gcc -fPIC -c *.c
    gcc -shared -o libtemp.so *.o
    
    readelf -r libtemp.so
    

    搬迁数据如下:

    偏移 0x34c 处的重定位节“.rel.dyn”包含 6 个条目: 偏移信息类型 Sym.Value Sym。姓名 000016dc 00000008 R_386_RELATIVE 000016e0 00000008 R_386_RELATIVE 000016ac 00000106 R_386_GLOB_DAT 00000000 __gmon_start__ 000016b0 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses 000016b4 00000d06 R_386_GLOB_DAT 000016e0 你好 000016b8 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize 偏移 0x37c 处的重定位节“.rel.plt”包含 5 个条目: 偏移信息类型 Sym.Value Sym。姓名 000016c8 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__ 000016cc 00000507 R_386_JUMP_SLOT 000004fc please_say 000016d0 00000807 R_386_JUMP_SLOT 00000540 说 000016d4 00000307 R_386_JUMP_SLOT 00000000 printf 000016d8 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize

    hello 的 R_386_GLOB_DAT 项目是 GOT 条目。同样,say、please_say 和 printf 的 R_386_JUMP_SLOT 项是 PLT 项。它们来自与位置无关的代码的使用,而不是我们制作了共享对象的事实。

    在没有 -fPIC 的情况下执行相同的构建过程后,我们会得到不同的重定位。所以

    gcc -c *.c
    gcc -shared -o libtemp.so *.o
    
    readelf -r libtemp.so
    

    给我们

    偏移 0x34c 处的重定位节“.rel.dyn”包含 9 个条目: 偏移信息类型 Sym.Value Sym。姓名 00001674 00000008 R_386_RELATIVE 00001678 00000008 R_386_RELATIVE 000004d3 00000802 R_386_PC32 000004f0 说 000004e0 00000502 R_386_PC32 000004cc please_say 000004f7 00000d01 R_386_32 00001678 你好 000004ff 00000302 R_386_PC32 00000000 printf 00001654 00000106 R_386_GLOB_DAT 00000000 __gmon_start__ 00001658 00000206 R_386_GLOB_DAT 00000000 _Jv_RegisterClasses 0000165c 00000406 R_386_GLOB_DAT 00000000 __cxa_finalize 偏移量 0x394 处的重定位节“.rel.plt”包含 2 个条目: 偏移信息类型 Sym.Value Sym。姓名 0000166c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__ 00001670 00000407 R_386_JUMP_SLOT 00000000 __cxa_finalize

    现在共享对象对所有定义都有熟悉的重定位。 hello 有绝对重定位,函数有 PC 相对重定位。

    这是什么意思?好吧,GOT 和 PLT 表仍然存在。有两件重要的事情需要注意。首先是编译后的代码没有 GOT 或 PLT 条目。第二个是仍然需要 GOT 和 PLT 表。它们被用于初始化和清理(可能用于标准库)。由于您使用的是自定义 ELF 加载器,因此建议对 GOT 和 PLT 条目实现一些基本支持,即使您的主应用程序执行标准重定位也是如此。

    然后您的应用程序将付出搬迁的代价,而不是位置独立的代价。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多