summaryrefslogtreecommitdiffstats
path: root/lld/ELF/OutputSections.cpp
diff options
context:
space:
mode:
authorEugene Leviant <eleviant@accesssoftek.com>2016-11-11 11:33:32 +0000
committerEugene Leviant <eleviant@accesssoftek.com>2016-11-11 11:33:32 +0000
commitad4439e8026ffd4552f2087ab9802b8098710c0d (patch)
treea8d6aabe5c4105cf41121052f84712a72aa83212 /lld/ELF/OutputSections.cpp
parent08dedfc5892ffba346a7843db0316275dbac80e1 (diff)
downloadbcm5719-llvm-ad4439e8026ffd4552f2087ab9802b8098710c0d.tar.gz
bcm5719-llvm-ad4439e8026ffd4552f2087ab9802b8098710c0d.zip
[ELF] Convert .got section to input section
Differential revision: https://reviews.llvm.org/D26498 llvm-svn: 286580
Diffstat (limited to 'lld/ELF/OutputSections.cpp')
-rw-r--r--lld/ELF/OutputSections.cpp284
1 files changed, 5 insertions, 279 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index c2c37f20f75..b1b71fef08d 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -109,275 +109,6 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT>
-GotSection<ELFT>::GotSection()
- : OutputSectionBase(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) {
- if (Config->EMachine == EM_MIPS)
- this->Flags |= SHF_MIPS_GPREL;
- this->Addralign = Target->GotEntrySize;
-}
-
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
- Sym.GotIndex = Entries.size();
- Entries.push_back(&Sym);
-}
-
-template <class ELFT>
-void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_t Addend,
- RelExpr Expr) {
- // For "true" local symbols which can be referenced from the same module
- // only compiler creates two instructions for address loading:
- //
- // lw $8, 0($gp) # R_MIPS_GOT16
- // addi $8, $8, 0 # R_MIPS_LO16
- //
- // The first instruction loads high 16 bits of the symbol address while
- // the second adds an offset. That allows to reduce number of required
- // GOT entries because only one global offset table entry is necessary
- // for every 64 KBytes of local data. So for local symbols we need to
- // allocate number of GOT entries to hold all required "page" addresses.
- //
- // All global symbols (hidden and regular) considered by compiler uniformly.
- // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
- // to load address of the symbol. So for each such symbol we need to
- // allocate dedicated GOT entry to store its address.
- //
- // If a symbol is preemptible we need help of dynamic linker to get its
- // final address. The corresponding GOT entries are allocated in the
- // "global" part of GOT. Entries for non preemptible global symbol allocated
- // in the "local" part of GOT.
- //
- // See "Global Offset Table" in Chapter 5:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
- // At this point we do not know final symbol value so to reduce number
- // of allocated GOT entries do the following trick. Save all output
- // sections referenced by GOT relocations. Then later in the `finalize`
- // method calculate number of "pages" required to cover all saved output
- // section and allocate appropriate number of GOT entries.
- auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
- MipsOutSections.insert(OutSec);
- return;
- }
- if (Sym.isTls()) {
- // GOT entries created for MIPS TLS relocations behave like
- // almost GOT entries from other ABIs. They go to the end
- // of the global offset table.
- Sym.GotIndex = Entries.size();
- Entries.push_back(&Sym);
- return;
- }
- auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
- if (S.isInGot() && !A)
- return;
- size_t NewIndex = Items.size();
- if (!MipsGotMap.insert({{&S, A}, NewIndex}).second)
- return;
- Items.emplace_back(&S, A);
- if (!A)
- S.GotIndex = NewIndex;
- };
- if (Sym.isPreemptible()) {
- // Ignore addends for preemptible symbols. They got single GOT entry anyway.
- AddEntry(Sym, 0, MipsGlobal);
- Sym.IsInGlobalMipsGot = true;
- } else if (Expr == R_MIPS_GOT_OFF32) {
- AddEntry(Sym, Addend, MipsLocal32);
- Sym.Is32BitMipsGot = true;
- } else {
- // Hold local GOT entries accessed via a 16-bit index separately.
- // That allows to write them in the beginning of the GOT and keep
- // their indexes as less as possible to escape relocation's overflow.
- AddEntry(Sym, Addend, MipsLocal);
- }
-}
-
-template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
- if (Sym.GlobalDynIndex != -1U)
- return false;
- Sym.GlobalDynIndex = Entries.size();
- // Global Dynamic TLS entries take two GOT slots.
- Entries.push_back(nullptr);
- Entries.push_back(&Sym);
- return true;
-}
-
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-template <class ELFT> bool GotSection<ELFT>::addTlsIndex() {
- if (TlsIndexOff != uint32_t(-1))
- return false;
- TlsIndexOff = Entries.size() * sizeof(uintX_t);
- Entries.push_back(nullptr);
- Entries.push_back(nullptr);
- return true;
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
- // Initialize the entry by the %hi(EntryValue) expression
- // but without right-shifting.
- EntryValue = (EntryValue + 0x8000) & ~0xffff;
- // Take into account MIPS GOT header.
- // See comment in the GotSection::writeTo.
- size_t NewIndex = MipsLocalGotPos.size() + 2;
- auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
- assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
- return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
- // Calculate offset of the GOT entries block: TLS, global, local.
- uintX_t GotBlockOff;
- if (B.isTls())
- GotBlockOff = getMipsTlsOffset();
- else if (B.IsInGlobalMipsGot)
- GotBlockOff = getMipsLocalEntriesNum() * sizeof(uintX_t);
- else if (B.Is32BitMipsGot)
- GotBlockOff = (MipsPageEntries + MipsLocal.size()) * sizeof(uintX_t);
- else
- GotBlockOff = MipsPageEntries * sizeof(uintX_t);
- // Calculate index of the GOT entry in the block.
- uintX_t GotIndex;
- if (B.isInGot())
- GotIndex = B.GotIndex;
- else {
- auto It = MipsGotMap.find({&B, Addend});
- assert(It != MipsGotMap.end());
- GotIndex = It->second;
- }
- return GotBlockOff + GotIndex * sizeof(uintX_t) - MipsGPOffset;
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t GotSection<ELFT>::getMipsTlsOffset() const {
- return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
- return this->Addr + B.GlobalDynIndex * sizeof(uintX_t);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
- return B.GlobalDynIndex * sizeof(uintX_t);
-}
-
-template <class ELFT>
-const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
- return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
-}
-
-template <class ELFT>
-unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
- return MipsPageEntries + MipsLocal.size() + MipsLocal32.size();
-}
-
-template <class ELFT> void GotSection<ELFT>::finalize() {
- size_t EntriesNum = Entries.size();
- if (Config->EMachine == EM_MIPS) {
- // Take into account MIPS GOT header.
- // See comment in the GotSection::writeTo.
- MipsPageEntries += 2;
- for (const OutputSectionBase *OutSec : MipsOutSections) {
- // Calculate an upper bound of MIPS GOT entries required to store page
- // addresses of local symbols. We assume the worst case - each 64kb
- // page of the output section has at least one GOT relocation against it.
- // Add 0x8000 to the section's size because the page address stored
- // in the GOT entry is calculated as (value + 0x8000) & ~0xffff.
- MipsPageEntries += (OutSec->Size + 0x8000 + 0xfffe) / 0xffff;
- }
- EntriesNum += getMipsLocalEntriesNum() + MipsGlobal.size();
- }
- this->Size = EntriesNum * sizeof(uintX_t);
-}
-
-template <class ELFT>
-static void writeUint(uint8_t *Buf, typename ELFT::uint Val) {
- typedef typename ELFT::uint uintX_t;
- write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf, Val);
-}
-
-template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
- // Set the MSB of the second GOT slot. This is not required by any
- // MIPS ABI documentation, though.
- //
- // There is a comment in glibc saying that "The MSB of got[1] of a
- // gnu object is set to identify gnu objects," and in GNU gold it
- // says "the second entry will be used by some runtime loaders".
- // But how this field is being used is unclear.
- //
- // We are not really willing to mimic other linkers behaviors
- // without understanding why they do that, but because all files
- // generated by GNU tools have this special GOT value, and because
- // we've been doing this for years, it is probably a safe bet to
- // keep doing this for now. We really need to revisit this to see
- // if we had to do this.
- auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
- P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
- // Write 'page address' entries to the local part of the GOT.
- for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
- uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
- writeUint<ELFT>(Entry, L.first);
- }
- Buf += MipsPageEntries * sizeof(uintX_t);
- auto AddEntry = [&](const MipsGotEntry &SA) {
- uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
- const SymbolBody *Body = SA.first;
- uintX_t VA = Body->template getVA<ELFT>(SA.second);
- writeUint<ELFT>(Entry, VA);
- };
- std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
- std::for_each(std::begin(MipsLocal32), std::end(MipsLocal32), AddEntry);
- std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
- // Initialize TLS-related GOT entries. If the entry has a corresponding
- // dynamic relocations, leave it initialized by zero. Write down adjusted
- // TLS symbol's values otherwise. To calculate the adjustments use offsets
- // for thread-local storage.
- // https://www.linux-mips.org/wiki/NPTL
- if (TlsIndexOff != -1U && !Config->Pic)
- writeUint<ELFT>(Buf + TlsIndexOff, 1);
- for (const SymbolBody *B : Entries) {
- if (!B || B->isPreemptible())
- continue;
- uintX_t VA = B->getVA<ELFT>();
- if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x7000);
- }
- if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
- writeUint<ELFT>(Entry, 1);
- Entry += sizeof(uintX_t);
- writeUint<ELFT>(Entry, VA - 0x8000);
- }
- }
-}
-
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- if (Config->EMachine == EM_MIPS) {
- writeMipsGot(Buf);
- return;
- }
- for (const SymbolBody *B : Entries) {
- uint8_t *Entry = Buf;
- Buf += sizeof(uintX_t);
- if (!B)
- continue;
- if (B->isPreemptible())
- continue; // The dynamic linker will take care of it.
- uintX_t VA = B->getVA<ELFT>();
- writeUint<ELFT>(Entry, VA);
- }
-}
-
-template <class ELFT>
PltSection<ELFT>::PltSection()
: OutputSectionBase(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) {
this->Addralign = 16;
@@ -443,11 +174,11 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
if (Config->Rela)
P->r_addend = Rel.getAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getOutputSec() == Out<ELFT>::Got)
+ if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In<ELFT>::Got)
// Dynamic relocation against MIPS GOT section make deal TLS entries
// allocated in the end of the GOT. We need to adjust the offset to take
// in account 'local' and 'global' GOT entries.
- P->r_offset += Out<ELFT>::Got->getMipsTlsOffset();
+ P->r_offset += In<ELFT>::Got->getMipsTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL);
}
@@ -794,12 +525,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
Add({DT_MIPS_FLAGS, RHF_NOTPOT});
Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase});
Add({DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()});
- Add({DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()});
- if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry())
+ Add({DT_MIPS_LOCAL_GOTNO, In<ELFT>::Got->getMipsLocalEntriesNum()});
+ if (const SymbolBody *B = In<ELFT>::Got->getMipsFirstGlobalEntry())
Add({DT_MIPS_GOTSYM, B->DynsymIndex});
else
Add({DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()});
- Add({DT_PLTGOT, Out<ELFT>::Got});
+ Add({DT_PLTGOT, In<ELFT>::Got});
if (Out<ELFT>::MipsRldMap)
Add({DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap});
}
@@ -1819,11 +1550,6 @@ template class EhFrameHeader<ELF32BE>;
template class EhFrameHeader<ELF64LE>;
template class EhFrameHeader<ELF64BE>;
-template class GotSection<ELF32LE>;
-template class GotSection<ELF32BE>;
-template class GotSection<ELF64LE>;
-template class GotSection<ELF64BE>;
-
template class PltSection<ELF32LE>;
template class PltSection<ELF32BE>;
template class PltSection<ELF64LE>;
OpenPOWER on IntegriCloud