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;
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:
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
// 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: }
-# 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
# 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
# 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)
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