//===- 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 #include namespace lld { namespace elf { template class OutputSection; using namespace llvm::ELF; template class Segment; template class TargetLayout; /// \brief An ELF section. template class Section : public Chunk { public: Section(const ELFLinkingContext &ctx, StringRef sectionName, StringRef chunkName, typename Chunk::Kind k = Chunk::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::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::SegmentType segmentType) { this->_segmentType = segmentType; } virtual const AtomLayout *findAtomLayoutByName(StringRef) const { return nullptr; } const OutputSection *getOutputSection() const { return _outputSection; } void setOutputSection(OutputSection *os, bool isFirst = false) { _outputSection = os; _isFirstSectionInOutputSection = isFirst; } static bool classof(const Chunk *c) { return c->kind() == Chunk::Kind::ELFSection || c->kind() == Chunk::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 *_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::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 AtomSection : public Section { 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 virtual 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::iterator atom_iter; range atoms() { return _atoms; } void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) override; static bool classof(const Chunk *c) { return c->kind() == Chunk::Kind::AtomSection; } protected: llvm::BumpPtrAllocator _alloc; int32_t _contentType; int32_t _contentPermissions; bool _isLoadedInMemory = true; std::vector _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 OutputSection { public: // Iterators typedef typename std::vector *>::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 *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 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 *> _sections; }; /// \brief The class represents the ELF String Table template class StringTable : public Section { public: StringTable(const ELFLinkingContext &, const char *str, int32_t order, bool dynamic = false); uint64_t addString(StringRef symname); void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) override; void setNumEntries(int64_t numEntries) { _stringMap.resize(numEntries); } private: std::vector _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 StringMapT; typedef typename StringMapT::iterator StringMapTIter; StringMapT _stringMap; }; /// \brief The SymbolTable class represents the symbol table in a ELF file template class SymbolTable : public Section { typedef typename llvm::object::ELFDataTypeTypedefHelper::Elf_Addr Elf_Addr; public: typedef llvm::object::Elf_Sym_Impl 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 &layout, llvm::FileOutputBuffer &buffer) override; void setStringSection(StringTable *s) { _stringSection = s; } StringTable *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 *_stringSection; std::vector _symbolTable; }; template class HashSection; template class DynamicSymbolTable : public SymbolTable { public: DynamicSymbolTable(const ELFLinkingContext &ctx, TargetLayout &layout, const char *str, int32_t order); // Set the dynamic hash table for symbols to be added into void setHashTable(HashSection *hashTable) { _hashTable = hashTable; } // Add all the dynamic symbos to the hash table void addSymbolsToHashTable(); void finalize() override; protected: HashSection *_hashTable = nullptr; TargetLayout &_layout; }; template class RelocationTable : public Section { public: typedef llvm::object::Elf_Rel_Impl Elf_Rel; typedef llvm::object::Elf_Rel_Impl 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 *symbolTable) { _symbolTable = symbolTable; } /// \brief Check if any relocation modifies a read-only section. bool canModifyReadonlySection() const; void finalize() override; void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) override; protected: const DynamicSymbolTable *_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> _relocs; }; template class HashSection; template class DynamicTable : public Section { public: typedef llvm::object::Elf_Dyn_Impl Elf_Dyn; typedef std::vector EntriesT; DynamicTable(const ELFLinkingContext &ctx, TargetLayout &layout, StringRef str, int32_t order); range entries() { return _entries; } /// \returns the index of the entry. std::size_t addEntry(int64_t tag, uint64_t val); void write(ELFWriter *writer, TargetLayout &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 *dynsym) { _dynamicSymbolTable = dynsym; } const DynamicSymbolTable *getSymbolTable() const { return _dynamicSymbolTable; } void setHashTable(HashSection *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 &_layout; DynamicSymbolTable *_dynamicSymbolTable; HashSection *_hashTable; const AtomLayout *getInitAtomLayout(); const AtomLayout *getFiniAtomLayout(); }; template class InterpSection : public Section { public: InterpSection(const ELFLinkingContext &ctx, StringRef str, int32_t order, StringRef interp); void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer); 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 HashSection : public Section { 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 *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 &layout, llvm::FileOutputBuffer &buffer) override; private: typedef typename llvm::object::ELFDataTypeTypedefHelper::Elf_Word Elf_Word; std::vector _entries; std::vector _buckets; std::vector _chains; const DynamicSymbolTable *_symbolTable = nullptr; }; template class EHFrameHeader : public Section { public: EHFrameHeader(const ELFLinkingContext &ctx, StringRef name, TargetLayout &layout, int32_t order); void doPreFlight() override; void finalize() override; void write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) override; private: int32_t _ehFrameOffset = 0; TargetLayout &_layout; }; } // end namespace elf } // end namespace lld #endif