| //===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLD_READER_WRITER_ELF_SECTION_CHUNKS_H |
| #define LLD_READER_WRITER_ELF_SECTION_CHUNKS_H |
| |
| #include "Chunk.h" |
| #include "TargetHandler.h" |
| #include "Writer.h" |
| #include "lld/Core/DefinedAtom.h" |
| #include "lld/Core/range.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/ELF.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/FileOutputBuffer.h" |
| #include <memory> |
| #include <mutex> |
| |
| namespace lld { |
| 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 &ctx, StringRef sectionName, |
| StringRef chunkName, |
| typename Chunk<ELFT>::Kind k = Chunk<ELFT>::Kind::ELFSection); |
| |
| /// \brief Modify the section contents before assigning virtual addresses |
| // or assigning file offsets |
| |
| /// \brief Finalize the section contents before writing |
| |
| /// \brief Does this section have an output segment. |
| virtual bool hasOutputSegment() const { return false; } |
| |
| /// Return if the section is a loadable section that occupies memory |
| virtual bool isLoadableSection() const { return false; } |
| |
| /// \brief Assign file offsets starting at offset. |
| virtual void assignFileOffsets(uint64_t offset) {} |
| |
| /// \brief Assign virtual addresses starting at addr. |
| virtual void assignVirtualAddress(uint64_t addr) {} |
| |
| uint64_t getFlags() const { return _flags; } |
| uint64_t getEntSize() const { return _entSize; } |
| uint32_t getType() const { return _type; } |
| uint32_t getLink() const { return _link; } |
| uint32_t getInfo() const { return _info; } |
| |
| 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 |
| virtual StringRef segmentKindToStr() const; |
| |
| /// \brief Records the segmentType, that this section belongs to |
| void |
| setSegmentType(const typename TargetLayout<ELFT>::SegmentType segmentType) { |
| this->_segmentType = segmentType; |
| } |
| |
| virtual const AtomLayout *findAtomLayoutByName(StringRef) const { |
| return nullptr; |
| } |
| |
| const OutputSection<ELFT> *getOutputSection() const { |
| return _outputSection; |
| } |
| |
| void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) { |
| _outputSection = os; |
| _isFirstSectionInOutputSection = isFirst; |
| } |
| |
| static bool classof(const Chunk<ELFT> *c) { |
| return c->kind() == Chunk<ELFT>::Kind::ELFSection || |
| c->kind() == Chunk<ELFT>::Kind::AtomSection; |
| } |
| |
| uint64_t alignment() const override { |
| return _isFirstSectionInOutputSection ? _outputSection->alignment() |
| : this->_alignment; |
| } |
| |
| virtual StringRef inputSectionName() const { return _inputSectionName; } |
| |
| virtual StringRef outputSectionName() const { return _outputSectionName; } |
| |
| virtual void setOutputSectionName(StringRef outputSectionName) { |
| _outputSectionName = outputSectionName; |
| } |
| |
| void setArchiveNameOrPath(StringRef name) { _archivePath = name; } |
| |
| void setMemberNameOrPath(StringRef name) { _memberPath = name; } |
| |
| StringRef archivePath() { return _archivePath; } |
| |
| StringRef memberPath() { return _memberPath; } |
| |
| protected: |
| /// \brief OutputSection this Section is a member of, or nullptr. |
| OutputSection<ELFT> *_outputSection = nullptr; |
| /// \brief ELF SHF_* flags. |
| uint64_t _flags = 0; |
| /// \brief The size of each entity. |
| uint64_t _entSize = 0; |
| /// \brief ELF SHT_* type. |
| uint32_t _type = 0; |
| /// \brief sh_link field. |
| uint32_t _link = 0; |
| /// \brief the sh_info field. |
| uint32_t _info = 0; |
| /// \brief Is this the first section in the output section. |
| bool _isFirstSectionInOutputSection = false; |
| /// \brief the output ELF segment type of this section. |
| typename TargetLayout<ELFT>::SegmentType _segmentType = SHT_NULL; |
| /// \brief Input section name. |
| StringRef _inputSectionName; |
| /// \brief Output section name. |
| StringRef _outputSectionName; |
| StringRef _archivePath; |
| StringRef _memberPath; |
| }; |
| |
| /// \brief A section containing atoms. |
| template <class ELFT> class AtomSection : public Section<ELFT> { |
| public: |
| 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); |
| |
| /// Return if the section is a loadable section that occupies memory |
| bool isLoadableSection() const override { return _isLoadedInMemory; } |
| |
| // \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 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 |
| 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; |
| |
| /// \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; |
| |
| /// \brief Return the raw flags, we need this to sort segments |
| int64_t atomflags() const { return _contentPermissions; } |
| |
| /// Atom Iterators |
| typedef typename std::vector<AtomLayout *>::iterator atom_iter; |
| |
| range<atom_iter> atoms() { return _atoms; } |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| static bool classof(const Chunk<ELFT> *c) { |
| return c->kind() == Chunk<ELFT>::Kind::AtomSection; |
| } |
| |
| protected: |
| llvm::BumpPtrAllocator _alloc; |
| int32_t _contentType; |
| int32_t _contentPermissions; |
| bool _isLoadedInMemory = true; |
| std::vector<AtomLayout *> _atoms; |
| mutable std::mutex _outputMutex; |
| |
| std::string formatError(const std::string &errorStr, const AtomLayout &atom, |
| const Reference &ref) const; |
| }; |
| |
| /// \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<Section<ELFT> *>::iterator SectionIter; |
| |
| OutputSection(StringRef name) : _name(name) {} |
| |
| // Appends a section into the list of sections that are part of this Output |
| // Section |
| void appendSection(Section<ELFT> *c); |
| |
| // Set the OutputSection is associated with a segment |
| void setHasSegment() { _hasSegment = true; } |
| |
| /// Sets the ordinal |
| void setOrdinal(uint64_t ordinal) { _ordinal = ordinal; } |
| |
| /// Sets the Memory size |
| void setMemSize(uint64_t memsz) { _memSize = memsz; } |
| |
| /// Sets the size fo the output Section. |
| void setSize(uint64_t fsiz) { _size = fsiz; } |
| |
| // The offset of the first section contained in the output section is |
| // contained here. |
| void setFileOffset(uint64_t foffset) { _fileOffset = foffset; } |
| |
| // Sets the starting address of the section |
| void setAddr(uint64_t addr) { _virtualAddr = addr; } |
| |
| // Is the section loadable? |
| bool isLoadableSection() const { return _isLoadableSection; } |
| |
| // Set section Loadable |
| void setLoadableSection(bool isLoadable) { |
| _isLoadableSection = isLoadable; |
| } |
| |
| void setLink(uint64_t link) { _link = link; } |
| void setInfo(uint64_t info) { _shInfo = info; } |
| void setFlag(uint64_t flags) { _flags = flags; } |
| 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; } |
| uint64_t flags() const { return _flags; } |
| uint64_t memSize() const { return _memSize; } |
| |
| private: |
| StringRef _name; |
| 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; |
| }; |
| |
| /// \brief The class represents the ELF String Table |
| template <class ELFT> class StringTable : public Section<ELFT> { |
| public: |
| StringTable(const ELFLinkingContext &, const char *str, int32_t order, |
| bool dynamic = false); |
| |
| uint64_t addString(StringRef symname); |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); } |
| |
| private: |
| std::vector<StringRef> _strings; |
| |
| struct StringRefMappingInfo { |
| static StringRef getEmptyKey() { return StringRef(); } |
| static StringRef getTombstoneKey() { return StringRef(" ", 1); } |
| static unsigned getHashValue(StringRef const val) { |
| return llvm::HashString(val); |
| } |
| static bool isEqual(StringRef const lhs, StringRef const rhs) { |
| return lhs.equals(rhs); |
| } |
| }; |
| typedef typename llvm::DenseMap<StringRef, uint64_t, StringRefMappingInfo> |
| StringMapT; |
| typedef typename StringMapT::iterator StringMapTIter; |
| StringMapT _stringMap; |
| }; |
| |
| /// \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; |
| |
| public: |
| typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; |
| |
| 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 |
| void setNumEntries(int64_t numEntries) const { |
| if (_stringSection) |
| _stringSection->setNumEntries(numEntries); |
| } |
| |
| /// \brief return number of entries |
| std::size_t size() const { return _symbolTable.size(); } |
| |
| void addSymbol(const Atom *atom, int32_t sectionIndex, uint64_t addr = 0, |
| const AtomLayout *layout = nullptr); |
| |
| /// \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 { |
| for (size_t i = 0, e = _symbolTable.size(); i < e; ++i) |
| if (_symbolTable[i]._atom == a) |
| return i; |
| return STN_UNDEF; |
| } |
| |
| void finalize() override { finalize(true); } |
| |
| virtual void sortSymbols() { |
| std::stable_sort(_symbolTable.begin(), _symbolTable.end(), |
| [](const SymbolEntry &A, const SymbolEntry &B) { |
| return A._symbol.getBinding() < B._symbol.getBinding(); |
| }); |
| } |
| |
| virtual void addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, |
| int64_t addr); |
| |
| virtual void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, |
| int64_t addr); |
| |
| virtual void addUndefinedAtom(Elf_Sym &sym, const UndefinedAtom *ua); |
| |
| virtual void addSharedLibAtom(Elf_Sym &sym, const SharedLibraryAtom *sla); |
| |
| virtual void finalize(bool sort); |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| void setStringSection(StringTable<ELFT> *s) { _stringSection = s; } |
| |
| StringTable<ELFT> *getStringTable() const { return _stringSection; } |
| |
| protected: |
| struct SymbolEntry { |
| SymbolEntry(const Atom *a, const Elf_Sym &sym, const AtomLayout *layout) |
| : _atom(a), _atomLayout(layout), _symbol(sym) {} |
| |
| const Atom *_atom; |
| const AtomLayout *_atomLayout; |
| Elf_Sym _symbol; |
| }; |
| |
| llvm::BumpPtrAllocator _symbolAllocate; |
| StringTable<ELFT> *_stringSection; |
| std::vector<SymbolEntry> _symbolTable; |
| }; |
| |
| template <class ELFT> class HashSection; |
| |
| template <class ELFT> class DynamicSymbolTable : public SymbolTable<ELFT> { |
| public: |
| 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(); |
| |
| void finalize() override; |
| |
| protected: |
| HashSection<ELFT> *_hashTable = nullptr; |
| TargetLayout<ELFT> &_layout; |
| }; |
| |
| template <class ELFT> class RelocationTable : public Section<ELFT> { |
| public: |
| typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel; |
| typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela; |
| |
| 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); |
| |
| 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; |
| |
| void finalize() override; |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| protected: |
| const DynamicSymbolTable<ELFT> *_symbolTable = nullptr; |
| |
| virtual void writeRela(ELFWriter *writer, Elf_Rela &r, |
| const DefinedAtom &atom, const Reference &ref); |
| virtual void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom, |
| const Reference &ref); |
| uint32_t getSymbolIndex(const Atom *a); |
| |
| private: |
| std::vector<std::pair<const DefinedAtom *, const Reference *>> _relocs; |
| }; |
| |
| template <class ELFT> class HashSection; |
| |
| template <class ELFT> class DynamicTable : public Section<ELFT> { |
| public: |
| typedef llvm::object::Elf_Dyn_Impl<ELFT> Elf_Dyn; |
| typedef std::vector<Elf_Dyn> EntriesT; |
| |
| 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(int64_t tag, uint64_t val); |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| 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; |
| |
| void setSymbolTable(DynamicSymbolTable<ELFT> *dynsym) { |
| _dynamicSymbolTable = dynsym; |
| } |
| |
| const DynamicSymbolTable<ELFT> *getSymbolTable() const { |
| return _dynamicSymbolTable; |
| } |
| |
| void setHashTable(HashSection<ELFT> *hsh) { _hashTable = hsh; } |
| |
| virtual void updateDynamicTable(); |
| |
| protected: |
| EntriesT _entries; |
| |
| /// \brief Return a virtual address (maybe adjusted) for the atom layout |
| /// Some targets like microMIPS and ARM Thumb use the last bit |
| /// of a symbol's value to mark 'compressed' code. This function allows |
| /// to adjust a virtal address before using it in the dynamic table tag. |
| virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const { |
| return al->_virtualAddr; |
| } |
| |
| private: |
| std::size_t _dt_hash; |
| std::size_t _dt_strtab; |
| std::size_t _dt_symtab; |
| std::size_t _dt_rela; |
| std::size_t _dt_relasz; |
| std::size_t _dt_relaent; |
| std::size_t _dt_strsz; |
| std::size_t _dt_syment; |
| std::size_t _dt_pltrelsz; |
| std::size_t _dt_pltgot; |
| std::size_t _dt_pltrel; |
| std::size_t _dt_jmprel; |
| std::size_t _dt_init_array; |
| std::size_t _dt_init_arraysz; |
| std::size_t _dt_fini_array; |
| std::size_t _dt_fini_arraysz; |
| std::size_t _dt_textrel; |
| std::size_t _dt_init; |
| std::size_t _dt_fini; |
| TargetLayout<ELFT> &_layout; |
| DynamicSymbolTable<ELFT> *_dynamicSymbolTable; |
| HashSection<ELFT> *_hashTable; |
| |
| const AtomLayout *getInitAtomLayout(); |
| |
| const AtomLayout *getFiniAtomLayout(); |
| }; |
| |
| template <class ELFT> class InterpSection : public Section<ELFT> { |
| public: |
| InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order, |
| StringRef interp); |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| private: |
| StringRef _interp; |
| }; |
| |
| /// The hash table in the dynamic linker is organized into |
| /// |
| /// [ nbuckets ] |
| /// [ nchains ] |
| /// [ buckets[0] ] |
| /// ......................... |
| /// [ buckets[nbuckets-1] ] |
| /// [ chains[0] ] |
| /// ......................... |
| /// [ chains[nchains - 1] ] |
| /// |
| /// nbuckets - total number of hash buckets |
| /// nchains is equal to the number of dynamic symbols. |
| /// |
| /// The symbol is searched by the dynamic linker using the below approach. |
| /// * Calculate the hash of the symbol that needs to be searched |
| /// * 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; |
| uint32_t _index; |
| }; |
| |
| public: |
| 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); |
| |
| /// \brief Set the dynamic symbol table |
| 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; |
| |
| void finalize() override; |
| |
| void write(ELFWriter *writer, TargetLayout<ELFT> &layout, |
| llvm::FileOutputBuffer &buffer) override; |
| |
| private: |
| typedef |
| typename llvm::object::ELFDataTypeTypedefHelper<ELFT>::Elf_Word Elf_Word; |
| |
| std::vector<SymbolTableEntry> _entries; |
| 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 &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; |
| |
| private: |
| int32_t _ehFrameOffset = 0; |
| TargetLayout<ELFT> &_layout; |
| }; |
| |
| } // end namespace elf |
| } // end namespace lld |
| |
| #endif // LLD_READER_WRITER_ELF_SECTION_CHUNKS_H |