Eli*_*sky 10 linux x86 assembly x86-64 shared-libraries
尝试将非PIC代码编译到x64上的共享库中,gcc导致错误,例如:
/usr/bin/ld: /tmp/ccQ2ttcT.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
Run Code Online (Sandbox Code Playgroud)
这个问题是为什么会这样.我知道x64具有RIP相对寻址,旨在提高PIC代码的效率.但是,这并不意味着加载时重定位不能(理论上)应用于此类代码.
一些在线资源,包括这个(在这个问题上被广泛引用)声称,由于 RIP相对寻址,在共享库中禁止非PIC代码存在一些固有的限制.我不明白为什么这是真的.
考虑"旧x86" - call指令也有一个IP相关操作数.然而,其中的x86代码可以call很好地编译成没有PIC的共享库,但使用加载时重定位 R_386_PC32.对于x64中的数据RIP相对寻址,不能做同样的事情吗?
请注意,我完全理解PIC代码的好处,并且性能损失RIP相对寻址有助于缓解.不过,我很好奇不允许使用非PIC代码的原因.它背后是否有真正的技术推理,还是鼓励编写PIC代码?
Mat*_*Mat 16
这是我从comp.unix.programmer上的帖子中读到的最好的解释:
共享库需要x86-64上的PIC,或者更准确地说,可重定位代码必须是PIC.这是因为在重定位后,代码中使用的32位立即数地址操作数可能需要超过32位.如果发生这种情况,则无处可写新值.
再说一些额外的话.
在问题中提供的url中,它提到您可以传递-mcmodel=large给gcc告诉编译器为您的代码生成64位立即数地址操作数.
因此,gcc -mcmodel=large -shared a.c将生成非PIC共享对象.
-
演示:
AC:
#include <stdio.h>
void foo(void)
{
printf("%p\n", main);
}
Run Code Online (Sandbox Code Playgroud)
32位立即数地址操作数阻止您生成非PIC对象.
xiami@gentoo ~ $ cc -shared -o a.so a.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/cck3FWeL.o: relocation R_X86_64_32 against `main' can not be used when making a shared object; recompile with -fPIC
/tmp/cck3FWeL.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
使用-mcmodel=large来解决这个问题.(警告仅出现在我的系统上,因为我的PaX内核禁止对.text进行修改.)
xiami@gentoo ~ $ cc -mcmodel=large -shared -o a.so a.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/../../../../x86_64-pc-linux-gnu/bin/ld: /tmp/ccZ3b9Xk.o: warning: relocation in readonly section `.text'.
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/../../../../x86_64-pc-linux-gnu/bin/ld: warning: creating a DT_TEXTREL in object.
Run Code Online (Sandbox Code Playgroud)
现在您可以看到重定位条目的类型是R_X86_64_64,而不是R_X86_64_32,R_X86_64_PLT32,R_X86_64_PLTOFF64.
xiami@gentoo ~ $ objdump -R a.so
a.so: file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
...
0000000000000758 R_X86_64_64 printf
...
Run Code Online (Sandbox Code Playgroud)
在我的系统上,将此共享对象链接到正常代码并运行该程序将发出如下错误:
./a.out: error while loading shared libraries: ./a.so: cannot make segment writable for relocation: Permission denied
这证明动态加载器特林做搬迁的.text其PIC库不会.