https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94391
Fangrui Song <i at maskray dot me> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |i at maskray dot me
--- Comment #5 from Fangrui Song <i at maskray dot me> ---
This bug exposes several problems:
* GNU ld does not reject a PC-relative relocation referencing a SHN_ABS symbol
* GCC should not produce R_X86_64_PC32 referencing an external symbol in -fpie
mode.
% gcc -fuse-ld=lld -nostdlib -fpie -pie a.c
% objdump -dr a.o
...
0000000000000000 <foo>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # b <foo+0xb>
7: R_X86_64_PC32 _binary_a_c_size-0x4
b: 5d pop %rbp
c: c3 retq
% gcc -fuse-ld=bfd -nostdlib -fpie -pie a.c b.o -o a
/usr/bin/ld.bfd: warning: cannot find entry symbol _start; defaulting to
0000000000001000
% objdump -dr a
...
0000000000001000 <foo>:
1000: 55 push %rbp
1001: 48 89 e5 mov %rsp,%rbp
1004: 48 8d 05 39 f0 ff ff lea -0xfc7(%rip),%rax # 44
<_binary_a_c_size>
100b: 5d pop %rbp
100c: c3 retq
It is incorrect to reference a non-preemptible symbol with a PC relative
relocation in a -pie link. GNU ld allows it but the code can be incorrect at
runtime.
lea -0xfc7(%rip),%rax # loads 44 to %rax only if the load base is 0. Due to
ASLR (-pie), this is simply not true.
lld correctly rejects the relocation.
To fix this, I had a write-up last year:
https://gcc.gnu.org/legacy-ml/gcc/2019-05/msg00215.html
We should change the configure-time HAVE_LD_PIE_COPYRELOC to an option,
probably -f(no-)direct-access-extern
In clang, HAVE_LD_PIE_COPYRELOC is a compile-time option:
-mpie-copy-relocations. But I think we should improve the option name. At the
very least, we can also let -fno-pic code reference an external symbol with GOT
to avoid copy relocations. -f(no-)direct-access-extern may be a candidate.