Don't create dynamic relocations when its known what the got points to.
llvm-svn: 249485
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 72776e0..45364d6 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -14,6 +14,7 @@
using namespace llvm;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
@@ -29,10 +30,11 @@
}
template <class ELFT>
-GotSection<ELFT>::GotSection()
+GotSection<ELFT>::GotSection(const OutputSection<ELFT> &BssSec)
: OutputSectionBase<ELFT::Is64Bits>(".got", llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC |
- llvm::ELF::SHF_WRITE) {
+ llvm::ELF::SHF_WRITE),
+ BssSec(BssSec) {
this->Header.sh_addralign = this->getAddrSize();
}
@@ -47,6 +49,16 @@
return this->getVA() + B.getGotIndex() * this->getAddrSize();
}
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+ for (const SymbolBody *B : Entries) {
+ if (canBePreempted(B))
+ continue; // The dynamic linker will take care of it.
+ uintX_t VA = getSymVA(*B, BssSec);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, VA);
+ Buf += sizeof(uintX_t);
+ }
+}
+
template <class ELFT>
PltSection<ELFT>::PltSection(const GotSection<ELFT> &GotSec)
: OutputSectionBase<ELFT::Is64Bits>(".plt", llvm::ELF::SHT_PROGBITS,
@@ -399,6 +411,16 @@
return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value;
}
+bool lld::elf2::canBePreempted(const SymbolBody *Body) {
+ if (!Body)
+ return false;
+ if (Body->isShared() || Body->isUndefined())
+ return true;
+ if (!Config->Shared)
+ return false;
+ return true;
+}
+
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
for (InputSection<ELFT> *C : Sections)
C->writeTo(Buf, BssSec, PltSec, GotSec);
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index b0cf435..26a779c 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -40,7 +40,7 @@
typename llvm::object::ELFFile<ELFT>::uintX_t
getLocalSymVA(const typename llvm::object::ELFFile<ELFT>::Elf_Sym *Sym,
const ObjectFile<ELFT> &File);
-
+bool canBePreempted(const SymbolBody *Body);
template <class ELFT> bool includeInSymtab(const SymbolBody &B);
bool includeInDynamicSymtab(const SymbolBody &B);
@@ -103,17 +103,18 @@
typedef typename Base::uintX_t uintX_t;
public:
- GotSection();
+ GotSection(const OutputSection<ELFT> &BssSec);
void finalize() override {
this->Header.sh_size = Entries.size() * this->getAddrSize();
}
- void writeTo(uint8_t *Buf) override {}
+ void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody *Sym);
bool empty() const { return Entries.empty(); }
uintX_t getEntryAddr(const SymbolBody &B) const;
private:
std::vector<const SymbolBody *> Entries;
+ const OutputSection<ELFT> &BssSec;
};
template <class ELFT>
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index e25089d..61683ac 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -85,7 +85,7 @@
Writer(SymbolTable *T)
: SymTabSec(*T, StrTabSec, BssSec), DynSymSec(*T, DynStrSec, BssSec),
RelaDynSec(DynSymSec, GotSec, BssSec, T->shouldUseRela()),
- PltSec(GotSec), HashSec(DynSymSec),
+ GotSec(BssSec), PltSec(GotSec), HashSec(DynSymSec),
DynamicSec(*T, HashSec, RelaDynSec, BssSec),
BssSec(PltSec, GotSec, BssSec, ".bss", SHT_NOBITS,
SHF_ALLOC | SHF_WRITE) {}
@@ -230,18 +230,14 @@
if (Body->isInGot())
continue;
GotSec.addEntry(Body);
- Body->setUsedInDynamicReloc();
- RelaDynSec.addReloc({C, RI});
- continue;
- }
- if (Body->isShared()) {
- Body->setUsedInDynamicReloc();
- RelaDynSec.addReloc({C, RI});
- continue;
}
}
- if (Config->Shared && !Target->isRelRelative(Type))
+ if (canBePreempted(Body)) {
+ Body->setUsedInDynamicReloc();
RelaDynSec.addReloc({C, RI});
+ } else if (Config->Shared && !Target->isRelRelative(Type)) {
+ RelaDynSec.addReloc({C, RI});
+ }
}
}
diff --git a/lld/test/elf2/local-got.s b/lld/test/elf2/local-got.s
new file mode 100644
index 0000000..bc7edae
--- /dev/null
+++ b/lld/test/elf2/local-got.s
@@ -0,0 +1,40 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: lld -flavor gnu2 %t.o -o %t
+// RUN: llvm-readobj -s -r -section-data %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+ .globl _start
+_start:
+ call foo@gotpcrel
+
+ .global foo
+foo:
+ nop
+
+// 0x12000 - 0x11000 - 5 = 4091
+// DISASM: _start:
+// DISASM-NEXT: 11000: {{.*}} callq 4091
+
+// DISASM: foo:
+// DISASM-NEXT: 11005: {{.*}} nop
+
+// CHECK: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// 0x11005 in little endian
+// CHECK-NEXT: 0000: 05100100 00000000 |........|
+// CHECK-NEXT: )
+
+// CHECK: Relocations [
+// CHECK-NEXT: ]