diff options
Diffstat (limited to 'lib/ReaderWriter/ELF/SectionChunks.h')
-rw-r--r-- | lib/ReaderWriter/ELF/SectionChunks.h | 1124 |
1 files changed, 121 insertions, 1003 deletions
diff --git a/lib/ReaderWriter/ELF/SectionChunks.h b/lib/ReaderWriter/ELF/SectionChunks.h index 03bdb59e6568..b10ba05237ff 100644 --- a/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lib/ReaderWriter/ELF/SectionChunks.h @@ -11,19 +11,16 @@ #define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H #include "Chunk.h" -#include "Layout.h" #include "TargetHandler.h" #include "Writer.h" #include "lld/Core/DefinedAtom.h" -#include "lld/Core/Parallel.h" #include "lld/Core/range.h" -#include "llvm/ADT/ArrayRef.h" +#include "lld/ReaderWriter/AtomLayout.h" +#include "lld/ReaderWriter/ELFLinkingContext.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" @@ -35,29 +32,22 @@ namespace elf { template <class> class OutputSection; using namespace llvm::ELF; template <class ELFT> class Segment; +template <class ELFT> class TargetLayout; /// \brief An ELF section. template <class ELFT> class Section : public Chunk<ELFT> { public: - Section(const ELFLinkingContext &context, StringRef sectionName, + Section(const ELFLinkingContext &ctx, StringRef sectionName, StringRef chunkName, - typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection) - : Chunk<ELFT>(chunkName, k, context), _outputSection(nullptr), _flags(0), - _entSize(0), _type(0), _link(0), _info(0), - _isFirstSectionInOutputSection(false), _segmentType(SHT_NULL), - _inputSectionName(sectionName), _outputSectionName(sectionName) {} + typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection); /// \brief Modify the section contents before assigning virtual addresses // or assigning file offsets - void doPreFlight() override {} /// \brief Finalize the section contents before writing - void finalize() override {} /// \brief Does this section have an output segment. - virtual bool hasOutputSegment() { - return false; - } + virtual bool hasOutputSegment() const { return false; } /// Return if the section is a loadable section that occupies memory virtual bool isLoadableSection() const { return false; } @@ -73,26 +63,21 @@ public: uint32_t getType() const { return _type; } uint32_t getLink() const { return _link; } uint32_t getInfo() const { return _info; } - Layout::SegmentType getSegmentType() const { return _segmentType; } - /// \brief Return the type of content that the section contains - virtual int getContentType() const override { - if (_flags & llvm::ELF::SHF_EXECINSTR) - return Chunk<ELFT>::ContentType::Code; - else if (_flags & llvm::ELF::SHF_WRITE) - return Chunk<ELFT>::ContentType::Data; - else if (_flags & llvm::ELF::SHF_ALLOC) - return Chunk<ELFT>::ContentType::Code; - else - return Chunk<ELFT>::ContentType::Unknown; + typename TargetLayout<ELFT>::SegmentType getSegmentType() const { + return _segmentType; } + /// \brief Return the type of content that the section contains + int getContentType() const override; + /// \brief convert the segment type to a String for diagnostics and printing /// purposes - StringRef segmentKindToStr() const; + virtual StringRef segmentKindToStr() const; /// \brief Records the segmentType, that this section belongs to - void setSegmentType(const Layout::SegmentType segmentType) { + void + setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) { this->_segmentType = segmentType; } @@ -100,6 +85,10 @@ public: return nullptr; } + const OutputSection<ELFT> *getOutputSection() const { + return _outputSection; + } + void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) { _outputSection = os; _isFirstSectionInOutputSection = isFirst; @@ -133,21 +122,21 @@ public: protected: /// \brief OutputSection this Section is a member of, or nullptr. - OutputSection<ELFT> *_outputSection; + OutputSection<ELFT> *_outputSection = nullptr; /// \brief ELF SHF_* flags. - uint64_t _flags; + uint64_t _flags = 0; /// \brief The size of each entity. - uint64_t _entSize; + uint64_t _entSize = 0; /// \brief ELF SHT_* type. - uint32_t _type; + uint32_t _type = 0; /// \brief sh_link field. - uint32_t _link; + uint32_t _link = 0; /// \brief the sh_info field. - uint32_t _info; + uint32_t _info = 0; /// \brief Is this the first section in the output section. - bool _isFirstSectionInOutputSection; + bool _isFirstSectionInOutputSection = false; /// \brief the output ELF segment type of this section. - Layout::SegmentType _segmentType; + typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL; /// \brief Input section name. StringRef _inputSectionName; /// \brief Output section name. @@ -159,65 +148,8 @@ protected: /// \brief A section containing atoms. template <class ELFT> class AtomSection : public Section<ELFT> { public: - AtomSection(const ELFLinkingContext &context, StringRef sectionName, - int32_t contentType, int32_t permissions, int32_t order) - : Section<ELFT>(context, sectionName, "AtomSection", - Chunk<ELFT>::Kind::AtomSection), - _contentType(contentType), _contentPermissions(permissions), - _isLoadedInMemory(true) { - this->setOrder(order); - - switch (contentType) { - case DefinedAtom::typeCode: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - this->_type = SHT_PROGBITS; - break; - - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeZeroFill: - this->_type = SHT_NOBITS; - break; - - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - this->_type = SHT_NOTE; - break; - - case DefinedAtom::typeNoAlloc: - this->_type = SHT_PROGBITS; - this->_isLoadedInMemory = false; - break; - } - - switch (permissions) { - case DefinedAtom::permR__: - this->_flags = SHF_ALLOC; - break; - case DefinedAtom::permR_X: - this->_flags = SHF_ALLOC | SHF_EXECINSTR; - break; - case DefinedAtom::permRW_: - case DefinedAtom::permRW_L: - this->_flags = SHF_ALLOC | SHF_WRITE; - if (_contentType == DefinedAtom::typeThreadData || - _contentType == DefinedAtom::typeThreadZeroFill) - this->_flags |= SHF_TLS; - break; - case DefinedAtom::permRWX: - this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; - break; - case DefinedAtom::perm___: - this->_flags = 0; - break; - } - } + AtomSection(const ELFLinkingContext &ctx, StringRef sectionName, + int32_t contentType, int32_t permissions, int32_t order); /// Align the offset to the required modulus defined by the atom alignment uint64_t alignOffset(uint64_t offset, DefinedAtom::Alignment &atomAlign); @@ -228,40 +160,27 @@ public: // \brief Append an atom to a Section. The atom gets pushed into a vector // contains the atom, the atom file offset, the atom virtual address // the atom file offset is aligned appropriately as set by the Reader - virtual const lld::AtomLayout *appendAtom(const Atom *atom); + virtual const AtomLayout *appendAtom(const Atom *atom); /// \brief Set the virtual address of each Atom in the Section. This /// routine gets called after the linker fixes up the virtual address /// of the section - virtual void assignVirtualAddress(uint64_t addr) override { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_virtualAddr = addr + ai->_fileOffset; - }); - } + void assignVirtualAddress(uint64_t addr) override; /// \brief Set the file offset of each Atom in the section. This routine /// gets called after the linker fixes up the section offset - void assignFileOffsets(uint64_t offset) override { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_fileOffset = offset + ai->_fileOffset; - }); - } + void assignFileOffsets(uint64_t offset) override; /// \brief Find the Atom address given a name, this is needed to properly /// apply relocation. The section class calls this to find the atom address /// to fix the relocation - const AtomLayout *findAtomLayoutByName(StringRef name) const override { - for (auto ai : _atoms) - if (ai->_atom->name() == name) - return ai; - return nullptr; - } + const AtomLayout *findAtomLayoutByName(StringRef name) const override; /// \brief Return the raw flags, we need this to sort segments int64_t atomflags() const { return _contentPermissions; } /// Atom Iterators - typedef typename std::vector<lld::AtomLayout *>::iterator atom_iter; + typedef typename std::vector<AtomLayout *>::iterator atom_iter; range<atom_iter> atoms() { return _atoms; } @@ -276,185 +195,27 @@ protected: llvm::BumpPtrAllocator _alloc; int32_t _contentType; int32_t _contentPermissions; - bool _isLoadedInMemory; - std::vector<lld::AtomLayout *> _atoms; + bool _isLoadedInMemory = true; + std::vector<AtomLayout *> _atoms; mutable std::mutex _outputMutex; - void printError(const std::string &errorStr, const AtomLayout &atom, - const Reference &ref) const { - StringRef kindValStr; - if (!this->_context.registry().referenceKindToString(ref.kindNamespace(), - ref.kindArch(), - ref.kindValue(), - kindValStr)) { - kindValStr = "unknown"; - } - - std::string errStr = (Twine(errorStr) + " in file " + - atom._atom->file().path() + - ": reference from " + atom._atom->name() + - "+" + Twine(ref.offsetInAtom()) + - " to " + ref.target()->name() + - "+" + Twine(ref.addend()) + - " of type " + Twine(ref.kindValue()) + - " (" + kindValStr + ")\n").str(); - - // Take the lock to prevent output getting interleaved between threads - std::lock_guard<std::mutex> lock(_outputMutex); - llvm::errs() << errStr; - } + std::string formatError(const std::string &errorStr, const AtomLayout &atom, + const Reference &ref) const; }; -/// Align the offset to the required modulus defined by the atom alignment -template <class ELFT> -uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset, - DefinedAtom::Alignment &atomAlign) { - uint64_t requiredModulus = atomAlign.modulus; - uint64_t alignment = 1u << atomAlign.powerOf2; - uint64_t currentModulus = (offset % alignment); - uint64_t retOffset = offset; - if (currentModulus != requiredModulus) { - if (requiredModulus > currentModulus) - retOffset += requiredModulus - currentModulus; - else - retOffset += alignment + requiredModulus - currentModulus; - } - return retOffset; -} - -// \brief Append an atom to a Section. The atom gets pushed into a vector -// contains the atom, the atom file offset, the atom virtual address -// the atom file offset is aligned appropriately as set by the Reader -template <class ELFT> -const lld::AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t alignment = 1u << atomAlign.powerOf2; - // Align the atom to the required modulus/ align the file offset and the - // memory offset separately this is required so that BSS symbols are handled - // properly as the BSS symbols only occupy memory size and not file size - uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); - uint64_t mOffset = alignOffset(this->memSize(), atomAlign); - switch(definedAtom->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeConstant: - case DefinedAtom::typeData: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - this->_msize = mOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", - llvm::dbgs() << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - break; - case DefinedAtom::typeNoAlloc: - _atoms.push_back(new (_alloc) lld::AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() << "[" << this->name() << " " - << this << "] " - << "Adding atom: " << atom->name() - << "@" << fOffset << "\n"); - break; - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFill: - _atoms.push_back(new (_alloc) lld::AtomLayout(atom, mOffset, 0)); - this->_msize = mOffset + definedAtom->size(); - break; - default: - llvm::dbgs() << definedAtom->contentType() << "\n"; - llvm_unreachable("Uexpected content type."); - } - // Set the section alignment to the largest alignment - // std::max doesn't support uint64_t - if (this->_alignment < alignment) - this->_alignment = alignment; - - if (_atoms.size()) - return _atoms.back(); - return nullptr; -} - -/// \brief convert the segment type to a String for diagnostics -/// and printing purposes -template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const { - switch(_segmentType) { - case llvm::ELF::PT_DYNAMIC: - return "DYNAMIC"; - case llvm::ELF::PT_INTERP: - return "INTERP"; - case llvm::ELF::PT_LOAD: - return "LOAD"; - case llvm::ELF::PT_GNU_EH_FRAME: - return "EH_FRAME"; - case llvm::ELF::PT_GNU_RELRO: - return "GNU_RELRO"; - case llvm::ELF::PT_NOTE: - return "NOTE"; - case llvm::ELF::PT_NULL: - return "NULL"; - case llvm::ELF::PT_TLS: - return "TLS"; - default: - return "UNKNOWN"; - } -} - -/// \brief Write the section and the atom contents to the buffer -template <class ELFT> -void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - bool success = true; - parallel_for_each(_atoms.begin(), _atoms.end(), [&](lld::AtomLayout * ai) { - DEBUG_WITH_TYPE("Section", - llvm::dbgs() << "Writing atom: " << ai->_atom->name() - << " | " << ai->_fileOffset << "\n"); - const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom); - if (!definedAtom->occupiesDiskSpace()) - return; - // Copy raw content of atom to file buffer. - ArrayRef<uint8_t> content = definedAtom->rawContent(); - uint64_t contentSize = content.size(); - if (contentSize == 0) - return; - uint8_t *atomContent = chunkBuffer + ai->_fileOffset; - std::memcpy(atomContent, content.data(), contentSize); - const TargetRelocationHandler &relHandler = - this->_context.template getTargetHandler<ELFT>().getRelocationHandler(); - for (const auto ref : *definedAtom) { - if (std::error_code ec = relHandler.applyRelocation(*writer, buffer, - *ai, *ref)) { - printError(ec.message(), *ai, *ref); - success = false; - } - } - }); - if (!success) - llvm::report_fatal_error("relocating output"); -} - /// \brief A OutputSection represents a set of sections grouped by the same /// name. The output file that gets written by the linker has sections grouped /// by similar names template <class ELFT> class OutputSection { public: // Iterators - typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter; + typedef typename std::vector<Section<ELFT> *>::iterator SectionIter; - OutputSection(StringRef name); + OutputSection(StringRef name) : _name(name) {} // Appends a section into the list of sections that are part of this Output // Section - void appendSection(Chunk<ELFT> *c); + void appendSection(Section<ELFT> *c); // Set the OutputSection is associated with a segment void setHasSegment() { _hasSegment = true; } @@ -484,90 +245,48 @@ public: } void setLink(uint64_t link) { _link = link; } - void setInfo(uint64_t info) { _shInfo = info; } - void setFlag(uint64_t flags) { _flags = flags; } - - void setType(int16_t type) { _type = type; } - - range<ChunkIter> sections() { return _sections; } + void setType(int64_t type) { _type = type; } + range<SectionIter> sections() { return _sections; } // The below functions returns the properties of the OutputSection. bool hasSegment() const { return _hasSegment; } - StringRef name() const { return _name; } - int64_t shinfo() const { return _shInfo; } - uint64_t alignment() const { return _alignment; } - int64_t link() const { return _link; } - int64_t type() const { return _type; } - uint64_t virtualAddr() const { return _virtualAddr; } - int64_t ordinal() const { return _ordinal; } - int64_t kind() const { return _kind; } - uint64_t fileSize() const { return _size; } - int64_t entsize() const { return _entSize; } - uint64_t fileOffset() const { return _fileOffset; } - - int64_t flags() const { return _flags; } - - uint64_t memSize() { return _memSize; } + uint64_t flags() const { return _flags; } + uint64_t memSize() const { return _memSize; } private: StringRef _name; - bool _hasSegment; - uint64_t _ordinal; - uint64_t _flags; - uint64_t _size; - uint64_t _memSize; - uint64_t _fileOffset; - uint64_t _virtualAddr; - int64_t _shInfo; - int64_t _entSize; - int64_t _link; - uint64_t _alignment; - int64_t _kind; - int64_t _type; - bool _isLoadableSection; - std::vector<Chunk<ELFT> *> _sections; + bool _hasSegment = false; + uint64_t _ordinal = 0; + uint64_t _flags = 0; + uint64_t _size = 0; + uint64_t _memSize = 0; + uint64_t _fileOffset = 0; + uint64_t _virtualAddr = 0; + int64_t _shInfo = 0; + int64_t _entSize = 0; + int64_t _link = 0; + uint64_t _alignment = 1; + int64_t _kind = 0; + int64_t _type = 0; + bool _isLoadableSection = false; + std::vector<Section<ELFT> *> _sections; }; -/// OutputSection -template <class ELFT> -OutputSection<ELFT>::OutputSection(StringRef name) - : _name(name), _hasSegment(false), _ordinal(0), _flags(0), _size(0), - _memSize(0), _fileOffset(0), _virtualAddr(0), _shInfo(0), _entSize(0), - _link(0), _alignment(0), _kind(0), _type(0), _isLoadableSection(false) {} - -template <class ELFT> void OutputSection<ELFT>::appendSection(Chunk<ELFT> *c) { - if (c->alignment() > _alignment) - _alignment = c->alignment(); - if (const auto section = dyn_cast<Section<ELFT>>(c)) { - assert(!_link && "Section already has a link!"); - _link = section->getLink(); - _shInfo = section->getInfo(); - _entSize = section->getEntSize(); - _type = section->getType(); - if (_flags < section->getFlags()) - _flags = section->getFlags(); - section->setOutputSection(this, (_sections.size() == 0)); - } - _kind = c->kind(); - _sections.push_back(c); -} - /// \brief The class represents the ELF String Table -template<class ELFT> -class StringTable : public Section<ELFT> { +template <class ELFT> class StringTable : public Section<ELFT> { public: StringTable(const ELFLinkingContext &, const char *str, int32_t order, bool dynamic = false); @@ -592,68 +311,21 @@ private: return lhs.equals(rhs); } }; - typedef typename llvm::DenseMap<StringRef, uint64_t, - StringRefMappingInfo> StringMapT; + typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo> + StringMapT; typedef typename StringMapT::iterator StringMapTIter; StringMapT _stringMap; }; -template <class ELFT> -StringTable<ELFT>::StringTable(const ELFLinkingContext &context, - const char *str, int32_t order, bool dynamic) - : Section<ELFT>(context, str, "StringTable") { - // the string table has a NULL entry for which - // add an empty string - _strings.push_back(""); - this->_fsize = 1; - this->_alignment = 1; - this->setOrder(order); - this->_type = SHT_STRTAB; - if (dynamic) { - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; - } -} - -template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) { - if (symname.empty()) - return 0; - StringMapTIter stringIter = _stringMap.find(symname); - if (stringIter == _stringMap.end()) { - _strings.push_back(symname); - uint64_t offset = this->_fsize; - this->_fsize += symname.size() + 1; - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; - _stringMap[symname] = offset; - return offset; - } - return stringIter->second; -} - -template <class ELFT> -void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto si : _strings) { - memcpy(dest, si.data(), si.size()); - dest += si.size(); - memcpy(dest, "", 1); - dest += 1; - } -} - /// \brief The SymbolTable class represents the symbol table in a ELF file -template<class ELFT> -class SymbolTable : public Section<ELFT> { - typedef typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr - Elf_Addr; +template <class ELFT> class SymbolTable : public Section<ELFT> { + typedef + typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Addr Elf_Addr; public: typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - SymbolTable(const ELFLinkingContext &context, const char *str, int32_t order); + SymbolTable(const ELFLinkingContext &ctx, const char *str, int32_t order); /// \brief set the number of entries that would exist in the symbol /// table for the current link @@ -666,7 +338,7 @@ public: std::size_t size() const { return _symbolTable.size(); } void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0, - const lld::AtomLayout *layout = nullptr); + const AtomLayout *layout = nullptr); /// \brief Get the symbol table index for an Atom. If it's not in the symbol /// table, return STN_UNDEF. @@ -681,9 +353,9 @@ public: virtual void sortSymbols() { std::stable_sort(_symbolTable.begin(), _symbolTable.end(), - [](const SymbolEntry & A, const SymbolEntry & B) { - return A._symbol.getBinding() < B._symbol.getBinding(); - }); + [](const SymbolEntry &A, const SymbolEntry &B) { + return A._symbol.getBinding() < B._symbol.getBinding(); + }); } virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, @@ -707,12 +379,11 @@ public: protected: struct SymbolEntry { - SymbolEntry(const Atom *a, const Elf_Sym &sym, - const lld::AtomLayout *layout) + SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout) : _atom(a), _atomLayout(layout), _symbol(sym) {} const Atom *_atom; - const lld::AtomLayout *_atomLayout; + const AtomLayout *_atomLayout; Elf_Sym _symbol; }; @@ -721,233 +392,23 @@ protected: std::vector<SymbolEntry> _symbolTable; }; -/// ELF Symbol Table -template <class ELFT> -SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &context, - const char *str, int32_t order) - : Section<ELFT>(context, str, "SymbolTable") { - this->setOrder(order); - Elf_Sym symbol; - std::memset(&symbol, 0, sizeof(Elf_Sym)); - _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr)); - this->_entSize = sizeof(Elf_Sym); - this->_fsize = sizeof(Elf_Sym); - this->_alignment = sizeof(Elf_Addr); - this->_type = SHT_SYMTAB; -} - -template <class ELFT> -void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - unsigned char binding = 0, type = 0; - sym.st_size = da->size(); - DefinedAtom::ContentType ct; - switch (ct = da->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeStub: - sym.st_value = addr; - type = llvm::ELF::STT_FUNC; - break; - case DefinedAtom::typeResolver: - sym.st_value = addr; - type = llvm::ELF::STT_GNU_IFUNC; - break; - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - sym.st_value = addr; - type = llvm::ELF::STT_OBJECT; - break; - case DefinedAtom::typeGOT: - sym.st_value = addr; - type = llvm::ELF::STT_NOTYPE; - break; - case DefinedAtom::typeZeroFill: - case DefinedAtom::typeZeroFillFast: - type = llvm::ELF::STT_OBJECT; - sym.st_value = addr; - break; - case DefinedAtom::typeThreadData: - case DefinedAtom::typeThreadZeroFill: - type = llvm::ELF::STT_TLS; - sym.st_value = addr; - break; - default: - type = llvm::ELF::STT_NOTYPE; - } - if (da->customSectionName() == da->name()) - type = llvm::ELF::STT_SECTION; - - if (da->scope() == DefinedAtom::scopeTranslationUnit) - binding = llvm::ELF::STB_LOCAL; - else - binding = llvm::ELF::STB_GLOBAL; - - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, - int64_t addr) { - unsigned char binding = 0, type = 0; - type = llvm::ELF::STT_OBJECT; - sym.st_shndx = llvm::ELF::SHN_ABS; - switch (aa->scope()) { - case AbsoluteAtom::scopeLinkageUnit: - sym.setVisibility(llvm::ELF::STV_HIDDEN); - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeTranslationUnit: - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeGlobal: - binding = llvm::ELF::STB_GLOBAL; - break; - } - sym.st_value = addr; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym, - const SharedLibraryAtom *aa) { - unsigned char binding = 0, type = 0; - if (aa->type() == SharedLibraryAtom::Type::Data) { - type = llvm::ELF::STT_OBJECT; - sym.st_size = aa->size(); - } else - type = llvm::ELF::STT_FUNC; - sym.st_shndx = llvm::ELF::SHN_UNDEF; - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym, - const UndefinedAtom *ua) { - unsigned char binding = 0, type = 0; - sym.st_value = 0; - type = llvm::ELF::STT_NOTYPE; - if (ua->canBeNull()) - binding = llvm::ELF::STB_WEAK; - else - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol -/// section don't have their virtual addresses set at the time of adding the -/// symbol to the symbol table(Example: dynamic symbols), the addresses needs -/// to be updated in the table before writing the dynamic symbol table -/// information -template <class ELFT> -void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex, - uint64_t addr, - const lld::AtomLayout *atomLayout) { - Elf_Sym symbol; - - if (atom->name().empty()) - return; - - symbol.st_name = _stringSection->addString(atom->name()); - symbol.st_size = 0; - symbol.st_shndx = sectionIndex; - symbol.st_value = 0; - symbol.st_other = 0; - symbol.setVisibility(llvm::ELF::STV_DEFAULT); - - // Add all the atoms - if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom)) - addDefinedAtom(symbol, da, addr); - else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)) - addAbsoluteAtom(symbol, aa, addr); - else if (isa<const SharedLibraryAtom>(atom)) - addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom)); - else - addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom)); - - _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout)); - this->_fsize += sizeof(Elf_Sym); - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; -} - -template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) { - // sh_info should be one greater than last symbol with STB_LOCAL binding - // we sort the symbol table to keep all local symbols at the beginning - if (sort) - sortSymbols(); - - uint16_t shInfo = 0; - for (const auto &i : _symbolTable) { - if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL) - break; - shInfo++; - } - this->_info = shInfo; - this->_link = _stringSection->ordinal(); - if (this->_outputSection) { - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } -} - -template <class ELFT> -void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &sti : _symbolTable) { - memcpy(dest, &sti._symbol, sizeof(Elf_Sym)); - dest += sizeof(Elf_Sym); - } -} - template <class ELFT> class HashSection; template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> { public: - DynamicSymbolTable(const ELFLinkingContext &context, - TargetLayout<ELFT> &layout, const char *str, int32_t order) - : SymbolTable<ELFT>(context, str, order), _hashTable(nullptr), - _layout(layout) { - this->_type = SHT_DYNSYM; - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; - } + DynamicSymbolTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout, + const char *str, int32_t order); // Set the dynamic hash table for symbols to be added into void setHashTable(HashSection<ELFT> *hashTable) { _hashTable = hashTable; } // Add all the dynamic symbos to the hash table - void addSymbolsToHashTable() { - int index = 0; - for (auto &ste : this->_symbolTable) { - if (!ste._atom) - _hashTable->addSymbol("", index); - else - _hashTable->addSymbol(ste._atom->name(), index); - ++index; - } - } + void addSymbolsToHashTable(); - void finalize() override { - // Defined symbols which have been added into the dynamic symbol table - // don't have their addresses known until addresses have been assigned - // so let's update the symbol values after they have got assigned - for (auto &ste: this->_symbolTable) { - const lld::AtomLayout *atomLayout = ste._atomLayout; - if (!atomLayout) - continue; - ste._symbol.st_value = atomLayout->_virtualAddr; - } - - // Don't sort the symbols - SymbolTable<ELFT>::finalize(false); - } + void finalize() override; protected: - HashSection<ELFT> *_hashTable; + HashSection<ELFT> *_hashTable = nullptr; TargetLayout<ELFT> &_layout; }; @@ -956,118 +417,36 @@ public: typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; - RelocationTable(const ELFLinkingContext &context, StringRef str, - int32_t order) - : Section<ELFT>(context, str, "RelocationTable"), _symbolTable(nullptr) { - this->setOrder(order); - this->_flags = SHF_ALLOC; - // Set the alignment properly depending on the target architecture - this->_alignment = ELFT::Is64Bits ? 8 : 4; - if (context.isRelaOutputFormat()) { - this->_entSize = sizeof(Elf_Rela); - this->_type = SHT_RELA; - } else { - this->_entSize = sizeof(Elf_Rel); - this->_type = SHT_REL; - } - } + RelocationTable(const ELFLinkingContext &ctx, StringRef str, int32_t order); /// \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() * this->_entSize; - this->_msize = this->_fsize; - return _relocs.size() - 1; - } + uint32_t addRelocation(const DefinedAtom &da, const Reference &r); - 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; - } + bool getRelocationIndex(const Reference &r, uint32_t &res); void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) { _symbolTable = symbolTable; } /// \brief Check if any relocation modifies a read-only section. - bool canModifyReadonlySection() const { - for (const auto &rel : _relocs) { - const DefinedAtom *atom = rel.first; - if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_) - return true; - } - return false; - } + bool canModifyReadonlySection() const; - void finalize() override { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); - } + void finalize() override; void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &rel : _relocs) { - if (this->_context.isRelaOutputFormat()) { - auto &r = *reinterpret_cast<Elf_Rela *>(dest); - writeRela(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() - << rel.second->kindValue() << " relocation at " - << rel.first->name() << "@" << r.r_offset << " to " - << rel.second->target()->name() << "@" << r.r_addend - << "\n";); - } else { - auto &r = *reinterpret_cast<Elf_Rel *>(dest); - writeRel(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() << rel.second->kindValue() - << " relocation at " << rel.first->name() - << "@" << r.r_offset << " to " - << rel.second->target()->name() << "\n";); - } - dest += this->_entSize; - } - } + llvm::FileOutputBuffer &buffer) override; protected: - const DynamicSymbolTable<ELFT> *_symbolTable; + const DynamicSymbolTable<ELFT> *_symbolTable = nullptr; virtual void writeRela(ELFWriter *writer, Elf_Rela &r, - const DefinedAtom &atom, const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); - // The addend is used only by relative relocations - if (this->_context.isRelativeReloc(ref)) - r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend(); - else - r.r_addend = 0; - } - + const DefinedAtom &atom, const Reference &ref); virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom, - const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); - } - - uint32_t getSymbolIndex(const Atom *a) { - return _symbolTable ? _symbolTable->getSymbolTableIndex(a) - : (uint32_t)STN_UNDEF; - } + const Reference &ref); + uint32_t getSymbolIndex(const Atom *a); private: - std::vector<std::pair<const DefinedAtom *, const Reference *> > _relocs; + std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs; }; template <class ELFT> class HashSection; @@ -1077,125 +456,25 @@ public: typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn; typedef std::vector<Elf_Dyn> EntriesT; - DynamicTable(const ELFLinkingContext &context, TargetLayout<ELFT> &layout, - StringRef str, int32_t order) - : Section<ELFT>(context, str, "DynamicSection"), _layout(layout) { - this->setOrder(order); - this->_entSize = sizeof(Elf_Dyn); - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Reserve space for the DT_NULL entry. - this->_fsize = sizeof(Elf_Dyn); - this->_msize = sizeof(Elf_Dyn); - this->_type = SHT_DYNAMIC; - this->_flags = SHF_ALLOC; - } + DynamicTable(const ELFLinkingContext &ctx, TargetLayout<ELFT> &layout, + StringRef str, int32_t order); range<typename EntriesT::iterator> entries() { return _entries; } /// \returns the index of the entry. - std::size_t addEntry(Elf_Dyn e) { - _entries.push_back(e); - this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn); - this->_msize = this->_fsize; - return _entries.size() - 1; - } + std::size_t addEntry(int64_t tag, uint64_t val); void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - // Add the null entry. - Elf_Dyn d; - d.d_tag = 0; - d.d_un.d_val = 0; - _entries.push_back(d); - std::memcpy(dest, _entries.data(), this->_fsize); - } - - virtual void createDefaultEntries() { - bool isRela = this->_context.isRelaOutputFormat(); - - Elf_Dyn dyn; - dyn.d_un.d_val = 0; - - dyn.d_tag = DT_HASH; - _dt_hash = addEntry(dyn); - dyn.d_tag = DT_STRTAB; - _dt_strtab = addEntry(dyn); - dyn.d_tag = DT_SYMTAB; - _dt_symtab = addEntry(dyn); - dyn.d_tag = DT_STRSZ; - _dt_strsz = addEntry(dyn); - dyn.d_tag = DT_SYMENT; - _dt_syment = addEntry(dyn); - if (_layout.hasDynamicRelocationTable()) { - dyn.d_tag = isRela ? DT_RELA : DT_REL; - _dt_rela = addEntry(dyn); - dyn.d_tag = isRela ? DT_RELASZ : DT_RELSZ; - _dt_relasz = addEntry(dyn); - dyn.d_tag = isRela ? DT_RELAENT : DT_RELENT; - _dt_relaent = addEntry(dyn); - - if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) { - dyn.d_tag = DT_TEXTREL; - _dt_textrel = addEntry(dyn); - } - } - if (_layout.hasPLTRelocationTable()) { - dyn.d_tag = DT_PLTRELSZ; - _dt_pltrelsz = addEntry(dyn); - dyn.d_tag = getGotPltTag(); - _dt_pltgot = addEntry(dyn); - dyn.d_tag = DT_PLTREL; - dyn.d_un.d_val = isRela ? DT_RELA : DT_REL; - _dt_pltrel = addEntry(dyn); - dyn.d_un.d_val = 0; - dyn.d_tag = DT_JMPREL; - _dt_jmprel = addEntry(dyn); - } - } + llvm::FileOutputBuffer &buffer) override; - void doPreFlight() override { - Elf_Dyn dyn; - dyn.d_un.d_val = 0; - auto initArray = _layout.findOutputSection(".init_array"); - auto finiArray = _layout.findOutputSection(".fini_array"); - if (initArray) { - dyn.d_tag = DT_INIT_ARRAY; - _dt_init_array = addEntry(dyn); - dyn.d_tag = DT_INIT_ARRAYSZ; - _dt_init_arraysz = addEntry(dyn); - } - if (finiArray) { - dyn.d_tag = DT_FINI_ARRAY; - _dt_fini_array = addEntry(dyn); - dyn.d_tag = DT_FINI_ARRAYSZ; - _dt_fini_arraysz = addEntry(dyn); - } - if (getInitAtomLayout()) { - dyn.d_tag = DT_INIT; - _dt_init = addEntry(dyn); - } - if (getFiniAtomLayout()) { - dyn.d_tag = DT_FINI; - _dt_fini = addEntry(dyn); - } - } + virtual void createDefaultEntries(); + void doPreFlight() override; /// \brief Dynamic table tag for .got.plt section referencing. /// Usually but not always targets use DT_PLTGOT for that. virtual int64_t getGotPltTag() { return DT_PLTGOT; } - void finalize() override { - StringTable<ELFT> *dynamicStringTable = - _dynamicSymbolTable->getStringTable(); - this->_link = dynamicStringTable->ordinal(); - if (this->_outputSection) { - this->_outputSection->setType(this->_type); - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } - } + void finalize() override; void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) { _dynamicSymbolTable = dynsym; @@ -1207,42 +486,7 @@ public: void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; } - virtual void updateDynamicTable() { - StringTable<ELFT> *dynamicStringTable = - _dynamicSymbolTable->getStringTable(); - _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr(); - _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr(); - _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr(); - _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize(); - _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize(); - auto initArray = _layout.findOutputSection(".init_array"); - if (initArray) { - _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr(); - _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize(); - } - auto finiArray = _layout.findOutputSection(".fini_array"); - if (finiArray) { - _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr(); - _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize(); - } - if (const auto *al = getInitAtomLayout()) - _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al); - if (const auto *al = getFiniAtomLayout()) - _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al); - if (_layout.hasDynamicRelocationTable()) { - auto relaTbl = _layout.getDynamicRelocationTable(); - _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_relasz].d_un.d_val = relaTbl->memSize(); - _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize(); - } - if (_layout.hasPLTRelocationTable()) { - auto relaTbl = _layout.getPLTRelocationTable(); - _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize(); - auto gotplt = _layout.findOutputSection(".got.plt"); - _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr(); - } - } + virtual void updateDynamicTable(); protected: EntriesT _entries; @@ -1279,41 +523,18 @@ private: DynamicSymbolTable<ELFT> *_dynamicSymbolTable; HashSection<ELFT> *_hashTable; - const AtomLayout *getInitAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_context.initFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; - } + const AtomLayout *getInitAtomLayout(); - const AtomLayout *getFiniAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_context.finiFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; - } + const AtomLayout *getFiniAtomLayout(); }; template <class ELFT> class InterpSection : public Section<ELFT> { public: - InterpSection(const ELFLinkingContext &context, StringRef str, int32_t order, - StringRef interp) - : Section<ELFT>(context, str, "Dynamic:Interp"), _interp(interp) { - this->setOrder(order); - this->_alignment = 1; - // + 1 for null term. - this->_fsize = interp.size() + 1; - this->_msize = this->_fsize; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; - } + InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order, + StringRef interp); void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - std::memcpy(dest, _interp.data(), _interp.size()); - } + llvm::FileOutputBuffer &buffer) override; private: StringRef _interp; @@ -1338,7 +559,6 @@ private: /// * Take the value from the buckets[hash % nbuckets] as the index of symbol /// * Compare the symbol's name, if true return, if false, look through the /// * array since there was a collision - template <class ELFT> class HashSection : public Section<ELFT> { struct SymbolTableEntry { StringRef _name; @@ -1346,153 +566,51 @@ template <class ELFT> class HashSection : public Section<ELFT> { }; public: - HashSection(const ELFLinkingContext &context, StringRef name, int32_t order) - : Section<ELFT>(context, name, "Dynamic:Hash"), _symbolTable(nullptr) { - this->setOrder(order); - this->_entSize = 4; - this->_type = SHT_HASH; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - this->_fsize = 0; - this->_msize = 0; - } + HashSection(const ELFLinkingContext &ctx, StringRef name, int32_t order); /// \brief add the dynamic symbol into the table so that the /// hash could be calculated - void addSymbol(StringRef name, uint32_t index) { - SymbolTableEntry ste; - ste._name = name; - ste._index = index; - _entries.push_back(ste); - } + void addSymbol(StringRef name, uint32_t index); /// \brief Set the dynamic symbol table - void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable) { - _symbolTable = symbolTable; - } + void setSymbolTable(const DynamicSymbolTable<ELFT> *symbolTable); // The size of the section has to be determined so that fileoffsets // may be properly assigned. Let's calculate the buckets and the chains // and fill the chains and the buckets hash table used by the dynamic // linker and update the filesize and memory size accordingly - void doPreFlight() override { - // The number of buckets to use for a certain number of symbols. - // If there are less than 3 symbols, 1 bucket will be used. If - // there are less than 17 symbols, 3 buckets will be used, and so - // forth. The bucket numbers are defined by GNU ld. We use the - // same rules here so we generate hash sections with the same - // size as those generated by GNU ld. - uint32_t hashBuckets[] = { 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, - 2053, 4099, 8209, 16411, 32771, 65537, 131101, - 262147 }; - int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t); - - unsigned int bucketsCount = 0; - unsigned int dynSymCount = _entries.size(); - - // Get the number of buckes that we want to use - for (int i = 0; i < hashBucketsCount; ++i) { - if (dynSymCount < hashBuckets[i]) - break; - bucketsCount = hashBuckets[i]; - } - _buckets.resize(bucketsCount); - _chains.resize(_entries.size()); - - // Create the hash table for the dynamic linker - for (auto ai : _entries) { - unsigned int dynsymIndex = ai._index; - unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount; - _chains[dynsymIndex] = _buckets[bucketpos]; - _buckets[bucketpos] = dynsymIndex; - } + void doPreFlight() override; - this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t); - this->_msize = this->_fsize; - } - - void finalize() override { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); - } + void finalize() override; void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - uint32_t bucketChainCounts[2]; - bucketChainCounts[0] = _buckets.size(); - bucketChainCounts[1] = _chains.size(); - std::memcpy(dest, (char *)bucketChainCounts, sizeof(bucketChainCounts)); - dest += sizeof(bucketChainCounts); - // write bucket values - for (auto bi : _buckets) { - uint32_t val = (bi); - std::memcpy(dest, &val, sizeof(uint32_t)); - dest += sizeof(uint32_t); - } - // write chain values - for (auto ci : _chains) { - uint32_t val = (ci); - std::memcpy(dest, &val, sizeof(uint32_t)); - dest += sizeof(uint32_t); - } - } + llvm::FileOutputBuffer &buffer) override; private: + typedef + typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word; + std::vector<SymbolTableEntry> _entries; - std::vector<uint32_t> _buckets; - std::vector<uint32_t> _chains; - const DynamicSymbolTable<ELFT> *_symbolTable; + std::vector<Elf_Word> _buckets; + std::vector<Elf_Word> _chains; + const DynamicSymbolTable<ELFT> *_symbolTable = nullptr; }; template <class ELFT> class EHFrameHeader : public Section<ELFT> { public: - EHFrameHeader(const ELFLinkingContext &context, StringRef name, - TargetLayout<ELFT> &layout, int32_t order) - : Section<ELFT>(context, name, "EHFrameHeader"), _ehFrameOffset(0), - _layout(layout) { - this->setOrder(order); - this->_entSize = 0; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Minimum size for empty .eh_frame_hdr. - this->_fsize = 1 + 1 + 1 + 1 + 4; - this->_msize = this->_fsize; - } - - void doPreFlight() override { - // TODO: Generate a proper binary search table. - } - - void finalize() override { - OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame"); - OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr"); - if (s && h) - _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4); - } - + EHFrameHeader(const ELFLinkingContext &ctx, StringRef name, + TargetLayout<ELFT> &layout, int32_t order); + void doPreFlight() override; + void finalize() override; void write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) override { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - int pos = 0; - dest[pos++] = 1; // version - dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel | - llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc - *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>( - dest + pos) = _ehFrameOffset; - } + llvm::FileOutputBuffer &buffer) override; private: - int32_t _ehFrameOffset; + int32_t _ehFrameOffset = 0; TargetLayout<ELFT> &_layout; }; + } // end namespace elf } // end namespace lld -#endif +#endif // LLD_READER_WRITER_ELF_SECTION_CHUNKS_H |