diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2013-02-27 01:30:27 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2013-02-27 01:30:27 +0000 |
commit | 2063679ec43c222e39e6e7849fa0a3d7a956195f (patch) | |
tree | 75e39d47ebf506a8eeaab32256a9454b32f86952 | |
parent | f352d8c7ec174b38aa7e0775c7b4ca6c0158cae8 (diff) | |
download | bcm5719-llvm-2063679ec43c222e39e6e7849fa0a3d7a956195f.tar.gz bcm5719-llvm-2063679ec43c222e39e6e7849fa0a3d7a956195f.zip |
[ELF][Writer] Add dynamic relocation tables.
This adds separate PLT and dynamic relocation tables. It also fills in the dynamic table
entries for them.
llvm-svn: 176150
-rw-r--r-- | lld/include/lld/ReaderWriter/ELFTargetInfo.h | 19 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/DefaultLayout.h | 42 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/SectionChunks.h | 67 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/Writer.cpp | 39 |
4 files changed, 146 insertions, 21 deletions
diff --git a/lld/include/lld/ReaderWriter/ELFTargetInfo.h b/lld/include/lld/ReaderWriter/ELFTargetInfo.h index 9362aac71e3..8f585965a1c 100644 --- a/lld/include/lld/ReaderWriter/ELFTargetInfo.h +++ b/lld/include/lld/ReaderWriter/ELFTargetInfo.h @@ -44,11 +44,28 @@ public: virtual StringRef getEntry() const; virtual uint64_t getBaseAddress() const { return _options._baseAddress; } - virtual bool isRuntimeRelocation(const DefinedAtom &, + /// \brief Does this relocation belong in the dynamic relocation table? + /// + /// This table is evaluated at loadtime by the dynamic loader and is + /// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table. + /// Relocations that return true will be added to the dynamic relocation + /// table. + virtual bool isDynamicRelocation(const DefinedAtom &, const Reference &) const { return false; } + /// \brief Does this relocation belong in the dynamic plt relocation table? + /// + /// This table holds all of the relocations used for delayed symbol binding. + /// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced + /// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table. + /// Relocations that return true will be added to the dynamic plt relocation + /// table. + virtual bool isPLTRelocation(const DefinedAtom &, const Reference &) const { + return false; + } + virtual StringRef getInterpreter() const { return "/lib64/ld-linux-x86-64.so.2"; } diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 96373e31ea9..48c97a45a21 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -144,9 +144,7 @@ public: typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT; - DefaultLayout(const ELFTargetInfo &ti) - : _relocationTable(nullptr), _targetInfo(ti) { - } + DefaultLayout(const ELFTargetInfo &ti) : _targetInfo(ti) {} /// \brief Return the section order for a input section virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType, @@ -243,14 +241,29 @@ public: return _programHeader; } - RelocationTable<ELFT> *getRelocationTable() { - // Only create the relocation table if it is needed. - if (!_relocationTable) { - _relocationTable.reset(new (_allocator) - RelocationTable<ELFT>(_targetInfo, ".rela.plt", ORDER_REL)); - addSection(_relocationTable.get()); + bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; } + + bool hasPLTRelocationTable() const { return !!_pltRelocationTable; } + + /// \brief Get or create the dynamic relocation table. All relocations in this + /// table are processed at startup. + RelocationTable<ELFT> *getDynamicRelocationTable() { + if (!_dynamicRelocationTable) { + _dynamicRelocationTable.reset(new (_allocator) RelocationTable<ELFT>( + _targetInfo, ".rela.dyn", ORDER_REL)); + addSection(_dynamicRelocationTable.get()); + } + return _dynamicRelocationTable.get(); + } + + /// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL. + RelocationTable<ELFT> *getPLTRelocationTable() { + if (!_pltRelocationTable) { + _pltRelocationTable.reset(new (_allocator) RelocationTable<ELFT>( + _targetInfo, ".rela.plt", ORDER_REL)); + addSection(_pltRelocationTable.get()); } - return _relocationTable.get(); + return _pltRelocationTable.get(); } uint64_t getTLSSize() const { @@ -277,7 +290,8 @@ private: std::vector<MergedSections<ELFT> *> _mergedSections; Header<ELFT> *_header; ProgramHeader<ELFT> *_programHeader; - LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _relocationTable; + LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _dynamicRelocationTable; + LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _pltRelocationTable; std::vector<AtomLayout *> _absoluteAtoms; const ELFTargetInfo &_targetInfo; }; @@ -472,8 +486,10 @@ ErrorOr<const AtomLayout &> DefaultLayout<ELFT>::addAtom(const Atom *atom) { getSection(sectionName, contentType, permissions); // Add runtime relocations to the .rela section. for (const auto &reloc : *definedAtom) - if (_targetInfo.isRuntimeRelocation(*definedAtom, *reloc)) - getRelocationTable()->addRelocation(*definedAtom, *reloc); + if (_targetInfo.isDynamicRelocation(*definedAtom, *reloc)) + getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc); + else if (_targetInfo.isPLTRelocation(*definedAtom, *reloc)) + getPLTRelocationTable()->addRelocation(*definedAtom, *reloc); return section->appendAtom(atom); } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) { // Absolute atoms are not part of any section, they are global for the whole diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 24d6f946690..68ea0932d48 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -29,6 +29,14 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" +namespace { +LLVM_ATTRIBUTE_UNUSED std::string kindOrUnknown(llvm::ErrorOr<std::string> k) { + if (k) + return *k; + return "<unknown>"; +} +} + namespace lld { namespace elf { template <class> class MergedSections; @@ -587,6 +595,18 @@ public: void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0); + /// \brief Get the symbol table index for an Atom. If it's not in the symbol + /// table, return STN_UNDEF. + uint32_t getSymbolTableIndex(const Atom *a) const { + auto se = std::find_if(_symbolTable.begin(), _symbolTable.end(), + [=](const SymbolEntry &se) { + return se._atom == a; + }); + if (se == _symbolTable.end()) + return STN_UNDEF; + return std::distance(_symbolTable.begin(), se); + } + virtual void finalize(); virtual void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer); @@ -740,7 +760,7 @@ public: typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; RelocationTable(const ELFTargetInfo &ti, StringRef str, int32_t order) - : Section<ELFT>(ti, str) { + : Section<ELFT>(ti, str), _symbolTable(nullptr) { this->setOrder(order); this->_entSize = sizeof(Elf_Rela); this->_align2 = llvm::alignOf<Elf_Rela>(); @@ -748,10 +768,36 @@ public: this->_flags = SHF_ALLOC; } - void addRelocation(const DefinedAtom &da, const Reference &r) { + /// \returns the index of the relocation added. + uint32_t addRelocation(const DefinedAtom &da, const Reference &r) { _relocs.emplace_back(&da, &r); this->_fsize = _relocs.size() * sizeof(Elf_Rela); this->_msize = this->_fsize; + return _relocs.size() - 1; + } + + bool getRelocationIndex(const Reference &r, uint32_t &res) { + auto rel = std::find_if( + _relocs.begin(), _relocs.end(), + [&](const std::pair<const DefinedAtom *, const Reference *> &p) { + if (p.second == &r) + return true; + return false; + }); + if (rel == _relocs.end()) + return false; + res = std::distance(_relocs.begin(), rel); + return true; + } + + void setSymbolTable(const SymbolTable<ELFT> *symbolTable) { + _symbolTable = symbolTable; + } + + virtual void finalize() { + this->_link = _symbolTable ? _symbolTable->ordinal() : 0; + if (this->_parent) + this->_parent->setLink(this->_link); } virtual void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) { @@ -759,21 +805,28 @@ public: uint8_t *dest = chunkBuffer + this->fileOffset(); for (const auto &rel : _relocs) { Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest); - r->setSymbolAndType(0, rel.second->kind()); + uint32_t index = + _symbolTable ? _symbolTable->getSymbolTableIndex(rel.second->target()) + : STN_UNDEF; + r->setSymbolAndType(index, rel.second->kind()); r->r_offset = writer->addressOfAtom(rel.first) + rel.second->offsetInAtom(); r->r_addend = writer->addressOfAtom(rel.second->target()) + rel.second->addend(); dest += sizeof(Elf_Rela); - DEBUG_WITH_TYPE("ELFRelocationTable", llvm::dbgs() - << "IRELATIVE relocation at " << rel.first->name() << "@" - << r->r_offset << " to " << rel.second->target()->name() - << "@" << r->r_addend << "\n"); + DEBUG_WITH_TYPE("ELFRelocationTable", + llvm::dbgs() + << kindOrUnknown(this->_targetInfo.stringFromRelocKind( + rel.second->kind())) << " relocation at " + << rel.first->name() << "@" << r->r_offset << " to " + << rel.second->target()->name() << "@" << r->r_addend + << "\n"); } } private: std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs; + const SymbolTable<ELFT> *_symbolTable; }; template <class ELFT> class DynamicTable : public Section<ELFT> { diff --git a/lld/lib/ReaderWriter/ELF/Writer.cpp b/lld/lib/ReaderWriter/ELF/Writer.cpp index 2412515ad43..a32aa61ee9c 100644 --- a/lld/lib/ReaderWriter/ELF/Writer.cpp +++ b/lld/lib/ReaderWriter/ELF/Writer.cpp @@ -69,6 +69,26 @@ private: _dt_strsz = _dynamicTable->addEntry(dyn); dyn.d_tag = DT_SYMENT; _dt_syment = _dynamicTable->addEntry(dyn); + if (_layout->hasDynamicRelocationTable()) { + dyn.d_tag = DT_RELA; + _dt_rela = _dynamicTable->addEntry(dyn); + dyn.d_tag = DT_RELASZ; + _dt_relasz = _dynamicTable->addEntry(dyn); + dyn.d_tag = DT_RELAENT; + _dt_relaent = _dynamicTable->addEntry(dyn); + } + if (_layout->hasPLTRelocationTable()) { + dyn.d_tag = DT_PLTRELSZ; + _dt_pltrelsz = _dynamicTable->addEntry(dyn); + dyn.d_tag = DT_PLTGOT; + _dt_pltgot = _dynamicTable->addEntry(dyn); + dyn.d_tag = DT_PLTREL; + dyn.d_un.d_val = DT_RELA; + _dt_pltrel = _dynamicTable->addEntry(dyn); + dyn.d_un.d_val = 0; + dyn.d_tag = DT_JMPREL; + _dt_jmprel = _dynamicTable->addEntry(dyn); + } } void updateDynamicTable() { @@ -78,6 +98,19 @@ private: tbl[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr(); tbl[_dt_strsz].d_un.d_val = _dynamicStringTable->memSize(); tbl[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize(); + if (_layout->hasDynamicRelocationTable()) { + auto relaTbl = _layout->getDynamicRelocationTable(); + tbl[_dt_rela].d_un.d_val = relaTbl->virtualAddr(); + tbl[_dt_relasz].d_un.d_val = relaTbl->memSize(); + tbl[_dt_relaent].d_un.d_val = relaTbl->getEntSize(); + } + if (_layout->hasPLTRelocationTable()) { + auto relaTbl = _layout->getPLTRelocationTable(); + tbl[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr(); + tbl[_dt_pltrelsz].d_un.d_val = relaTbl->memSize(); + auto gotplt = _layout->findOutputSection(".got.plt"); + tbl[_dt_pltgot].d_un.d_val = gotplt->virtualAddr(); + } } llvm::BumpPtrAllocator _alloc; @@ -414,6 +447,12 @@ void ExecutableWriter<ELFT>::createDefaultSections() { _layout->addSection(_interpSection.get()); _layout->addSection(_hashTable.get()); _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); + if (_layout->hasDynamicRelocationTable()) + _layout->getDynamicRelocationTable()->setSymbolTable( + _dynamicSymbolTable.get()); + if (_layout->hasPLTRelocationTable()) + _layout->getPLTRelocationTable()->setSymbolTable( + _dynamicSymbolTable.get()); } // give a chance for the target to add sections |