aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Arch/X86_64.cpp43
-rw-r--r--lld/ELF/Relocations.cpp6
-rw-r--r--lld/ELF/Relocations.h1
-rw-r--r--lld/ELF/Writer.cpp1
-rw-r--r--lld/test/ELF/x86-64-gotpc-err.s26
-rw-r--r--lld/test/ELF/x86-64-gotpc-relax-too-far.s55
-rw-r--r--lld/test/ELF/x86-64-gotpc-relax.s50
7 files changed, 129 insertions, 53 deletions
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 9e49f54..2135ac2 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -7,12 +7,14 @@
//===----------------------------------------------------------------------===//
#include "OutputSections.h"
+#include "Relocations.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
using namespace llvm;
using namespace llvm::object;
@@ -47,6 +49,7 @@ public:
uint8_t stOther) const override;
bool deleteFallThruJmpInsn(InputSection &is, InputFile *file,
InputSection *nextIS) const override;
+ bool relaxOnce(int pass) const override;
};
} // namespace
@@ -305,6 +308,43 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
return true;
}
+bool X86_64::relaxOnce(int pass) const {
+ uint64_t minVA = UINT64_MAX, maxVA = 0;
+ for (OutputSection *osec : outputSections) {
+ minVA = std::min(minVA, osec->addr);
+ maxVA = std::max(maxVA, osec->addr + osec->size);
+ }
+ // If the max VA difference is under 2^31, GOT-generating relocations with a 32-bit range cannot overflow.
+ if (isUInt<31>(maxVA - minVA))
+ return false;
+
+ SmallVector<InputSection *, 0> storage;
+ bool changed = false;
+ for (OutputSection *osec : outputSections) {
+ if (!(osec->flags & SHF_EXECINSTR))
+ continue;
+ for (InputSection *sec : getInputSections(*osec, storage)) {
+ for (Relocation &rel : sec->relocs()) {
+ if (rel.expr != R_RELAX_GOT_PC)
+ continue;
+
+ uint64_t v = sec->getRelocTargetVA(
+ sec->file, rel.type, rel.addend,
+ sec->getOutputSection()->addr + rel.offset, *rel.sym, rel.expr);
+ if (isInt<32>(v))
+ continue;
+ if (rel.sym->auxIdx == 0) {
+ rel.sym->allocateAux();
+ addGotEntry(*rel.sym);
+ changed = true;
+ }
+ rel.expr = R_GOT_PC;
+ }
+ }
+ }
+ return changed;
+}
+
RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
@@ -912,7 +952,8 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op,
}
static void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) {
- checkInt(loc, val, 32, rel);
+ assert(isInt<32>(val) &&
+ "GOTPCRELX should not have been relaxed if it overflows");
const uint8_t op = loc[-2];
const uint8_t modRm = loc[-1];
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 9305c95..ee27cc1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -904,7 +904,7 @@ static void addPltEntry(PltSection &plt, GotPltSection &gotPlt,
sym, 0, R_ABS});
}
-static void addGotEntry(Symbol &sym) {
+void elf::addGotEntry(Symbol &sym) {
in.got->addEntry(sym);
uint64_t off = sym.getGotOffset();
@@ -1055,6 +1055,10 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
} else if (!isAbsoluteValue(sym)) {
expr =
target->adjustGotPcExpr(type, addend, sec->content().data() + offset);
+ // If the target adjusted the expression to R_RELAX_GOT_PC, we may end up
+ // needing the GOT if we can't relax everything.
+ if (expr == R_RELAX_GOT_PC)
+ in.got->hasGotOffRel.store(true, std::memory_order_relaxed);
}
}
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 0559245..15a2b5f 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -137,6 +137,7 @@ struct JumpInstrMod {
template <class ELFT> void scanRelocations();
void reportUndefinedSymbols();
void postScanRelocations();
+void addGotEntry(Symbol &sym);
void hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections);
bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index d6adc4f..ce72189 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1672,6 +1672,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
changed |= a32p.createFixes();
}
+ finalizeSynthetic(in.got.get());
if (in.mipsGot)
in.mipsGot->updateAllocSize();
diff --git a/lld/test/ELF/x86-64-gotpc-err.s b/lld/test/ELF/x86-64-gotpc-err.s
deleted file mode 100644
index 6fc7cbe..0000000
--- a/lld/test/ELF/x86-64-gotpc-err.s
+++ /dev/null
@@ -1,26 +0,0 @@
-# REQUIRES: x86
-# RUN: split-file %s %t
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
-# RUN: not ld.lld -T %t/lds %t/a.o -o /dev/null 2>&1 | FileCheck %s
-
-## Test diagnostics for GOTPCRELX overflows. In addition, test that there is no
-## `>>> defined in` for linker synthesized __stop_* symbols (there is no
-## associated file or linker script line number).
-
-# CHECK: error: {{.*}}:(.text+0x2): relocation R_X86_64_GOTPCRELX out of range: 2147483655 is not in [-2147483648, 2147483647]; references '__stop_data'
-# CHECK-NEXT: error: {{.*}}:(.text+0x9): relocation R_X86_64_REX_GOTPCRELX out of range: 2147483648 is not in [-2147483648, 2147483647]; references '__stop_data'
-# CHECK-NOT: error:
-
-#--- a.s
- movl __stop_data@GOTPCREL(%rip), %eax # out of range
- movq __stop_data@GOTPCREL(%rip), %rax # out of range
- movq __stop_data@GOTPCREL(%rip), %rax # in range
-
-.section data,"aw",@progbits
-.space 13
-
-#--- lds
-SECTIONS {
- .text 0x200000 : { *(.text) }
- data 0x80200000 : { *(data) }
-}
diff --git a/lld/test/ELF/x86-64-gotpc-relax-too-far.s b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
new file mode 100644
index 0000000..74aa6d8
--- /dev/null
+++ b/lld/test/ELF/x86-64-gotpc-relax-too-far.s
@@ -0,0 +1,55 @@
+# REQUIRES: x86
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
+# RUN: ld.lld -T %t/lds1 %t/a.o -o %t/bin
+# RUN: llvm-objdump --no-print-imm-hex -d %t/bin | FileCheck --check-prefix=DISASM %s
+# RUN: llvm-readelf -S %t/bin | FileCheck --check-prefixes=GOT %s
+# RUN: ld.lld -T %t/lds2 %t/a.o -o %t/bin2
+# RUN: llvm-readelf -S %t/bin2 | FileCheck --check-prefixes=UNNECESSARY-GOT %s
+
+# DISASM: <_foo>:
+# DISASM-NEXT: movl 2097146(%rip), %eax
+# DISASM: <_start>:
+# DISASM-NEXT: movl 1048578(%rip), %eax
+# DISASM-NEXT: movq 1048571(%rip), %rax
+# DISASM-NEXT: leaq 2147483641(%rip), %rax
+# DISASM-NEXT: leal 2147483635(%rip), %eax
+
+# In our implementation, .got is retained even if all GOT-generating relocations are optimized.
+# Make sure .got still exists with the right size.
+# UNNECESSARY-GOT: .got PROGBITS 0000000000300000 101020 000000 00 WA 0 0 8
+# GOT: .got PROGBITS 0000000000300000 102000 000010 00 WA 0 0 8
+
+#--- a.s
+.section .text.foo,"ax"
+.globl _foo
+.type _foo, @function
+_foo:
+ movl __start_data@GOTPCREL(%rip), %eax # out of range
+
+.section .text,"ax"
+.globl _start
+.type _start, @function
+_start:
+ movl __stop_data@GOTPCREL(%rip), %eax # out of range
+ movq __stop_data@GOTPCREL(%rip), %rax # out of range
+ movq __stop_data@GOTPCREL(%rip), %rax # in range
+ movl __stop_data@GOTPCREL(%rip), %eax # in range
+
+.section data,"aw",@progbits
+.space 13
+
+#--- lds1
+SECTIONS {
+ .text.foo 0x100000 : { *(.text.foo) }
+ .text 0x200000 : { *(.text) }
+ .got 0x300000 : { *(.got) }
+ data 0x80200000 : { *(data) }
+}
+#--- lds2
+SECTIONS {
+ .text.foo 0x100000 : { *(.text.foo) }
+ .text 0x200000 : { *(.text) }
+ .got 0x300000 : { *(.got) }
+ data 0x400000 : { *(data) }
+}
diff --git a/lld/test/ELF/x86-64-gotpc-relax.s b/lld/test/ELF/x86-64-gotpc-relax.s
index 0bcc43c..de858bf 100644
--- a/lld/test/ELF/x86-64-gotpc-relax.s
+++ b/lld/test/ELF/x86-64-gotpc-relax.s
@@ -13,18 +13,18 @@
# RUN: ld.lld --no-relax %t.o -o %t2
# RUN: llvm-objdump --no-print-imm-hex -d %t2 | FileCheck --check-prefix=NORELAX %s
-## .got is removed as all GOT-generating relocations are optimized.
+## In our implementation, .got is retained even if all GOT-generating relocations are optimized.
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
-# CHECK: .iplt PROGBITS 0000000000201210 000210 000010 00 AX 0 0 16
-# CHECK-NEXT: .got.plt PROGBITS 0000000000202220 000220 000008 00 WA 0 0 8
+# CHECK: .iplt PROGBITS 0000000000201280 000280 000010 00 AX 0 0 16
+# CHECK-NEXT: .got PROGBITS 0000000000202290 000290 000000 00 WA 0 0 8
## There is one R_X86_64_IRELATIVE relocations.
# RELOC-LABEL: Relocation section '.rela.dyn' at offset {{.*}} contains 1 entry:
# CHECK: Offset Info Type Symbol's Value Symbol's Name + Addend
-# CHECK: 0000000000202220 0000000000000025 R_X86_64_IRELATIVE 201172
+# CHECK: 0000000000203290 0000000000000025 R_X86_64_IRELATIVE 2011e2
# CHECK-LABEL: Hex dump of section '.got.plt':
-# NOAPPLY-NEXT: 0x00202220 00000000 00000000
-# APPLY-NEXT: 0x00202220 72112000 00000000
+# NOAPPLY-NEXT: 0x00203290 00000000 00000000
+# APPLY-NEXT: 0x00203290 e2112000 00000000
# 0x201173 + 7 - 10 = 0x201170
# 0x20117a + 7 - 17 = 0x201170
@@ -33,40 +33,40 @@
# DISASM: Disassembly of section .text:
# DISASM-EMPTY:
# DISASM-NEXT: <foo>:
-# DISASM-NEXT: 201170: 90 nop
+# DISASM-NEXT: 2011e0: 90 nop
# DISASM: <hid>:
-# DISASM-NEXT: 201171: 90 nop
+# DISASM-NEXT: 2011e1: 90 nop
# DISASM: <ifunc>:
-# DISASM-NEXT: 201172: c3 retq
+# DISASM-NEXT: 2011e2: c3 retq
# DISASM: <_start>:
# DISASM-NEXT: leaq -10(%rip), %rax
# DISASM-NEXT: leaq -17(%rip), %rax
# DISASM-NEXT: leaq -23(%rip), %rax
# DISASM-NEXT: leaq -30(%rip), %rax
-# DISASM-NEXT: movq 4234(%rip), %rax
-# DISASM-NEXT: movq 4227(%rip), %rax
+# DISASM-NEXT: movq 8330(%rip), %rax
+# DISASM-NEXT: movq 8323(%rip), %rax
# DISASM-NEXT: leaq -52(%rip), %rax
# DISASM-NEXT: leaq -59(%rip), %rax
# DISASM-NEXT: leaq -65(%rip), %rax
# DISASM-NEXT: leaq -72(%rip), %rax
-# DISASM-NEXT: movq 4192(%rip), %rax
-# DISASM-NEXT: movq 4185(%rip), %rax
-# DISASM-NEXT: callq 0x201170 <foo>
-# DISASM-NEXT: callq 0x201170 <foo>
-# DISASM-NEXT: callq 0x201171 <hid>
-# DISASM-NEXT: callq 0x201171 <hid>
-# DISASM-NEXT: callq *4155(%rip)
-# DISASM-NEXT: callq *4149(%rip)
-# DISASM-NEXT: jmp 0x201170 <foo>
+# DISASM-NEXT: movq 8288(%rip), %rax
+# DISASM-NEXT: movq 8281(%rip), %rax
+# DISASM-NEXT: callq 0x2011e0 <foo>
+# DISASM-NEXT: callq 0x2011e0 <foo>
+# DISASM-NEXT: callq 0x2011e1 <hid>
+# DISASM-NEXT: callq 0x2011e1 <hid>
+# DISASM-NEXT: callq *8251(%rip)
+# DISASM-NEXT: callq *8245(%rip)
+# DISASM-NEXT: jmp 0x2011e0 <foo>
# DISASM-NEXT: nop
-# DISASM-NEXT: jmp 0x201170 <foo>
+# DISASM-NEXT: jmp 0x2011e0 <foo>
# DISASM-NEXT: nop
-# DISASM-NEXT: jmp 0x201171 <hid>
+# DISASM-NEXT: jmp 0x2011e1 <hid>
# DISASM-NEXT: nop
-# DISASM-NEXT: jmp 0x201171 <hid>
+# DISASM-NEXT: jmp 0x2011e1 <hid>
# DISASM-NEXT: nop
-# DISASM-NEXT: jmpq *4119(%rip)
-# DISASM-NEXT: jmpq *4113(%rip)
+# DISASM-NEXT: jmpq *8215(%rip)
+# DISASM-NEXT: jmpq *8209(%rip)
# NORELAX-LABEL: <_start>:
# NORELAX-COUNT-12: movq