https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94391
--- Comment #9 from H.J. Lu <hjl.tools at gmail dot com> ---
(In reply to Fangrui Song from comment #5)
> 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.
Your are using the incorrect user code. Please use
---
extern unsigned long _binary_a_c_size;
unsigned long foo() { return _binary_a_c_size; }
---
GCC and ld handle it correctly.