你的发行版配置的gcc与--enable-default-pie
,所以它在默认情况下做出与位置无关的可执行文件,(允许可执行的ASLR以及图书馆)。 PIC/PIE不允许搬迁。
使用gcc -fno-pie -no-pie
覆盖此回旧的行为。-no-pie
是链接器选项-fno-pie
is the code-gen option。仅使用-fno-pie
时,gcc将使编码类似mov eax, offset .LC0
,但不与仍然启用的-pie
链接。
(铛可以在默认情况下启用了PIE,太:clang -fno-pie -nopie
一个July 2017 patch做出-no-pie
一个别名-nopie
,为COMPAT用gcc,但clang4.0.1没有它。)
由于只有-no-pie
,(但仍然-fpie
)编译器生成的代码会比必要慢,但是仍然会被链接到不从ASLR受益位置相关的可执行文件。惩罚主要是在访问全局变量时(而不是使用静态存储类的static
文件作用域变量)。请注意,对于64位代码,-fPIE
不如-fPIC
差,但对于32位仍然不好。见some examples on the Godbolt compiler explorer,并参见The sorry state of dynamic libraries on Linux。
如果你的GCC是这样配置的,gcc -v |& grep -o -e '[^ ]*pie'
打印--enable-default-pie
。在early 2015的gcc中添加了对此配置选项的支持。 Ubuntu在16.10启用它,并且在gcc 6.2.0-7
的同一时间Debian(导致内核构建错误:https://lkml.org/lkml/2016/10/21/904)。相关:Build compressed x86 kernels as PIE。
请注意,ld
本身并没有改变它的默认值。它仍然正常工作(至少在Arch Linux上使用binutils 2.28)。这种变化是gcc
默认为传递-pie
作为一个连接器选项,除非你明确地使用-static
或-no-pie
。
在NASM源文件中,我使用了a32 mov eax, [abs buf]
来获取绝对地址。 (我测试,如果6个字节的方式来编码小的绝对地址(地址大小+ MOV EAX,总督们:67 a1 40 f1 60 00
)已对英特尔CPU的LCP失速It does。)
nasm -felf64 -Worphan-labels -g -Fdwarf testloop.asm &&
ld -o testloop testloop.o # works
gcc -v -nostdlib testloop.o # doesn't work
...
..../collect2 ... -pie ...
/usr/bin/ld: testloop.o: relocation R_X86_64_32 against `.bss' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
gcc -v -no-pie -nostdlib testloop.o # works
gcc -v -static -nostdlib testloop.o # also works: -static implies -no-pie
相关:building static/dynamic executables with/without libc, defining _start
or main
。
file
和readelf
说馅饼 “共享对象”,而不是可执行文件。
$ gcc -fno-pie -no-pie -O3 hello.c
$ file a.out
a.out: ELF 64-bit LSB executable, ...
$ gcc -O3 hello.c
$ file a.out
a.out: ELF 64-bit LSB shared object, ...
半相关:另一个最近的gcc的特点是gcc -fno-plt
。最后,调用共享库可能只是call [rip + [email protected]]
(AT & T call *[email protected](%rip)
),没有PLT蹦床。
Distros希望尽快启用它,因为它也避免了需要可写+可执行的内存页面。对于进行大量共享库调用的程序来说,这是一个显着的提速。 x86-64 clang -O2 -g
在任何硬件the patch author tested on上编译tramp3d从41.6s变为36.8s。 (铿锵也许是共享库调用的最坏情况)。
它确实需要早期绑定而不是懒惰的动态链接,所以对于立即退出的大型程序来说它会更慢。 (例如clang --version
或编译hello.c
)。显然,这种放缓可能会因为预先链接而减少。
虽然这并不能消除PIC代码中外部变量的GOT开销。 (请参阅上面的godbolt链接)。
对于'-m32'来说这真的很糟糕,因为它浪费了一个宝贵的寄存器来存放PC。我的64位发行版也启用了标志,所以'-m32'也使用它。 –