我有一个自定义工具链,可生成可重定位的共享库。这适用于同样定制的ELF加载程序,它将这些加载到内存中,修复它们。我现在正试图说服gcc和binutils生成与这个加载器兼容的ELF文件。
不幸的是,似乎binutils拒绝生成可重定位的共享对象。它会生成PIC共享对象,但由于GOT / PLT的额外开销(此外,自定义ELF加载程序不支持它),我不想这样做。并且它将生成可重定位的对象,但是它们不是动态对象,因此没有ELF加载器希望能够加载它们的适当部分。
我不清楚为什么GNU ld拒绝允许我在同一命令行上指定--relocatable和-shared。任何人都可以开导我吗?有没有人知道让ld生成我正在寻找的目标文件的咒语?
答案 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条目实施一些基本支持,即使您的主应用程序执行标准重定位也是如此。
您的申请将支付搬迁费用,但不支付职位独立性。