Author: Fangrui Song Date: 2020-11-30T08:27:31-08:00 New Revision: 25c8fbb3d92fd8321af59bb370e901f0e229b1c9
URL: https://github.com/llvm/llvm-project/commit/25c8fbb3d92fd8321af59bb370e901f0e229b1c9 DIFF: https://github.com/llvm/llvm-project/commit/25c8fbb3d92fd8321af59bb370e901f0e229b1c9.diff LOG: [X86] Don't emit R_X86_64_[REX_]GOTPCRELX for a GOT load with an offset clang may produce `movl x@GOTPCREL+4(%rip), %eax` when loading the high 32 bits of the address of a global variable in -fpic/-fpie mode. If assembled by GNU as, the fixup emits R_X86_64_GOTPCRELX with an addend != -4. The instruction loads from the GOT entry with an offset and thus it is incorrect to relax the instruction. This patch does not emit a relaxable relocation for a GOT load with an offset because R_X86_64_[REX_]GOTPCRELX do not make sense for instructions which cannot be relaxed. The result is good enough for LLD to work. GNU ld relaxes mov+GOTPCREL as well, but it suppresses the relaxation if addend != -4. Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D92114 Added: Modified: llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp llvm/test/MC/ELF/got-relaxed-rex.s llvm/test/MC/X86/gotpcrelx.s Removed: ################################################################################ diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 714f45c6e660..4e5e45f03925 100644 --- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -397,10 +397,14 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op, emitByte(modRMByte(0, RegOpcodeField, 5), OS); unsigned Opcode = MI.getOpcode(); - // movq loads are handled with a special relocation form which allows the - // linker to eliminate some loads for GOT references which end up in the - // same linkage unit. - unsigned FixupKind = [=]() { + unsigned FixupKind = [&]() { + // Enable relaxed relocation only for a MCSymbolRefExpr. We cannot use a + // relaxed relocation if an offset is present (e.g. x@GOTPCREL+4). + if (!(Disp.isExpr() && isa<MCSymbolRefExpr>(Disp.getExpr()))) + return X86::reloc_riprel_4byte; + + // Certain loads for GOT references can be relocated against the symbol + // directly if the symbol ends up in the same linkage unit. switch (Opcode) { default: return X86::reloc_riprel_4byte; @@ -416,6 +420,9 @@ void X86MCCodeEmitter::emitMemModRMByte(const MCInst &MI, unsigned Op, case X86::XOR32rm: return X86::reloc_riprel_4byte_relax; case X86::MOV64rm: + // movq loads is a subset of reloc_riprel_4byte_relax_rex. It is a + // special case because COFF and Mach-O don't support ELF's more + // flexible R_X86_64_REX_GOTPCRELX relaxation. assert(HasREX); return X86::reloc_riprel_4byte_movq_load; case X86::CALL64m: diff --git a/llvm/test/MC/ELF/got-relaxed-rex.s b/llvm/test/MC/ELF/got-relaxed-rex.s index e694d7431ba9..1924bddc473e 100644 --- a/llvm/test/MC/ELF/got-relaxed-rex.s +++ b/llvm/test/MC/ELF/got-relaxed-rex.s @@ -13,6 +13,11 @@ sub sub@GOTPCREL(%rip), %rax xor xor@GOTPCREL(%rip), %rax +.section .norelax,"ax" +## This expression loads the GOT entry with an offset. +## Don't emit R_X86_64_REX_GOTPCRELX. + movq mov@GOTPCREL+1(%rip), %rax + // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.text { // CHECK-NEXT: R_X86_64_REX_GOTPCRELX mov @@ -26,4 +31,6 @@ // CHECK-NEXT: R_X86_64_REX_GOTPCRELX sub // CHECK-NEXT: R_X86_64_REX_GOTPCRELX xor // CHECK-NEXT: } -// CHECK-NEXT: ] +// CHECK-NEXT: Section ({{.*}}) .rela.norelax { +// CHECK-NEXT: R_X86_64_GOTPCREL mov +// CHECK-NEXT: } diff --git a/llvm/test/MC/X86/gotpcrelx.s b/llvm/test/MC/X86/gotpcrelx.s index 4afc76235b0d..3889835a1683 100644 --- a/llvm/test/MC/X86/gotpcrelx.s +++ b/llvm/test/MC/X86/gotpcrelx.s @@ -1,8 +1,10 @@ -# RUN: llvm-mc -filetype=obj -triple=x86_64 %s | llvm-readobj -r - | FileCheck %s -# RUN: llvm-mc -filetype=obj -triple=x86_64 -relax-relocations=false %s | llvm-readobj -r - | FileCheck --check-prefix=NORELAX %s +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefixes=CHECK,COMMON +# RUN: llvm-mc -filetype=obj -triple=x86_64 -relax-relocations=false %s -o %t1.o +# RUN: llvm-readobj -r %t1.o | FileCheck %s --check-prefixes=NORELAX,COMMON -# CHECK: Relocations [ -# CHECK-NEXT: Section ({{.*}}) .rela.text { +# COMMON: Relocations [ +# COMMON-NEXT: Section ({{.*}}) .rela.text { # CHECK-NEXT: R_X86_64_GOTPCRELX mov # CHECK-NEXT: R_X86_64_GOTPCRELX test # CHECK-NEXT: R_X86_64_GOTPCRELX adc @@ -16,10 +18,7 @@ # CHECK-NEXT: R_X86_64_GOTPCRELX call # CHECK-NEXT: R_X86_64_GOTPCRELX jmp # CHECK-NEXT: } -# CHECK-NEXT: ] -# NORELAX: Relocations [ -# NORELAX-NEXT: Section ({{.*}}) .rela.text { # NORELAX-NEXT: R_X86_64_GOTPCREL mov # NORELAX-NEXT: R_X86_64_GOTPCREL test # NORELAX-NEXT: R_X86_64_GOTPCREL adc @@ -33,7 +32,6 @@ # NORELAX-NEXT: R_X86_64_GOTPCREL call # NORELAX-NEXT: R_X86_64_GOTPCREL jmp # NORELAX-NEXT: } -# NORELAX-NEXT: ] movl mov@GOTPCREL(%rip), %eax test %eax, test@GOTPCREL(%rip) @@ -47,3 +45,16 @@ sub sub@GOTPCREL(%rip), %eax xor xor@GOTPCREL(%rip), %eax call *call@GOTPCREL(%rip) jmp *jmp@GOTPCREL(%rip) + +# COMMON-NEXT: Section ({{.*}}) .rela.norelax { +# COMMON-NEXT: R_X86_64_GOTPCREL mov 0x0 +# COMMON-NEXT: R_X86_64_GOTPCREL mov 0xFFFFFFFFFFFFFFFC +# COMMON-NEXT: } +# COMMON-NEXT: ] + +.section .norelax,"ax",@progbits +## Clang may emit this expression to load the high 32-bit of the GOT entry. +## Don't emit R_X86_64_GOTPCRELX. +movl mov@GOTPCREL+4(%rip), %eax +## We could emit R_X86_64_GOTPCRELX, but it is probably unnecessary. +movl mov@GOTPCREL+0(%rip), %eax _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits