summaryrefslogtreecommitdiffstats
path: root/lld/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/OutputSections.cpp58
-rw-r--r--lld/ELF/OutputSections.h12
-rw-r--r--lld/ELF/Writer.cpp17
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);
OpenPOWER on IntegriCloud