使用binutils创建可重定位的共享库

时间:2011-01-25 12:14:49

标签: shared-libraries elf ld binutils

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

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

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

1 个答案:

答案 0 :(得分:2)

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

我将尝试通过一个实际的例子展示它是如何工作的。这里有一些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

重新安置数据如下:

Relocation section '.rel.dyn' at offset 0x34c contains 6 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
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   hello
000016b8  00000406 R_386_GLOB_DAT    00000000   __cxa_finalize

Relocation section '.rel.plt' at offset 0x37c contains 5 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
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   say
000016d4  00000307 R_386_JUMP_SLOT   00000000   printf
000016d8  00000407 R_386_JUMP_SLOT   00000000   __cxa_finalize

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

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

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

readelf -r libtemp.so

给我们

Relocation section '.rel.dyn' at offset 0x34c contains 9 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00001674  00000008 R_386_RELATIVE
00001678  00000008 R_386_RELATIVE
000004d3  00000802 R_386_PC32        000004f0   say
000004e0  00000502 R_386_PC32        000004cc   please_say
000004f7  00000d01 R_386_32          00001678   hello
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

Relocation section '.rel.plt' at offset 0x394 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
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条目实施一些基本支持,即使您的主应用程序执行标准重定位也是如此。

您的申请将支付搬迁费用,但不支付职位独立性。