[llvm] f04d92a - [X86] Produce R_X86_64_GOTPCRELX for test/binop instructions (MOV32rm/TEST32rm/...) when -Wa, -mrelax-relocations=yes is enabled
Stephan Bergmann via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 26 15:07:40 PDT 2020
On 25/10/2020 00:14, Fangrui Song via llvm-commits wrote:
>
> Author: Fangrui Song
> Date: 2020-10-24T15:14:17-07:00
> New Revision: f04d92af94a8d763e91ae38fe35319e426dc466c
>
> URL: https://github.com/llvm/llvm-project/commit/f04d92af94a8d763e91ae38fe35319e426dc466c
> DIFF: https://github.com/llvm/llvm-project/commit/f04d92af94a8d763e91ae38fe35319e426dc466c.diff
>
> LOG: [X86] Produce R_X86_64_GOTPCRELX for test/binop instructions (MOV32rm/TEST32rm/...) when -Wa,-mrelax-relocations=yes is enabled
>
> We have been producing R_X86_64_REX_GOTPCRELX (MOV64rm/TEST64rm/...) and
> R_X86_64_GOTPCRELX for CALL64m/JMP64m without the REX prefix since 2016 (to be
> consistent with GNU as), but not for MOV32rm/TEST32rm/...
>
> Added:
> llvm/test/MC/X86/gotpcrelx.s
>
> Modified:
> llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
> llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
> llvm/test/MC/ELF/got.s
>
> Removed:
> llvm/test/MC/ELF/got-relaxed.s
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=/home/sbergman/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.
More information about the llvm-commits
mailing list