diff options
Diffstat (limited to 'ELF/OutputSections.h')
-rw-r--r-- | ELF/OutputSections.h | 596 |
1 files changed, 421 insertions, 175 deletions
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index d7109c580cdc..5fdf8de4cb46 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -10,64 +10,35 @@ #ifndef LLD_ELF_OUTPUT_SECTIONS_H #define LLD_ELF_OUTPUT_SECTIONS_H -#include "lld/Core/LLVM.h" +#include "Config.h" +#include "Relocations.h" -#include "llvm/ADT/MapVector.h" +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" - -#include "Config.h" - -#include <type_traits> +#include "llvm/Support/MD5.h" +#include "llvm/Support/SHA1.h" namespace lld { -namespace elf2 { +namespace elf { class SymbolBody; +struct SectionPiece; template <class ELFT> class SymbolTable; template <class ELFT> class SymbolTableSection; template <class ELFT> class StringTableSection; -template <class ELFT> class EHInputSection; +template <class ELFT> class EhInputSection; template <class ELFT> class InputSection; template <class ELFT> class InputSectionBase; template <class ELFT> class MergeInputSection; template <class ELFT> class MipsReginfoInputSection; template <class ELFT> class OutputSection; template <class ELFT> class ObjectFile; +template <class ELFT> class SharedFile; +template <class ELFT> class SharedSymbol; template <class ELFT> class DefinedRegular; -// Flag to force GOT to be in output if we have relocations -// that relies on its address. -extern bool HasGotOffRel; - -template <class ELFT> -static inline typename llvm::object::ELFFile<ELFT>::uintX_t -getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Rel) { - return 0; -} - -template <class ELFT> -static inline typename llvm::object::ELFFile<ELFT>::uintX_t -getAddend(const typename llvm::object::ELFFile<ELFT>::Elf_Rela &Rel) { - return Rel.r_addend; -} - -template <class ELFT> -typename llvm::object::ELFFile<ELFT>::uintX_t getSymVA(const SymbolBody &S); - -template <class ELFT, bool IsRela> -typename llvm::object::ELFFile<ELFT>::uintX_t -getLocalRelTarget(const ObjectFile<ELFT> &File, - const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel, - typename llvm::object::ELFFile<ELFT>::uintX_t Addend); - -bool canBePreempted(const SymbolBody *Body, bool NeedsGot); - -template <class ELFT> -bool shouldKeepInSymtab( - const ObjectFile<ELFT> &File, StringRef Name, - const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym); - // This represents a section in an output file. // Different sub classes represent different types of sections. Some contain // input sections, others are created by the linker. @@ -75,13 +46,14 @@ bool shouldKeepInSymtab( // non-overlapping file offsets and VAs. template <class ELFT> class OutputSectionBase { public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; - OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags); void setVA(uintX_t VA) { Header.sh_addr = VA; } uintX_t getVA() const { return Header.sh_addr; } void setFileOffset(uintX_t Off) { Header.sh_offset = Off; } + void setSHName(unsigned Val) { Header.sh_name = Val; } void writeHeaderTo(Elf_Shdr *SHdr); StringRef getName() { return Name; } @@ -92,21 +64,24 @@ public: // Returns the size of the section in the output file. uintX_t getSize() const { return Header.sh_size; } void setSize(uintX_t Val) { Header.sh_size = Val; } - uintX_t getFlags() { return Header.sh_flags; } - uintX_t getFileOff() { return Header.sh_offset; } - uintX_t getAlign() { - // The ELF spec states that a value of 0 means the section has no alignment - // constraits. - return std::max<uintX_t>(Header.sh_addralign, 1); - } - uint32_t getType() { return Header.sh_type; } - void updateAlign(uintX_t Align) { - if (Align > Header.sh_addralign) - Header.sh_addralign = Align; + uintX_t getFlags() const { return Header.sh_flags; } + uintX_t getFileOff() const { return Header.sh_offset; } + uintX_t getAlignment() const { return Header.sh_addralign; } + uint32_t getType() const { return Header.sh_type; } + + void updateAlignment(uintX_t Alignment) { + if (Alignment > Header.sh_addralign) + Header.sh_addralign = Alignment; } + // If true, this section will be page aligned on disk. + // Typically the first section of each PT_LOAD segment has this flag. + bool PageAlign = false; + virtual void finalize() {} - virtual void writeTo(uint8_t *Buf) = 0; + virtual void finalizePieces() {} + virtual void assignOffsets() {} + virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; protected: @@ -116,18 +91,21 @@ protected: template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename Base::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: GotSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); - bool addDynTlsEntry(SymbolBody *Sym); - bool addCurrentModuleTlsIndex(); - bool empty() const { return Entries.empty(); } - uintX_t getEntryAddr(const SymbolBody &B) const; + void addEntry(SymbolBody &Sym); + void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr); + bool addDynTlsEntry(SymbolBody &Sym); + bool addTlsIndex(); + bool empty() const { return MipsPageEntries == 0 && Entries.empty(); } + uintX_t getMipsLocalPageOffset(uintX_t Addr); + uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const; uintX_t getGlobalDynAddr(const SymbolBody &B) const; + uintX_t getGlobalDynOffset(const SymbolBody &B) const; uintX_t getNumEntries() const { return Entries.size(); } // Returns the symbol which corresponds to the first entry of the global part @@ -140,24 +118,52 @@ public: // the number of reserved entries. This method is MIPS-specific. unsigned getMipsLocalEntriesNum() const; - uint32_t getLocalTlsIndexVA() { return Base::getVA() + LocalTlsIndexOff; } + // Returns offset of TLS part of the MIPS GOT table. This part goes + // after 'local' and 'global' entries. + uintX_t getMipsTlsOffset(); + + uintX_t getTlsIndexVA() { return Base::getVA() + TlsIndexOff; } + uint32_t getTlsIndexOff() { return TlsIndexOff; } + + // Flag to force GOT to be in output if we have relocations + // that relies on its address. + bool HasGotOffRel = false; private: std::vector<const SymbolBody *> Entries; - uint32_t LocalTlsIndexOff = -1; + uint32_t TlsIndexOff = -1; + uint32_t MipsPageEntries = 0; + // Output sections referenced by MIPS GOT relocations. + llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections; + llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos; + + // MIPS ABI requires to create unique GOT entry for each Symbol/Addend + // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal` + // or `MipsGlobal` vectors. In general it does not have a sence to take in + // account addend for preemptible symbols because the corresponding + // GOT entries should have one-to-one mapping with dynamic symbols table. + // But we use the same container's types for both kind of GOT entries + // to handle them uniformly. + typedef std::pair<const SymbolBody*, uintX_t> MipsGotEntry; + typedef std::vector<MipsGotEntry> MipsGotEntries; + llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap; + MipsGotEntries MipsLocal; + MipsGotEntries MipsGlobal; + + // Write MIPS-specific parts of the GOT. + void writeMipsGot(uint8_t *&Buf); }; template <class ELFT> class GotPltSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: GotPltSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); + void addEntry(SymbolBody &Sym); bool empty() const; - uintX_t getEntryAddr(const SymbolBody &B) const; private: std::vector<const SymbolBody *> Entries; @@ -165,156 +171,248 @@ private: template <class ELFT> class PltSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename Base::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; public: PltSection(); void finalize() override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody *Sym); + void addEntry(SymbolBody &Sym); bool empty() const { return Entries.empty(); } - uintX_t getEntryAddr(const SymbolBody &B) const; private: std::vector<std::pair<const SymbolBody *, unsigned>> Entries; }; -template <class ELFT> struct DynamicReloc { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - InputSectionBase<ELFT> *C; - const Elf_Rel *RI; +template <class ELFT> class DynamicReloc { + typedef typename ELFT::uint uintX_t; + +public: + DynamicReloc(uint32_t Type, const InputSectionBase<ELFT> *InputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + DynamicReloc(uint32_t Type, const OutputSectionBase<ELFT> *OutputSec, + uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, + uintX_t Addend) + : Type(Type), Sym(Sym), OutputSec(OutputSec), OffsetInSec(OffsetInSec), + UseSymVA(UseSymVA), Addend(Addend) {} + + uintX_t getOffset() const; + uintX_t getAddend() const; + uint32_t getSymIndex() const; + const OutputSectionBase<ELFT> *getOutputSec() const { return OutputSec; } + + uint32_t Type; + +private: + SymbolBody *Sym; + const InputSectionBase<ELFT> *InputSec = nullptr; + const OutputSectionBase<ELFT> *OutputSec = nullptr; + uintX_t OffsetInSec; + bool UseSymVA; + uintX_t Addend; }; template <class ELFT> class SymbolTableSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - SymbolTableSection(SymbolTable<ELFT> &Table, - StringTableSection<ELFT> &StrTabSec); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::uint uintX_t; + SymbolTableSection(StringTableSection<ELFT> &StrTabSec); void finalize() override; void writeTo(uint8_t *Buf) override; - void addLocalSymbol(StringRef Name); void addSymbol(SymbolBody *Body); StringTableSection<ELFT> &getStrTabSec() const { return StrTabSec; } - unsigned getNumSymbols() const { return NumVisible + 1; } + unsigned getNumSymbols() const { return NumLocals + Symbols.size() + 1; } - ArrayRef<SymbolBody *> getSymbols() const { return Symbols; } + ArrayRef<std::pair<SymbolBody *, size_t>> getSymbols() const { + return Symbols; + } + + unsigned NumLocals = 0; + StringTableSection<ELFT> &StrTabSec; private: void writeLocalSymbols(uint8_t *&Buf); void writeGlobalSymbols(uint8_t *Buf); - static uint8_t getSymbolBinding(SymbolBody *Body); + const OutputSectionBase<ELFT> *getOutputSection(SymbolBody *Sym); - SymbolTable<ELFT> &Table; - StringTableSection<ELFT> &StrTabSec; - std::vector<SymbolBody *> Symbols; - unsigned NumVisible = 0; - unsigned NumLocals = 0; + // A vector of symbols and their string table offsets. + std::vector<std::pair<SymbolBody *, size_t>> Symbols; +}; + +// For more information about .gnu.version and .gnu.version_r see: +// https://www.akkadia.org/drepper/symbol-versioning + +// The .gnu.version_d section which has a section type of SHT_GNU_verdef shall +// contain symbol version definitions. The number of entries in this section +// shall be contained in the DT_VERDEFNUM entry of the .dynamic section. +// The section shall contain an array of Elf_Verdef structures, optionally +// followed by an array of Elf_Verdaux structures. +template <class ELFT> +class VersionDefinitionSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verdef Elf_Verdef; + typedef typename ELFT::Verdaux Elf_Verdaux; + +public: + VersionDefinitionSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + +private: + void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); + + unsigned FileDefNameOff; +}; + +// The .gnu.version section specifies the required version of each symbol in the +// dynamic symbol table. It contains one Elf_Versym for each dynamic symbol +// table entry. An Elf_Versym is just a 16-bit integer that refers to a version +// identifier defined in the either .gnu.version_r or .gnu.version_d section. +// The values 0 and 1 are reserved. All other values are used for versions in +// the own object or in any of the dependencies. +template <class ELFT> +class VersionTableSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Versym Elf_Versym; + +public: + VersionTableSection(); + void finalize() override; + void writeTo(uint8_t *Buf) override; +}; + +// The .gnu.version_r section defines the version identifiers used by +// .gnu.version. It contains a linked list of Elf_Verneed data structures. Each +// Elf_Verneed specifies the version requirements for a single DSO, and contains +// a reference to a linked list of Elf_Vernaux data structures which define the +// mapping from version identifiers to version names. +template <class ELFT> +class VersionNeedSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::Verneed Elf_Verneed; + typedef typename ELFT::Vernaux Elf_Vernaux; + + // A vector of shared files that need Elf_Verneed data structures and the + // string table offsets of their sonames. + std::vector<std::pair<SharedFile<ELFT> *, size_t>> Needed; + + // The next available version identifier. + unsigned NextIndex; + +public: + VersionNeedSection(); + void addSymbol(SharedSymbol<ELFT> *SS); + void finalize() override; + void writeTo(uint8_t *Buf) override; + size_t getNeedNum() const { return Needed.size(); } }; template <class ELFT> class RelocationSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::uint uintX_t; public: - RelocationSection(StringRef Name, bool IsRela); - void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); } + RelocationSection(StringRef Name, bool Sort); + void addReloc(const DynamicReloc<ELFT> &Reloc); unsigned getRelocOffset(); void finalize() override; void writeTo(uint8_t *Buf) override; bool hasRelocs() const { return !Relocs.empty(); } - bool isRela() const { return IsRela; } bool Static = false; private: - bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P, - Elf_Rel *N); - + bool Sort; std::vector<DynamicReloc<ELFT>> Relocs; - const bool IsRela; }; template <class ELFT> class OutputSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::uint uintX_t; + OutputSection(StringRef Name, uint32_t Type, uintX_t Flags); void addSection(InputSectionBase<ELFT> *C) override; + void sortInitFini(); + void sortCtorsDtors(); void writeTo(uint8_t *Buf) override; - -private: + void finalize() override; + void assignOffsets() override; std::vector<InputSection<ELFT> *> Sections; }; template <class ELFT> class MergeOutputSection final : public OutputSectionBase<ELFT> { - typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t; - - bool shouldTailMerge() const; + typedef typename ELFT::uint uintX_t; public: - MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags, + uintX_t Alignment); void addSection(InputSectionBase<ELFT> *S) override; void writeTo(uint8_t *Buf) override; unsigned getOffset(StringRef Val); void finalize() override; + void finalizePieces() override; + bool shouldTailMerge() const; private: - llvm::StringTableBuilder Builder{llvm::StringTableBuilder::RAW}; + llvm::StringTableBuilder Builder; + std::vector<MergeInputSection<ELFT> *> Sections; }; -// FDE or CIE -template <class ELFT> struct EHRegion { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - EHRegion(EHInputSection<ELFT> *S, unsigned Index); - StringRef data() const; - EHInputSection<ELFT> *S; - unsigned Index; -}; - -template <class ELFT> struct Cie : public EHRegion<ELFT> { - Cie(EHInputSection<ELFT> *S, unsigned Index); - std::vector<EHRegion<ELFT>> Fdes; +struct CieRecord { + SectionPiece *Piece = nullptr; + std::vector<SectionPiece *> FdePieces; }; +// Output section for .eh_frame. template <class ELFT> -class EHOutputSection final : public OutputSectionBase<ELFT> { +class EhOutputSection final : public OutputSectionBase<ELFT> { + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - EHOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + EhOutputSection(); void writeTo(uint8_t *Buf) override; - - template <bool IsRela> - void addSectionAux( - EHInputSection<ELFT> *S, - llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, IsRela> *> - Rels); + void finalize() override; + bool empty() const { return Sections.empty(); } void addSection(InputSectionBase<ELFT> *S) override; + size_t NumFdes = 0; + private: - uintX_t readEntryLength(ArrayRef<uint8_t> D); + template <class RelTy> + void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels); + + template <class RelTy> + CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels); + + template <class RelTy> + bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec, + ArrayRef<RelTy> &Rels); + + uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc); - std::vector<EHInputSection<ELFT> *> Sections; - std::vector<Cie<ELFT>> Cies; + std::vector<EhInputSection<ELFT> *> Sections; + std::vector<CieRecord *> Cies; - // Maps CIE content + personality to a index in Cies. - llvm::DenseMap<std::pair<StringRef, StringRef>, unsigned> CieMap; + // CIE records are uniquified by their contents and personality functions. + llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap; }; template <class ELFT> @@ -327,25 +425,24 @@ public: template <class ELFT> class StringTableSection final : public OutputSectionBase<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::uint uintX_t; StringTableSection(StringRef Name, bool Dynamic); - void reserve(StringRef S); - size_t addString(StringRef S); + unsigned addString(StringRef S, bool HashIt = true); void writeTo(uint8_t *Buf) override; - size_t getSize() const { return Used + Reserved; } + unsigned getSize() const { return Size; } void finalize() override { this->Header.sh_size = getSize(); } bool isDynamic() const { return Dynamic; } private: const bool Dynamic; + llvm::DenseMap<StringRef, unsigned> StringMap; std::vector<StringRef> Strings; - size_t Used = 1; // ELF string tables start with a NUL byte, so 1. - size_t Reserved = 0; + unsigned Size = 1; // ELF string tables start with a NUL byte, so 1. }; template <class ELFT> class HashTableSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; + typedef typename ELFT::Word Elf_Word; public: HashTableSection(); @@ -357,9 +454,9 @@ public: // https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections template <class ELFT> class GnuHashTableSection final : public OutputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Off Elf_Off; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Off Elf_Off; + typedef typename ELFT::Word Elf_Word; + typedef typename ELFT::uint uintX_t; public: GnuHashTableSection(); @@ -368,7 +465,7 @@ public: // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. - void addSymbols(std::vector<SymbolBody *> &Symbols); + void addSymbols(std::vector<std::pair<SymbolBody *, size_t>> &Symbols); private: static unsigned calcNBuckets(unsigned NumHashed); @@ -378,12 +475,13 @@ private: void writeBloomFilter(uint8_t *&Buf); void writeHashTable(uint8_t *Buf); - struct HashedSymbolData { + struct SymbolData { SymbolBody *Body; + size_t STName; uint32_t Hash; }; - std::vector<HashedSymbolData> HashedSymbols; + std::vector<SymbolData> Symbols; unsigned MaskWords; unsigned NBuckets; @@ -393,27 +491,45 @@ private: template <class ELFT> class DynamicSection final : public OutputSectionBase<ELFT> { typedef OutputSectionBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Dyn Elf_Dyn; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename ELFT::Dyn Elf_Dyn; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; + + // The .dynamic section contains information for the dynamic linker. + // The section consists of fixed size entries, which consist of + // type and value fields. Value are one of plain integers, symbol + // addresses, or section addresses. This struct represents the entry. + struct Entry { + int32_t Tag; + union { + OutputSectionBase<ELFT> *OutSec; + uint64_t Val; + const SymbolBody *Sym; + }; + enum KindT { SecAddr, SymAddr, PlainInt } Kind; + Entry(int32_t Tag, OutputSectionBase<ELFT> *OutSec) + : Tag(Tag), OutSec(OutSec), Kind(SecAddr) {} + Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {} + Entry(int32_t Tag, const SymbolBody *Sym) + : Tag(Tag), Sym(Sym), Kind(SymAddr) {} + }; + + // finalize() fills this vector with the section contents. finalize() + // cannot directly create final section contents because when the + // function is called, symbol or section addresses are not fixed yet. + std::vector<Entry> Entries; public: - DynamicSection(SymbolTable<ELFT> &SymTab); + explicit DynamicSection(); void finalize() override; void writeTo(uint8_t *Buf) override; OutputSectionBase<ELFT> *PreInitArraySec = nullptr; OutputSectionBase<ELFT> *InitArraySec = nullptr; OutputSectionBase<ELFT> *FiniArraySec = nullptr; - -private: - SymbolTable<ELFT> &SymTab; - const SymbolBody *InitSym = nullptr; - const SymbolBody *FiniSym = nullptr; - uint32_t DtFlags = 0; - uint32_t DtFlags1 = 0; }; template <class ELFT> @@ -429,17 +545,94 @@ private: uint32_t GprMask = 0; }; -inline uint64_t align(uint64_t Value, uint64_t Align) { - return llvm::RoundUpToAlignment(Value, Align); -} +template <class ELFT> +class MipsOptionsOutputSection final : public OutputSectionBase<ELFT> { + typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; + typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; + +public: + MipsOptionsOutputSection(); + void writeTo(uint8_t *Buf) override; + void addSection(InputSectionBase<ELFT> *S) override; + +private: + uint32_t GprMask = 0; +}; + +// --eh-frame-hdr option tells linker to construct a header for all the +// .eh_frame sections. This header is placed to a section named .eh_frame_hdr +// and also to a PT_GNU_EH_FRAME segment. +// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by +// calling dl_iterate_phdr. +// This section contains a lookup table for quick binary search of FDEs. +// Detailed info about internals can be found in Ian Lance Taylor's blog: +// http://www.airs.com/blog/archives/460 (".eh_frame") +// http://www.airs.com/blog/archives/462 (".eh_frame_hdr") +template <class ELFT> +class EhFrameHeader final : public OutputSectionBase<ELFT> { + typedef typename ELFT::uint uintX_t; + +public: + EhFrameHeader(); + void finalize() override; + void writeTo(uint8_t *Buf) override; + void addFde(uint32_t Pc, uint32_t FdeVA); + +private: + struct FdeData { + uint32_t Pc; + uint32_t FdeVA; + }; + + std::vector<FdeData> Fdes; +}; + +template <class ELFT> class BuildIdSection : public OutputSectionBase<ELFT> { +public: + void writeTo(uint8_t *Buf) override; + virtual void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) = 0; + +protected: + BuildIdSection(size_t HashSize); + size_t HashSize; + uint8_t *HashBuf = nullptr; +}; + +template <class ELFT> class BuildIdFnv1 final : public BuildIdSection<ELFT> { +public: + BuildIdFnv1() : BuildIdSection<ELFT>(8) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> class BuildIdMd5 final : public BuildIdSection<ELFT> { +public: + BuildIdMd5() : BuildIdSection<ELFT>(16) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> class BuildIdSha1 final : public BuildIdSection<ELFT> { +public: + BuildIdSha1() : BuildIdSection<ELFT>(20) {} + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; + +template <class ELFT> +class BuildIdHexstring final : public BuildIdSection<ELFT> { +public: + BuildIdHexstring(); + void writeBuildId(ArrayRef<ArrayRef<uint8_t>> Bufs) override; +}; // All output sections that are hadnled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. template <class ELFT> struct Out { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Phdr Elf_Phdr; + static BuildIdSection<ELFT> *BuildId; static DynamicSection<ELFT> *Dynamic; + static EhFrameHeader<ELFT> *EhFrameHdr; + static EhOutputSection<ELFT> *EhFrame; static GnuHashTableSection<ELFT> *GnuHashTab; static GotPltSection<ELFT> *GotPlt; static GotSection<ELFT> *Got; @@ -457,10 +650,47 @@ template <class ELFT> struct Out { static StringTableSection<ELFT> *StrTab; static SymbolTableSection<ELFT> *DynSymTab; static SymbolTableSection<ELFT> *SymTab; + static VersionDefinitionSection<ELFT> *VerDef; + static VersionTableSection<ELFT> *VerSym; + static VersionNeedSection<ELFT> *VerNeed; static Elf_Phdr *TlsPhdr; + static OutputSectionBase<ELFT> *ElfHeader; + static OutputSectionBase<ELFT> *ProgramHeaders; }; +template <bool Is64Bits> struct SectionKey { + typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t; + StringRef Name; + uint32_t Type; + uintX_t Flags; + uintX_t Alignment; +}; + +// This class knows how to create an output section for a given +// input section. Output section type is determined by various +// factors, including input section's sh_flags, sh_type and +// linker scripts. +template <class ELFT> class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename elf::SectionKey<ELFT::Is64Bits> Key; + +public: + std::pair<OutputSectionBase<ELFT> *, bool> create(InputSectionBase<ELFT> *C, + StringRef OutsecName); + + OutputSectionBase<ELFT> *lookup(StringRef Name, uint32_t Type, uintX_t Flags); + +private: + Key createKey(InputSectionBase<ELFT> *C, StringRef OutsecName); + + llvm::SmallDenseMap<Key, OutputSectionBase<ELFT> *> Map; +}; + +template <class ELFT> BuildIdSection<ELFT> *Out<ELFT>::BuildId; template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic; +template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr; +template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame; template <class ELFT> GnuHashTableSection<ELFT> *Out<ELFT>::GnuHashTab; template <class ELFT> GotPltSection<ELFT> *Out<ELFT>::GotPlt; template <class ELFT> GotSection<ELFT> *Out<ELFT>::Got; @@ -478,9 +708,25 @@ template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::ShStrTab; template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab; template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab; -template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr; - -} // namespace elf2 +template <class ELFT> VersionDefinitionSection<ELFT> *Out<ELFT>::VerDef; +template <class ELFT> VersionTableSection<ELFT> *Out<ELFT>::VerSym; +template <class ELFT> VersionNeedSection<ELFT> *Out<ELFT>::VerNeed; +template <class ELFT> typename ELFT::Phdr *Out<ELFT>::TlsPhdr; +template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ElfHeader; +template <class ELFT> OutputSectionBase<ELFT> *Out<ELFT>::ProgramHeaders; + +} // namespace elf } // namespace lld -#endif // LLD_ELF_OUTPUT_SECTIONS_H +namespace llvm { +template <bool Is64Bits> struct DenseMapInfo<lld::elf::SectionKey<Is64Bits>> { + typedef typename lld::elf::SectionKey<Is64Bits> Key; + + static Key getEmptyKey(); + static Key getTombstoneKey(); + static unsigned getHashValue(const Key &Val); + static bool isEqual(const Key &LHS, const Key &RHS); +}; +} + +#endif |