From ad4439e8026ffd4552f2087ab9802b8098710c0d Mon Sep 17 00:00:00 2001 From: Eugene Leviant Date: Fri, 11 Nov 2016 11:33:32 +0000 Subject: [PATCH] [ELF] Convert .got section to input section Differential revision: https://reviews.llvm.org/D26498 llvm-svn: 286580 --- lld/ELF/InputSection.cpp | 36 +++--- lld/ELF/OutputSections.cpp | 284 +----------------------------------------- lld/ELF/OutputSections.h | 73 +---------- lld/ELF/Relocations.cpp | 52 ++++---- lld/ELF/Symbols.cpp | 2 +- lld/ELF/SyntheticSections.cpp | 278 ++++++++++++++++++++++++++++++++++++++++- lld/ELF/SyntheticSections.h | 73 ++++++++++- lld/ELF/Target.cpp | 2 +- lld/ELF/Writer.cpp | 60 ++++++--- 9 files changed, 443 insertions(+), 417 deletions(-) diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 9823f4ad..78449db 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -304,9 +304,9 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_TLSLD: - return Out::Got->getTlsIndexOff() + A - Out::Got->Size; + return In::Got->getTlsIndexOff() + A - In::Got->getSize(); case R_TLSLD_PC: - return Out::Got->getTlsIndexVA() + A - P; + return In::Got->getTlsIndexVA() + A - P; case R_THUNK_ABS: return Body.getThunkVA() + A; case R_THUNK_PC: @@ -315,13 +315,14 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, case R_PPC_TOC: return getPPC64TocBase() + A; case R_TLSGD: - return Out::Got->getGlobalDynOffset(Body) + A - Out::Got->Size; + return In::Got->getGlobalDynOffset(Body) + A - + In::Got->getSize(); case R_TLSGD_PC: - return Out::Got->getGlobalDynAddr(Body) + A - P; + return In::Got->getGlobalDynAddr(Body) + A - P; case R_TLSDESC: - return Out::Got->getGlobalDynAddr(Body) + A; + return In::Got->getGlobalDynAddr(Body) + A; case R_TLSDESC_PAGE: - return getAArch64Page(Out::Got->getGlobalDynAddr(Body) + A) - + return getAArch64Page(In::Got->getGlobalDynAddr(Body) + A) - getAArch64Page(P); case R_PLT: return Body.getPltVA() + A; @@ -331,12 +332,13 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, case R_SIZE: return Body.getSize() + A; case R_GOTREL: - return Body.getVA(A) - Out::Got->Addr; + return Body.getVA(A) - In::Got->getVA(); case R_GOTREL_FROM_END: - return Body.getVA(A) - Out::Got->Addr - Out::Got->Size; + return Body.getVA(A) - In::Got->getVA() - + In::Got->getSize(); case R_RELAX_TLS_GD_TO_IE_END: case R_GOT_FROM_END: - return Body.getGotOffset() + A - Out::Got->Size; + return Body.getGotOffset() + A - In::Got->getSize(); case R_RELAX_TLS_GD_TO_IE_ABS: case R_GOT: return Body.getGotVA() + A; @@ -347,9 +349,9 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, case R_GOT_PC: return Body.getGotVA() + A - P; case R_GOTONLY_PC: - return Out::Got->Addr + A - P; + return In::Got->getVA() + A - P; case R_GOTONLY_PC_FROM_END: - return Out::Got->Addr + A - P + Out::Got->Size; + return In::Got->getVA() + A - P + In::Got->getSize(); case R_RELAX_TLS_LD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_GD_TO_LE: @@ -378,19 +380,19 @@ static typename ELFT::uint getSymVA(uint32_t Type, typename ELFT::uint A, // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return Out::Got->getMipsLocalPageOffset(Body.getVA(A)); + return In::Got->getMipsLocalPageOffset(Body.getVA(A)); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return Out::Got->getMipsGotOffset(Body, A); + return In::Got->getMipsGotOffset(Body, A); case R_MIPS_TLSGD: - return Out::Got->getGlobalDynOffset(Body) + - Out::Got->getMipsTlsOffset() - MipsGPOffset; + return In::Got->getGlobalDynOffset(Body) + + In::Got->getMipsTlsOffset() - MipsGPOffset; case R_MIPS_TLSLD: - return Out::Got->getTlsIndexOff() + - Out::Got->getMipsTlsOffset() - MipsGPOffset; + return In::Got->getTlsIndexOff() + In::Got->getMipsTlsOffset() - + MipsGPOffset; case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index c2c37f2..b1b71fe 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -109,275 +109,6 @@ template void GdbIndexSection::writeTo(uint8_t *Buf) { } template -GotSection::GotSection() - : OutputSectionBase(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE) { - if (Config->EMachine == EM_MIPS) - this->Flags |= SHF_MIPS_GPREL; - this->Addralign = Target->GotEntrySize; -} - -template void GotSection::addEntry(SymbolBody &Sym) { - Sym.GotIndex = Entries.size(); - Entries.push_back(&Sym); -} - -template -void GotSection::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>(&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 bool GotSection::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 bool GotSection::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 -typename GotSection::uintX_t -GotSection::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 -typename GotSection::uintX_t -GotSection::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 -typename GotSection::uintX_t GotSection::getMipsTlsOffset() const { - return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t); -} - -template -typename GotSection::uintX_t -GotSection::getGlobalDynAddr(const SymbolBody &B) const { - return this->Addr + B.GlobalDynIndex * sizeof(uintX_t); -} - -template -typename GotSection::uintX_t -GotSection::getGlobalDynOffset(const SymbolBody &B) const { - return B.GlobalDynIndex * sizeof(uintX_t); -} - -template -const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { - return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; -} - -template -unsigned GotSection::getMipsLocalEntriesNum() const { - return MipsPageEntries + MipsLocal.size() + MipsLocal32.size(); -} - -template void GotSection::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 -static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { - typedef typename ELFT::uint uintX_t; - write(Buf, Val); -} - -template void GotSection::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(Buf); - P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); - // Write 'page address' entries to the local part of the GOT. - for (std::pair &L : MipsLocalGotPos) { - uint8_t *Entry = Buf + L.second * sizeof(uintX_t); - writeUint(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(SA.second); - writeUint(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(Buf + TlsIndexOff, 1); - for (const SymbolBody *B : Entries) { - if (!B || B->isPreemptible()) - continue; - uintX_t VA = B->getVA(); - if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); - writeUint(Entry, VA - 0x7000); - } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); - writeUint(Entry, 1); - Entry += sizeof(uintX_t); - writeUint(Entry, VA - 0x8000); - } - } -} - -template void GotSection::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(); - writeUint(Entry, VA); - } -} - -template PltSection::PltSection() : OutputSectionBase(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR) { this->Addralign = 16; @@ -443,11 +174,11 @@ template void RelocationSection::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::Got) + if (Config->EMachine == EM_MIPS && Rel.getInputSec() == In::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::Got->getMipsTlsOffset(); + P->r_offset += In::Got->getMipsTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->Mips64EL); } @@ -794,12 +525,12 @@ template void DynamicSection::finalize() { Add({DT_MIPS_FLAGS, RHF_NOTPOT}); Add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); Add({DT_MIPS_SYMTABNO, Out::DynSymTab->getNumSymbols()}); - Add({DT_MIPS_LOCAL_GOTNO, Out::Got->getMipsLocalEntriesNum()}); - if (const SymbolBody *B = Out::Got->getMipsFirstGlobalEntry()) + Add({DT_MIPS_LOCAL_GOTNO, In::Got->getMipsLocalEntriesNum()}); + if (const SymbolBody *B = In::Got->getMipsFirstGlobalEntry()) Add({DT_MIPS_GOTSYM, B->DynsymIndex}); else Add({DT_MIPS_GOTSYM, Out::DynSymTab->getNumSymbols()}); - Add({DT_PLTGOT, Out::Got}); + Add({DT_PLTGOT, In::Got}); if (Out::MipsRldMap) Add({DT_MIPS_RLD_MAP, Out::MipsRldMap}); } @@ -1819,11 +1550,6 @@ template class EhFrameHeader; template class EhFrameHeader; template class EhFrameHeader; -template class GotSection; -template class GotSection; -template class GotSection; -template class GotSection; - template class PltSection; template class PltSection; template class PltSection; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index f99f39e..1ef379e 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -15,7 +15,6 @@ #include "Relocations.h" #include "lld/Core/LLVM.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" @@ -50,7 +49,6 @@ public: EHFrame, EHFrameHdr, GnuHashTable, - Got, HashTable, Merge, Plt, @@ -142,74 +140,6 @@ private: uint32_t CuTypesOffset; }; -template class GotSection final : public OutputSectionBase { - typedef typename ELFT::uint uintX_t; - -public: - GotSection(); - void finalize() override; - void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody &Sym); - void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); - bool addDynTlsEntry(SymbolBody &Sym); - bool addTlsIndex(); - bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } - uintX_t getMipsLocalPageOffset(uintX_t Addr); - uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; - uintX_t getGlobalDynAddr(const SymbolBody &B) const; - uintX_t getGlobalDynOffset(const SymbolBody &B) const; - Kind getKind() const override { return Got; } - static bool classof(const OutputSectionBase *B) { - return B->getKind() == Got; - } - - // Returns the symbol which corresponds to the first entry of the global part - // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic - // table properties. - // Returns nullptr if the global part is empty. - const SymbolBody *getMipsFirstGlobalEntry() const; - - // Returns the number of entries in the local part of GOT including - // the number of reserved entries. This method is MIPS-specific. - unsigned getMipsLocalEntriesNum() const; - - // Returns offset of TLS part of the MIPS GOT table. This part goes - // after 'local' and 'global' entries. - uintX_t getMipsTlsOffset() const; - - uintX_t getTlsIndexVA() { return this->Addr + TlsIndexOff; } - uint32_t getTlsIndexOff() const { return TlsIndexOff; } - - // Flag to force GOT to be in output if we have relocations - // that relies on its address. - bool HasGotOffRel = false; - -private: - std::vector Entries; - uint32_t TlsIndexOff = -1; - uint32_t MipsPageEntries = 0; - // Output sections referenced by MIPS GOT relocations. - llvm::SmallPtrSet MipsOutSections; - llvm::DenseMap MipsLocalGotPos; - - // MIPS ABI requires to create unique GOT entry for each Symbol/Addend - // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` - // or `MipsGlobal` vectors. In general it does not have a sence to take in - // account addend for preemptible symbols because the corresponding - // GOT entries should have one-to-one mapping with dynamic symbols table. - // But we use the same container's types for both kind of GOT entries - // to handle them uniformly. - typedef std::pair MipsGotEntry; - typedef std::vector MipsGotEntries; - llvm::DenseMap MipsGotMap; - MipsGotEntries MipsLocal; - MipsGotEntries MipsLocal32; - MipsGotEntries MipsGlobal; - - // Write MIPS-specific parts of the GOT. - void writeMipsGot(uint8_t *Buf); -}; - template class PltSection final : public OutputSectionBase { typedef typename ELFT::uint uintX_t; @@ -248,6 +178,7 @@ public: uintX_t getAddend() const; uint32_t getSymIndex() const; const OutputSectionBase *getOutputSec() const { return OutputSec; } + const InputSectionBase *getInputSec() const { return InputSec; } uint32_t Type; @@ -661,7 +592,6 @@ template struct Out { static EhOutputSection *EhFrame; static GdbIndexSection *GdbIndex; static GnuHashTableSection *GnuHashTab; - static GotSection *Got; static HashTableSection *HashTab; static OutputSection *Bss; static OutputSection *MipsRldMap; @@ -726,7 +656,6 @@ template EhFrameHeader *Out::EhFrameHdr; template EhOutputSection *Out::EhFrame; template GdbIndexSection *Out::GdbIndex; template GnuHashTableSection *Out::GnuHashTab; -template GotSection *Out::Got; template HashTableSection *Out::HashTab; template OutputSection *Out::Bss; template OutputSection *Out::MipsRldMap; diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 07ba930..55665dea 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -101,23 +101,23 @@ static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body, typename ELFT::uint Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { - if (Out::Got->addTlsIndex() && + if (In::Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM)) - Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, - Out::Got->getTlsIndexOff(), false, + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, In::Got, + In::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } typedef typename ELFT::uint uintX_t; if (Target->isTlsGlobalDynamicRel(Type)) { - if (Out::Got->addDynTlsEntry(Body) && + if (In::Got->addDynTlsEntry(Body) && (Body.isPreemptible() || Config->EMachine == EM_ARM)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsModuleIndexRel, In::Got, Off, false, &Body, 0}); if (Body.isPreemptible()) - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, + Out::RelaDyn->addReloc({Target->TlsOffsetRel, In::Got, Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } @@ -147,10 +147,10 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) && Config->Shared) { - if (Out::Got->addDynTlsEntry(Body)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + if (In::Got->addDynTlsEntry(Body)) { + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsDescRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsDescRel, In::Got, Off, false, &Body, 0}); } if (Expr != R_TLSDESC_CALL) C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); @@ -164,9 +164,9 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 2; } - if (Out::Got->addTlsIndex()) - Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, - Out::Got->getTlsIndexOff(), false, + if (In::Got->addTlsIndex()) + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, In::Got, + In::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; @@ -182,15 +182,15 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL || Target->isTlsGlobalDynamicRel(Type)) { if (Config->Shared) { - if (Out::Got->addDynTlsEntry(Body)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); + if (In::Got->addDynTlsEntry(Body)) { + uintX_t Off = In::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); + {Target->TlsModuleIndexRel, In::Got, Off, false, &Body, 0}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. if (isPreemptible(Body, Type)) - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, + Out::RelaDyn->addReloc({Target->TlsOffsetRel, In::Got, Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } @@ -205,8 +205,8 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, Offset, Addend, &Body}); if (!Body.isInGot()) { - Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, + In::Got->addEntry(Body); + Out::RelaDyn->addReloc({Target->TlsGotRel, In::Got, Body.getGotOffset(), false, &Body, 0}); } @@ -671,7 +671,7 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { // needs it to be created. Here we request for that. if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END || Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC) - Out::Got->HasGotOffRel = true; + In::Got->HasGotOffRel = true; uintX_t Addend = computeAddend(File, Buf, E, RI, Expr, Body); @@ -725,7 +725,7 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - Out::Got->addMipsEntry(Body, Addend, Expr); + In::Got->addMipsEntry(Body, Addend, Expr); continue; } @@ -760,9 +760,9 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Out::Got->addMipsEntry(Body, Addend, Expr); + In::Got->addMipsEntry(Body, Addend, Expr); if (Body.isTls() && Body.isPreemptible()) - AddDyn({Target->TlsGotRel, Out::Got, Body.getGotOffset(), + AddDyn({Target->TlsGotRel, In::Got, Body.getGotOffset(), false, &Body, 0}); continue; } @@ -770,7 +770,7 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { if (Body.isInGot()) continue; - Out::Got->addEntry(Body); + In::Got->addEntry(Body); if (Preemptible || (Config->Pic && !isAbsolute(Body))) { uint32_t DynType; if (Body.isTls()) @@ -779,8 +779,8 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { DynType = Target->GotRel; else DynType = Target->RelativeRel; - AddDyn({DynType, Out::Got, Body.getGotOffset(), - !Preemptible, &Body, 0}); + AddDyn({DynType, In::Got, Body.getGotOffset(), !Preemptible, + &Body, 0}); } continue; } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index fc1bbd1..e6572c7 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -151,7 +151,7 @@ typename ELFT::uint SymbolBody::getVA(typename ELFT::uint Addend) const { } template typename ELFT::uint SymbolBody::getGotVA() const { - return Out::Got->Addr + getGotOffset(); + return In::Got->getVA() + getGotOffset(); } template typename ELFT::uint SymbolBody::getGotOffset() const { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 66468da..24e3e40 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -198,7 +198,7 @@ MipsOptionsSection::MipsOptionsSection() template void MipsOptionsSection::finalize() { if (!Config->Relocatable) getOptions()->getRegInfo().ri_gp_value = - Out::Got->Addr + MipsGPOffset; + In::Got->getVA() + MipsGPOffset; } // MIPS .reginfo section. @@ -226,7 +226,7 @@ MipsReginfoSection::MipsReginfoSection() template void MipsReginfoSection::finalize() { if (!Config->Relocatable) - Reginfo.ri_gp_value = Out::Got->Addr + MipsGPOffset; + Reginfo.ri_gp_value = In::Got->getVA() + MipsGPOffset; } static ArrayRef createInterp() { @@ -345,6 +345,275 @@ void BuildIdHexstring::writeBuildId(MutableArrayRef Buf) { } template +GotSection::GotSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + Target->GotEntrySize, ".got") { + if (Config->EMachine == EM_MIPS) + this->Flags |= SHF_MIPS_GPREL; +} + +template void GotSection::addEntry(SymbolBody &Sym) { + Sym.GotIndex = Entries.size(); + Entries.push_back(&Sym); +} + +template +void GotSection::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>(&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 bool GotSection::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 bool GotSection::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 +typename GotSection::uintX_t +GotSection::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 +typename GotSection::uintX_t +GotSection::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 +typename GotSection::uintX_t GotSection::getMipsTlsOffset() const { + return (getMipsLocalEntriesNum() + MipsGlobal.size()) * sizeof(uintX_t); +} + +template +typename GotSection::uintX_t +GotSection::getGlobalDynAddr(const SymbolBody &B) const { + return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t); +} + +template +typename GotSection::uintX_t +GotSection::getGlobalDynOffset(const SymbolBody &B) const { + return B.GlobalDynIndex * sizeof(uintX_t); +} + +template +const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { + return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first; +} + +template +unsigned GotSection::getMipsLocalEntriesNum() const { + return MipsPageEntries + MipsLocal.size() + MipsLocal32.size(); +} + +template void GotSection::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(); + } + Size = EntriesNum * sizeof(uintX_t); +} + +template +static void writeUint(uint8_t *Buf, typename ELFT::uint Val) { + typedef typename ELFT::uint uintX_t; + write(Buf, Val); +} + +template void GotSection::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(Buf); + P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31); + // Write 'page address' entries to the local part of the GOT. + for (std::pair &L : MipsLocalGotPos) { + uint8_t *Entry = Buf + L.second * sizeof(uintX_t); + writeUint(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(SA.second); + writeUint(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(Buf + TlsIndexOff, 1); + for (const SymbolBody *B : Entries) { + if (!B || B->isPreemptible()) + continue; + uintX_t VA = B->getVA(); + if (B->GotIndex != -1U) { + uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); + writeUint(Entry, VA - 0x7000); + } + if (B->GlobalDynIndex != -1U) { + uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); + writeUint(Entry, 1); + Entry += sizeof(uintX_t); + writeUint(Entry, VA - 0x8000); + } + } +} + +template void GotSection::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(); + writeUint(Entry, VA); + } +} + +template GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, ".got.plt") { @@ -434,6 +703,11 @@ template class elf::BuildIdHexstring; template class elf::BuildIdHexstring; template class elf::BuildIdHexstring; +template class elf::GotSection; +template class elf::GotSection; +template class elf::GotSection; +template class elf::GotSection; + template class elf::GotPltSection; template class elf::GotPltSection; template class elf::GotPltSection; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index f35e904..756d198 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -11,6 +11,7 @@ #define LLD_ELF_SYNTHETIC_SECTION_H #include "InputSection.h" +#include "llvm/ADT/SmallPtrSet.h" namespace lld { namespace elf { @@ -69,6 +70,9 @@ public: virtual void writeTo(uint8_t *Buf) = 0; virtual size_t getSize() const { return this->Data.size(); } + uintX_t getVA() const { + return this->OutSec ? this->OutSec->Addr + this->OutSecOff : 0; + } static bool classof(const InputSectionData *D) { return D->kind() == InputSectionData::Synthetic; @@ -131,6 +135,72 @@ public: void writeBuildId(llvm::MutableArrayRef) override; }; +template class GotSection final : public SyntheticSection { + typedef typename ELFT::uint uintX_t; + +public: + GotSection(); + void writeTo(uint8_t *Buf) override; + size_t getSize() const override { return Size; } + void finalize(); + void addEntry(SymbolBody &Sym); + void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); + bool addDynTlsEntry(SymbolBody &Sym); + bool addTlsIndex(); + bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } + uintX_t getMipsLocalPageOffset(uintX_t Addr); + uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; + uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getGlobalDynOffset(const SymbolBody &B) const; + + // Returns the symbol which corresponds to the first entry of the global part + // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic + // table properties. + // Returns nullptr if the global part is empty. + const SymbolBody *getMipsFirstGlobalEntry() const; + + // Returns the number of entries in the local part of GOT including + // the number of reserved entries. This method is MIPS-specific. + unsigned getMipsLocalEntriesNum() const; + + // Returns offset of TLS part of the MIPS GOT table. This part goes + // after 'local' and 'global' entries. + uintX_t getMipsTlsOffset() const; + + uintX_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; } + uint32_t getTlsIndexOff() const { return TlsIndexOff; } + + // Flag to force GOT to be in output if we have relocations + // that relies on its address. + bool HasGotOffRel = false; + +private: + std::vector Entries; + uint32_t TlsIndexOff = -1; + uint32_t MipsPageEntries = 0; + uintX_t Size = 0; + // Output sections referenced by MIPS GOT relocations. + llvm::SmallPtrSet MipsOutSections; + llvm::DenseMap MipsLocalGotPos; + + // MIPS ABI requires to create unique GOT entry for each Symbol/Addend + // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` + // or `MipsGlobal` vectors. In general it does not have a sence to take in + // account addend for preemptible symbols because the corresponding + // GOT entries should have one-to-one mapping with dynamic symbols table. + // But we use the same container's types for both kind of GOT entries + // to handle them uniformly. + typedef std::pair MipsGotEntry; + typedef std::vector MipsGotEntries; + llvm::DenseMap MipsGotMap; + MipsGotEntries MipsLocal; + MipsGotEntries MipsLocal32; + MipsGotEntries MipsGlobal; + + // Write MIPS-specific parts of the GOT. + void writeMipsGot(uint8_t *Buf); +}; + template class GotPltSection final : public SyntheticSection { typedef typename ELFT::uint uintX_t; @@ -141,7 +211,6 @@ public: bool empty() const; size_t getSize() const override; void writeTo(uint8_t *Buf) override; - uintX_t getVA() { return this->OutSec->Addr + this->OutSecOff; } private: std::vector Entries; @@ -155,6 +224,7 @@ template MergeInputSection *createCommentSection(); template struct In { static BuildIdSection *BuildId; static InputSection *Common; + static GotSection *Got; static GotPltSection *GotPlt; static InputSection *Interp; static MipsAbiFlagsSection *MipsAbiFlags; @@ -164,6 +234,7 @@ template struct In { template BuildIdSection *In::BuildId; template InputSection *In::Common; +template GotSection *In::Got; template GotPltSection *In::GotPlt; template InputSection *In::Interp; template MipsAbiFlagsSection *In::MipsAbiFlags; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 5f8cf7c..56ea6a4 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -1020,7 +1020,7 @@ uint64_t getPPC64TocBase() { // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. - uint64_t TocVA = Out::Got->Addr; + uint64_t TocVA = In::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 64d6842..941a6d8 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -212,7 +212,6 @@ template void Writer::createSyntheticSections() { Out::DynStrTab = make>(".dynstr", true); Out::Dynamic = make>(); Out::EhFrame = make>(); - Out::Got = make>(); Out::Plt = make>(); Out::RelaDyn = make>( Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); @@ -313,6 +312,7 @@ template void Writer::createSyntheticSections() { } } + In::Got = make>(); In::GotPlt = make>(); } @@ -427,7 +427,7 @@ template bool elf::isRelroSection(const OutputSectionBase *Sec) { return true; if (Sec == In::GotPlt->OutSec) return Config->ZNow; - if (Sec == Out::Dynamic || Sec == Out::Got) + if (Sec == Out::Dynamic || Sec == In::Got->OutSec) return true; StringRef S = Sec->getName(); return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || @@ -557,6 +557,28 @@ static Symbol *addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec, return Symtab::X->addSynthetic(Name, Sec, Val, StOther); } +template +static Symbol *addRegular(StringRef Name, InputSectionBase *IS, + typename ELFT::uint Value) { + typename ELFT::Sym LocalHidden = {}; + LocalHidden.setBindingAndType(STB_LOCAL, STT_NOTYPE); + LocalHidden.setVisibility(STV_HIDDEN); + Symbol *S = Symtab::X->addRegular(Name, LocalHidden, IS); + cast>(S->body())->Value = Value; + return S; +} + +template +static Symbol *addOptionalRegular(StringRef Name, InputSectionBase *IS, + typename ELFT::uint Value) { + SymbolBody *S = Symtab::X->find(Name); + if (!S) + return nullptr; + if (!S->isUndefined() && !S->isShared()) + return S->symbol(); + return addRegular(Name, IS, Value); +} + // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve @@ -582,13 +604,11 @@ template void Writer::addReservedSymbols() { // so that it points to an absolute address which is relative to GOT. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Symtab::X->addSynthetic("_gp", Out::Got, MipsGPOffset, - STV_HIDDEN); + addRegular("_gp", In::Got, MipsGPOffset); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. - Symbol *Sym = - addOptionalSynthetic("_gp_disp", Out::Got, MipsGPOffset); + Symbol *Sym = addOptionalRegular("_gp_disp", In::Got, MipsGPOffset); if (Sym) ElfSym::MipsGpDisp = Sym->body(); @@ -596,7 +616,7 @@ template void Writer::addReservedSymbols() { // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html - addOptionalSynthetic("__gnu_local_gp", Out::Got, MipsGPOffset); + addOptionalRegular("__gnu_local_gp", In::Got, MipsGPOffset); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol @@ -888,13 +908,6 @@ template void Writer::finalizeSections() { // This function adds linker-created Out::* sections. addPredefinedSections(); - // We fill .got.plt section in scanRelocs(). This is the - // reason we don't add it earlier in createSections(). - if (!In::GotPlt->empty()) { - addInputSec(In::GotPlt); - In::GotPlt->OutSec->assignOffsets(); - } - sortSections(); unsigned I = 1; @@ -925,7 +938,7 @@ template void Writer::finalizeSections() { } template bool Writer::needsGot() { - if (!Out::Got->empty()) + if (!In::Got->empty()) return true; // We add the .got section to the result for dynamic MIPS target because @@ -935,7 +948,7 @@ template bool Writer::needsGot() { // If we have a relocation that is relative to GOT (such as GOTOFFREL), // we need to emit a GOT even if it's empty. - return Out::Got->HasGotOffRel; + return In::Got->HasGotOffRel; } // This function add Out::* sections to OutputSections. @@ -976,8 +989,19 @@ template void Writer::addPredefinedSections() { if (Out::RelaPlt && Out::RelaPlt->hasRelocs()) Add(Out::RelaPlt); - if (needsGot()) - Add(Out::Got); + // We fill .got and .got.plt sections in scanRelocs(). This is the + // reason we don't add it earlier in createSections(). + if (needsGot()) { + In::Got->finalize(); + addInputSec(In::Got); + In::Got->OutSec->assignOffsets(); + } + + if (!In::GotPlt->empty()) { + addInputSec(In::GotPlt); + In::GotPlt->OutSec->assignOffsets(); + } + if (!Out::Plt->empty()) Add(Out::Plt); if (!Out::EhFrame->empty()) -- 2.7.4