After just having wasted a day scratching my head why a UBSan build on another machine now started to fail, after I had already forgotten about this issue again, here's a revert now:
This reverts commit f04d92af94a8d763e91ae38fe35319e426dc466c, which causes
miscompilation, as first reported at
<http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20201026/845488.html>
"Re: [llvm] f04d92a - [X86] Produce R_X86_64_GOTPCRELX for test/binop
instructions (MOV32rm/TEST32rm/...) when -Wa, -mrelax-relocations=yes is
enabled":
At least on Linux x86-64 in combination with lld, this causes miscompilation
when an expression like
((long) otherfunction) >> 32
computing the upper 32 bits of a function's address is emitted as
movl otherfunction at GOTPCREL+4(%rip), %eax
which lld then optimizes as
lea otherfunction+4(%rip), %eax
computing the lower 32 bits of the function's address + 4.
The simplest reproducer I came up with is
> $ cat test.c
> void otherfunction(void);
> int __attribute__ ((visibility("default"))) test1(void) { return (long) otherfunction; }
> int __attribute__ ((visibility("default"))) test2(void) { return ((long) otherfunction) >> 32; }
>
> $ cat otherfunction.c
> void otherfunction(void) {}
>
> $ cat main.c
> #include <stdio.h>
> int test1(void);
> int test2(void);
> int main() {
> printf("%08X %08X\n", test1(), test2());
> return 0;
> }
>
> $ llvm/inst/bin/clang -fpic -fvisibility=hidden -O -c test.c
> $ objdump -dr test.o | grep -F -A3 '<test'
> 0000000000000000 <test1>:
> 0: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 6 <test1+0x6>
> 2: R_X86_64_GOTPCRELX otherfunction-0x4
> 6: c3 retq
> 7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
> --
> 0000000000000010 <test2>:
> 10: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 16 <test2+0x6>
> 12: R_X86_64_GOTPCRELX otherfunction
> 16: c3 retq
>
> $ llvm/inst/bin/clang -fpic -fvisibility=hidden -c otherfunction.c
>
> $ llvm/inst/bin/clang -fuse-ld=lld --ld-path=/.../llvm/inst/bin/ld.lld -shared test.o otherfunction.o -o libtest.so
> $ objdump -dR libtest.so | grep -F -A3 '<test'
> 00000000000015d0 <test1>:
> 15d0: 8d 05 1a 00 00 00 lea 0x1a(%rip),%eax # 15f0 <otherfunction>
> 15d6: c3 retq
> 15d7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
> --
> 00000000000015e0 <test2>:
> 15e0: 8d 05 0e 00 00 00 lea 0xe(%rip),%eax # 15f4 <otherfunction+0x4>
> 15e6: c3 retq
> 15e7: cc int3
>
> $ llvm/inst/bin/clang main.c libtest.so
> $ LD_LIBRARY_PATH=. ./a.out
> 602065F0 602065F4
where using R_X86_64_GOTPCRELX instead of R_X86_64_GOTPCREL in test2 causes the
second value printed out to be (first value + 4) instead of some 00007F55 or
similar.