summaryrefslogtreecommitdiff
path: root/lld/ELF/Arch/X86_64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Arch/X86_64.cpp')
-rw-r--r--lld/ELF/Arch/X86_64.cpp17
1 files changed, 10 insertions, 7 deletions
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index a85bf3aa0c09..6f38c93d6e67 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -314,8 +314,10 @@ bool X86_64::relaxOnce(int pass) const {
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))
+ // If the max VA is under 2^31, GOTPCRELX relocations cannot overfow. In
+ // -pie/-shared, the condition can be relaxed to test the max VA difference as
+ // there is no R_RELAX_GOT_PC_NOPIC.
+ if (isUInt<31>(maxVA) || (isUInt<31>(maxVA - minVA) && config->isPic))
return false;
SmallVector<InputSection *, 0> storage;
@@ -325,13 +327,14 @@ bool X86_64::relaxOnce(int pass) const {
continue;
for (InputSection *sec : getInputSections(*osec, storage)) {
for (Relocation &rel : sec->relocs()) {
- if (rel.expr != R_RELAX_GOT_PC)
+ if (rel.expr != R_RELAX_GOT_PC && rel.expr != R_RELAX_GOT_PC_NOPIC)
continue;
+ assert(rel.addend == -4);
- uint64_t v = sec->getRelocTargetVA(sec->file, rel.type, rel.addend,
- sec->getOutputSection()->addr +
- sec->outSecOff + rel.offset,
- *rel.sym, rel.expr);
+ uint64_t v = sec->getRelocTargetVA(
+ sec->file, rel.type, rel.expr == R_RELAX_GOT_PC_NOPIC ? 0 : -4,
+ sec->getOutputSection()->addr + sec->outSecOff + rel.offset,
+ *rel.sym, rel.expr);
if (isInt<32>(v))
continue;
if (rel.sym->auxIdx == 0) {