diff options
Diffstat (limited to 'lld/ELF')
-rw-r--r-- | lld/ELF/OutputSections.cpp | 58 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 12 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 17 |
3 files changed, 84 insertions, 3 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index f1eba00145f..1c8311c9864 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -94,6 +94,17 @@ GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const { return this->getVA() + B.GotIndex * sizeof(uintX_t); } +template <class ELFT> +const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const { + return Entries.empty() ? nullptr : Entries.front(); +} + +template <class ELFT> +unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const { + // TODO: Update when the suppoort of GOT entries for local symbols is added. + return Target->getGotHeaderEntriesNum(); +} + template <class ELFT> void GotSection<ELFT>::finalize() { this->Header.sh_size = (Target->getGotHeaderEntriesNum() + Entries.size()) * sizeof(uintX_t); @@ -477,6 +488,12 @@ DynamicSection<ELFT>::DynamicSection(SymbolTable<ELFT> &SymTab) Elf_Shdr &Header = this->Header; Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; Header.sh_entsize = ELFT::Is64Bits ? 16 : 8; + + // .dynamic section is not writable on MIPS. + // See "Special Section" in Chapter 4 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS) + Header.sh_flags = llvm::ELF::SHF_ALLOC; } template <class ELFT> void DynamicSection<ELFT>::finalize() { @@ -495,7 +512,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) { ++NumEntries; // DT_JMPREL ++NumEntries; // DT_PLTRELSZ - ++NumEntries; // DT_PLTGOT + ++NumEntries; // DT_PLTGOT / DT_MIPS_PLTGOT ++NumEntries; // DT_PLTREL } @@ -558,6 +575,19 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { ++NumEntries; // DT_FLAGS if (DtFlags1) ++NumEntries; // DT_FLAGS_1 + + if (Config->EMachine == EM_MIPS) { + ++NumEntries; // DT_MIPS_RLD_VERSION + ++NumEntries; // DT_MIPS_FLAGS + ++NumEntries; // DT_MIPS_BASE_ADDRESS + ++NumEntries; // DT_MIPS_SYMTABNO + ++NumEntries; // DT_MIPS_LOCAL_GOTNO + ++NumEntries; // DT_MIPS_GOTSYM; + ++NumEntries; // DT_PLTGOT + if (Out<ELFT>::MipsRldMap) + ++NumEntries; // DT_MIPS_RLD_MAP + } + ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; @@ -588,7 +618,12 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) { WritePtr(DT_JMPREL, Out<ELFT>::RelaPlt->getVA()); WriteVal(DT_PLTRELSZ, Out<ELFT>::RelaPlt->getSize()); - WritePtr(DT_PLTGOT, Out<ELFT>::GotPlt->getVA()); + // On MIPS, the address of the .got.plt section is stored in + // the DT_MIPS_PLTGOT entry because the DT_PLTGOT entry points to + // the .got section. See "Dynamic Section" in the following document: + // https://sourceware.org/ml/binutils/2008-07/txt00000.txt + WritePtr((Config->EMachine == EM_MIPS) ? DT_MIPS_PLTGOT : DT_PLTGOT, + Out<ELFT>::GotPlt->getVA()); WriteVal(DT_PLTREL, Out<ELFT>::RelaPlt->isRela() ? DT_RELA : DT_REL); } @@ -640,6 +675,25 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { WriteVal(DT_FLAGS, DtFlags); if (DtFlags1) WriteVal(DT_FLAGS_1, DtFlags1); + + // See "Dynamic Section" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS) { + WriteVal(DT_MIPS_RLD_VERSION, 1); + WriteVal(DT_MIPS_FLAGS, RHF_NOTPOT); + WritePtr(DT_MIPS_BASE_ADDRESS, Target->getVAStart()); + WriteVal(DT_MIPS_SYMTABNO, Out<ELFT>::DynSymTab->getNumSymbols()); + WriteVal(DT_MIPS_LOCAL_GOTNO, Out<ELFT>::Got->getMipsLocalEntriesNum()); + if (const SymbolBody *B = Out<ELFT>::Got->getMipsFirstGlobalEntry()) + WriteVal(DT_MIPS_GOTSYM, B->getDynamicSymbolTableIndex()); + else + WriteVal(DT_MIPS_GOTSYM, Out<ELFT>::DynSymTab->getNumSymbols()); + WritePtr(DT_PLTGOT, Out<ELFT>::Got->getVA()); + if (Out<ELFT>::MipsRldMap) + WritePtr(DT_MIPS_RLD_MAP, Out<ELFT>::MipsRldMap->getVA()); + } + WriteVal(DT_NULL, 0); } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 7814222cccc..d4846bca0ea 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -122,6 +122,16 @@ public: bool empty() const { return Entries.empty(); } uintX_t getEntryAddr(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; + private: std::vector<const SymbolBody *> Entries; }; @@ -403,6 +413,7 @@ template <class ELFT> struct Out { static HashTableSection<ELFT> *HashTab; static InterpSection<ELFT> *Interp; static OutputSection<ELFT> *Bss; + static OutputSection<ELFT> *MipsRldMap; static OutputSectionBase<ELFT> *Opd; static uint8_t *OpdBuf; static PltSection<ELFT> *Plt; @@ -424,6 +435,7 @@ template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got; template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab; template <class ELFT> InterpSection<ELFT> *Out<ELFT>::Interp; template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss; +template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap; template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::Opd; template <class ELFT> uint8_t *Out<ELFT>::OpdBuf; template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index b60fc7e52b1..edc47abbb90 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -632,8 +632,23 @@ template <class ELFT> void Writer<ELFT>::createSections() { OutputSections.push_back(Out<ELFT>::RelaDyn); if (Out<ELFT>::RelaPlt && Out<ELFT>::RelaPlt->hasRelocs()) OutputSections.push_back(Out<ELFT>::RelaPlt); + // This is a MIPS specific section to hold a space within the data segment + // of executable file which is pointed to by the DT_MIPS_RLD_MAP entry. + // See "Dynamic section" in Chapter 5 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (Config->EMachine == EM_MIPS && !Config->Shared) { + Out<ELFT>::MipsRldMap = new (SecAlloc.Allocate()) + OutputSection<ELFT>(".rld_map", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); + Out<ELFT>::MipsRldMap->setSize(ELFT::Is64Bits ? 8 : 4); + Out<ELFT>::MipsRldMap->updateAlign(ELFT::Is64Bits ? 8 : 4); + OutputSections.push_back(Out<ELFT>::MipsRldMap); + } } - if (!Out<ELFT>::Got->empty()) + + // We add the .got section to the result for dynamic MIPS target because + // its address and properties are mentioned in the .dynamic section. + if (!Out<ELFT>::Got->empty() || + (isOutputDynamic() && Config->EMachine == EM_MIPS)) OutputSections.push_back(Out<ELFT>::Got); if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty()) OutputSections.push_back(Out<ELFT>::GotPlt); |