diff options
| author | Eugene Leviant <eleviant@accesssoftek.com> | 2016-11-11 11:33:32 +0000 |
|---|---|---|
| committer | Eugene Leviant <eleviant@accesssoftek.com> | 2016-11-11 11:33:32 +0000 |
| commit | ad4439e8026ffd4552f2087ab9802b8098710c0d (patch) | |
| tree | a8d6aabe5c4105cf41121052f84712a72aa83212 /lld/ELF/OutputSections.cpp | |
| parent | 08dedfc5892ffba346a7843db0316275dbac80e1 (diff) | |
| download | bcm5719-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.cpp | 284 |
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>; |

