diff options
Diffstat (limited to 'ELF/SyntheticSections.h')
-rw-r--r-- | ELF/SyntheticSections.h | 893 |
1 files changed, 519 insertions, 374 deletions
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 6fc40d355d5e2..1c4dd06e02776 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -1,9 +1,8 @@ //===- SyntheticSection.h ---------------------------------------*- C++ -*-===// // -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -18,8 +17,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_ELF_SYNTHETIC_SECTION_H -#define LLD_ELF_SYNTHETIC_SECTION_H +#ifndef LLD_ELF_SYNTHETIC_SECTIONS_H +#define LLD_ELF_SYNTHETIC_SECTIONS_H #include "DWARF.h" #include "EhFrame.h" @@ -32,107 +31,113 @@ namespace lld { namespace elf { class Defined; -class SharedSymbol; +struct PhdrEntry; +class SymbolTableBaseSection; +class VersionNeedBaseSection; class SyntheticSection : public InputSection { public: - SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, - StringRef Name) - : InputSection(nullptr, Flags, Type, Alignment, {}, Name, + SyntheticSection(uint64_t flags, uint32_t type, uint32_t alignment, + StringRef name) + : InputSection(nullptr, flags, type, alignment, {}, name, InputSectionBase::Synthetic) { - this->Live = true; + markLive(); } virtual ~SyntheticSection() = default; - virtual void writeTo(uint8_t *Buf) = 0; + virtual void writeTo(uint8_t *buf) = 0; virtual size_t getSize() const = 0; virtual void finalizeContents() {} // If the section has the SHF_ALLOC flag and the size may be changed if // thunks are added, update the section size. virtual bool updateAllocSize() { return false; } - virtual bool empty() const { return false; } + virtual bool isNeeded() const { return true; } - static bool classof(const SectionBase *D) { - return D->kind() == InputSectionBase::Synthetic; + static bool classof(const SectionBase *d) { + return d->kind() == InputSectionBase::Synthetic; } }; struct CieRecord { - EhSectionPiece *Cie = nullptr; - std::vector<EhSectionPiece *> Fdes; + EhSectionPiece *cie = nullptr; + std::vector<EhSectionPiece *> fdes; }; // Section for .eh_frame. class EhFrameSection final : public SyntheticSection { public: EhFrameSection(); - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; void finalizeContents() override; - bool empty() const override { return Sections.empty(); } - size_t getSize() const override { return Size; } + bool isNeeded() const override { return !sections.empty(); } + size_t getSize() const override { return size; } + + static bool classof(const SectionBase *d) { + return SyntheticSection::classof(d) && d->name == ".eh_frame"; + } - template <class ELFT> void addSection(InputSectionBase *S); + template <class ELFT> void addSection(InputSectionBase *s); - std::vector<EhInputSection *> Sections; - size_t NumFdes = 0; + std::vector<EhInputSection *> sections; + size_t numFdes = 0; struct FdeData { - uint32_t PcRel; - uint32_t FdeVARel; + uint32_t pcRel; + uint32_t fdeVARel; }; std::vector<FdeData> getFdeData() const; - ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; } + ArrayRef<CieRecord *> getCieRecords() const { return cieRecords; } private: // This is used only when parsing EhInputSection. We keep it here to avoid // allocating one for each EhInputSection. - llvm::DenseMap<size_t, CieRecord *> OffsetToCie; + llvm::DenseMap<size_t, CieRecord *> offsetToCie; - uint64_t Size = 0; + uint64_t size = 0; template <class ELFT, class RelTy> - void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels); + void addSectionAux(EhInputSection *s, llvm::ArrayRef<RelTy> rels); template <class ELFT, class RelTy> - CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); + CieRecord *addCie(EhSectionPiece &piece, ArrayRef<RelTy> rels); template <class ELFT, class RelTy> - bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); + bool isFdeLive(EhSectionPiece &piece, ArrayRef<RelTy> rels); - uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc) const; + uint64_t getFdePc(uint8_t *buf, size_t off, uint8_t enc) const; - std::vector<CieRecord *> CieRecords; + std::vector<CieRecord *> cieRecords; // CIE records are uniquified by their contents and personality functions. - llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> CieMap; + llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> cieMap; }; class GotSection : public SyntheticSection { public: GotSection(); - size_t getSize() const override { return Size; } + size_t getSize() const override { return size; } void finalizeContents() override; - bool empty() const override; - void writeTo(uint8_t *Buf) override; + bool isNeeded() const override; + void writeTo(uint8_t *buf) override; - void addEntry(Symbol &Sym); - bool addDynTlsEntry(Symbol &Sym); + void addEntry(Symbol &sym); + bool addDynTlsEntry(Symbol &sym); bool addTlsIndex(); - uint64_t getGlobalDynAddr(const Symbol &B) const; - uint64_t getGlobalDynOffset(const Symbol &B) const; + uint64_t getGlobalDynAddr(const Symbol &b) const; + uint64_t getGlobalDynOffset(const Symbol &b) const; - uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; } - uint32_t getTlsIndexOff() const { return TlsIndexOff; } + uint64_t getTlsIndexVA() { return this->getVA() + tlsIndexOff; } + uint32_t getTlsIndexOff() const { return tlsIndexOff; } // Flag to force GOT to be in output if we have relocations // that relies on its address. - bool HasGotOffRel = false; + bool hasGotOffRel = false; protected: - size_t NumEntries = 0; - uint32_t TlsIndexOff = -1; - uint64_t Size = 0; + size_t numEntries = 0; + uint32_t tlsIndexOff = -1; + uint64_t size = 0; }; // .note.GNU-stack section. @@ -140,27 +145,31 @@ class GnuStackSection : public SyntheticSection { public: GnuStackSection() : SyntheticSection(0, llvm::ELF::SHT_PROGBITS, 1, ".note.GNU-stack") {} - void writeTo(uint8_t *Buf) override {} + void writeTo(uint8_t *buf) override {} size_t getSize() const override { return 0; } }; +class GnuPropertySection : public SyntheticSection { +public: + GnuPropertySection(); + void writeTo(uint8_t *buf) override; + size_t getSize() const override; +}; + // .note.gnu.build-id section. class BuildIdSection : public SyntheticSection { // First 16 bytes are a header. - static const unsigned HeaderSize = 16; + static const unsigned headerSize = 16; public: + const size_t hashSize; BuildIdSection(); - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return HeaderSize + HashSize; } - void writeBuildId(llvm::ArrayRef<uint8_t> Buf); + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return headerSize + hashSize; } + void writeBuildId(llvm::ArrayRef<uint8_t> buf); private: - void computeHash(llvm::ArrayRef<uint8_t> Buf, - std::function<void(uint8_t *, ArrayRef<uint8_t>)> Hash); - - size_t HashSize; - uint8_t *HashBuf; + uint8_t *hashBuf; }; // BssSection is used to reserve space for copy relocations and common symbols. @@ -169,40 +178,40 @@ private: // respectively. class BssSection final : public SyntheticSection { public: - BssSection(StringRef Name, uint64_t Size, uint32_t Alignment); + BssSection(StringRef name, uint64_t size, uint32_t alignment); void writeTo(uint8_t *) override { llvm_unreachable("unexpected writeTo() call for SHT_NOBITS section"); } - bool empty() const override { return getSize() == 0; } - size_t getSize() const override { return Size; } + bool isNeeded() const override { return size != 0; } + size_t getSize() const override { return size; } - static bool classof(const SectionBase *S) { return S->Bss; } - uint64_t Size; + static bool classof(const SectionBase *s) { return s->bss; } + uint64_t size; }; class MipsGotSection final : public SyntheticSection { public: MipsGotSection(); - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } bool updateAllocSize() override; void finalizeContents() override; - bool empty() const override; + bool isNeeded() const override; // Join separate GOTs built for each input file to generate // primary and optional multiple secondary GOTs. - template <class ELFT> void build(); + void build(); - void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr); - void addDynTlsEntry(InputFile &File, Symbol &Sym); - void addTlsIndex(InputFile &File); + void addEntry(InputFile &file, Symbol &sym, int64_t addend, RelExpr expr); + void addDynTlsEntry(InputFile &file, Symbol &sym); + void addTlsIndex(InputFile &file); - uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S, - int64_t Addend) const; - uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S, - int64_t Addend) const; - uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const; - uint64_t getTlsIndexOffset(const InputFile *F) const; + uint64_t getPageEntryOffset(const InputFile *f, const Symbol &s, + int64_t addend) const; + uint64_t getSymEntryOffset(const InputFile *f, const Symbol &s, + int64_t addend) const; + uint64_t getGlobalDynOffset(const InputFile *f, const Symbol &s) const; + uint64_t getTlsIndexOffset(const InputFile *f) const; // Returns the symbol which corresponds to the first entry of the global part // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic @@ -215,7 +224,7 @@ public: unsigned getLocalEntriesNum() const; // Return _gp value for primary GOT (nullptr) or particular input file. - uint64_t getGp(const InputFile *F = nullptr) const; + uint64_t getGp(const InputFile *f = nullptr) const; private: // MIPS GOT consists of three parts: local, global and tls. Each part @@ -305,34 +314,35 @@ private: // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT // Number of "Header" entries. - static const unsigned HeaderEntriesNum = 2; + static const unsigned headerEntriesNum = 2; - uint64_t Size = 0; + uint64_t size = 0; // Symbol and addend. - typedef std::pair<Symbol *, int64_t> GotEntry; + using GotEntry = std::pair<Symbol *, int64_t>; struct FileGot { - InputFile *File = nullptr; - size_t StartIndex = 0; + InputFile *file = nullptr; + size_t startIndex = 0; struct PageBlock { - size_t FirstIndex = 0; - size_t Count = 0; + size_t firstIndex; + size_t count; + PageBlock() : firstIndex(0), count(0) {} }; // Map output sections referenced by MIPS GOT relocations // to the description (index/count) "page" entries allocated // for this section. - llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap; + llvm::SmallMapVector<const OutputSection *, PageBlock, 16> pagesMap; // Maps from Symbol+Addend pair or just Symbol to the GOT entry index. - llvm::MapVector<GotEntry, size_t> Local16; - llvm::MapVector<GotEntry, size_t> Local32; - llvm::MapVector<Symbol *, size_t> Global; - llvm::MapVector<Symbol *, size_t> Relocs; - llvm::MapVector<Symbol *, size_t> Tls; + llvm::MapVector<GotEntry, size_t> local16; + llvm::MapVector<GotEntry, size_t> local32; + llvm::MapVector<Symbol *, size_t> global; + llvm::MapVector<Symbol *, size_t> relocs; + llvm::MapVector<Symbol *, size_t> tls; // Set of symbols referenced by dynamic TLS relocations. - llvm::MapVector<Symbol *, size_t> DynTlsSymbols; + llvm::MapVector<Symbol *, size_t> dynTlsSymbols; // Total number of all entries. size_t getEntriesNum() const; @@ -345,27 +355,31 @@ private: // Container of GOT created for each input file. // After building a final series of GOTs this container // holds primary and secondary GOT's. - std::vector<FileGot> Gots; + std::vector<FileGot> gots; // Return (and create if necessary) `FileGot`. - FileGot &getGot(InputFile &F); + FileGot &getGot(InputFile &f); // Try to merge two GOTs. In case of success the `Dst` contains // result of merging and the function returns true. In case of // ovwerflow the `Dst` is unchanged and the function returns false. - bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary); + bool tryMergeGots(FileGot & dst, FileGot & src, bool isPrimary); }; class GotPltSection final : public SyntheticSection { public: GotPltSection(); - void addEntry(Symbol &Sym); + void addEntry(Symbol &sym); size_t getSize() const override; - void writeTo(uint8_t *Buf) override; - bool empty() const override; + void writeTo(uint8_t *buf) override; + bool isNeeded() const override; + + // Flag to force GotPlt to be in output if we have relocations + // that relies on its address. + bool hasGotPltOffRel = false; private: - std::vector<const Symbol *> Entries; + std::vector<const Symbol *> entries; }; // The IgotPltSection is a Got associated with the PltSection for GNU Ifunc @@ -375,167 +389,164 @@ private: class IgotPltSection final : public SyntheticSection { public: IgotPltSection(); - void addEntry(Symbol &Sym); + void addEntry(Symbol &sym); size_t getSize() const override; - void writeTo(uint8_t *Buf) override; - bool empty() const override { return Entries.empty(); } + void writeTo(uint8_t *buf) override; + bool isNeeded() const override { return !entries.empty(); } private: - std::vector<const Symbol *> Entries; + std::vector<const Symbol *> entries; }; class StringTableSection final : public SyntheticSection { public: - StringTableSection(StringRef Name, bool Dynamic); - unsigned addString(StringRef S, bool HashIt = true); - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } - bool isDynamic() const { return Dynamic; } + StringTableSection(StringRef name, bool dynamic); + unsigned addString(StringRef s, bool hashIt = true); + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } + bool isDynamic() const { return dynamic; } private: - const bool Dynamic; + const bool dynamic; - uint64_t Size = 0; + uint64_t size = 0; - llvm::DenseMap<StringRef, unsigned> StringMap; - std::vector<StringRef> Strings; + llvm::DenseMap<StringRef, unsigned> stringMap; + std::vector<StringRef> strings; }; class DynamicReloc { public: - DynamicReloc(RelType Type, const InputSectionBase *InputSec, - uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend) - : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), - UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {} + DynamicReloc(RelType type, const InputSectionBase *inputSec, + uint64_t offsetInSec, bool useSymVA, Symbol *sym, int64_t addend) + : type(type), sym(sym), inputSec(inputSec), offsetInSec(offsetInSec), + useSymVA(useSymVA), addend(addend), outputSec(nullptr) {} // This constructor records dynamic relocation settings used by MIPS // multi-GOT implementation. It's to relocate addresses of 64kb pages // lie inside the output section. - DynamicReloc(RelType Type, const InputSectionBase *InputSec, - uint64_t OffsetInSec, const OutputSection *OutputSec, - int64_t Addend) - : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec), - UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {} + DynamicReloc(RelType type, const InputSectionBase *inputSec, + uint64_t offsetInSec, const OutputSection *outputSec, + int64_t addend) + : type(type), sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), + useSymVA(false), addend(addend), outputSec(outputSec) {} uint64_t getOffset() const; - uint32_t getSymIndex() const; - const InputSectionBase *getInputSec() const { return InputSec; } + uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; // Computes the addend of the dynamic relocation. Note that this is not the - // same as the Addend member variable as it also includes the symbol address - // if UseSymVA is true. + // same as the addend member variable as it also includes the symbol address + // if useSymVA is true. int64_t computeAddend() const; - RelType Type; + RelType type; -private: - Symbol *Sym; - const InputSectionBase *InputSec = nullptr; - uint64_t OffsetInSec; + Symbol *sym; + const InputSectionBase *inputSec = nullptr; + uint64_t offsetInSec; // If this member is true, the dynamic relocation will not be against the // symbol but will instead be a relative relocation that simply adds the // load address. This means we need to write the symbol virtual address // plus the original addend as the final relocation addend. - bool UseSymVA; - int64_t Addend; - const OutputSection *OutputSec; + bool useSymVA; + int64_t addend; + const OutputSection *outputSec; }; template <class ELFT> class DynamicSection final : public SyntheticSection { - typedef typename ELFT::Dyn Elf_Dyn; - typedef typename ELFT::Rel Elf_Rel; - typedef typename ELFT::Rela Elf_Rela; - typedef typename ELFT::Relr Elf_Relr; - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Sym Elf_Sym; + using Elf_Dyn = typename ELFT::Dyn; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Relr = typename ELFT::Relr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Sym = typename ELFT::Sym; // finalizeContents() fills this vector with the section contents. - std::vector<std::pair<int32_t, std::function<uint64_t()>>> Entries; + std::vector<std::pair<int32_t, std::function<uint64_t()>>> entries; public: DynamicSection(); void finalizeContents() override; - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } private: - void add(int32_t Tag, std::function<uint64_t()> Fn); - void addInt(int32_t Tag, uint64_t Val); - void addInSec(int32_t Tag, InputSection *Sec); - void addInSecRelative(int32_t Tag, InputSection *Sec); - void addOutSec(int32_t Tag, OutputSection *Sec); - void addSize(int32_t Tag, OutputSection *Sec); - void addSym(int32_t Tag, Symbol *Sym); - - uint64_t Size = 0; + void add(int32_t tag, std::function<uint64_t()> fn); + void addInt(int32_t tag, uint64_t val); + void addInSec(int32_t tag, InputSection *sec); + void addInSecRelative(int32_t tag, InputSection *sec); + void addOutSec(int32_t tag, OutputSection *sec); + void addSize(int32_t tag, OutputSection *sec); + void addSym(int32_t tag, Symbol *sym); + + uint64_t size = 0; }; class RelocationBaseSection : public SyntheticSection { public: - RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag, - int32_t SizeDynamicTag); - void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec, - Symbol *Sym); + RelocationBaseSection(StringRef name, uint32_t type, int32_t dynamicTag, + int32_t sizeDynamicTag); + void addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, + Symbol *sym); // Add a dynamic relocation that might need an addend. This takes care of // writing the addend to the output section if needed. - void addReloc(RelType DynType, InputSectionBase *InputSec, - uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr, - RelType Type); - void addReloc(const DynamicReloc &Reloc); - bool empty() const override { return Relocs.empty(); } - size_t getSize() const override { return Relocs.size() * this->Entsize; } - size_t getRelativeRelocCount() const { return NumRelativeRelocs; } + void addReloc(RelType dynType, InputSectionBase *inputSec, + uint64_t offsetInSec, Symbol *sym, int64_t addend, RelExpr expr, + RelType type); + void addReloc(const DynamicReloc &reloc); + bool isNeeded() const override { return !relocs.empty(); } + size_t getSize() const override { return relocs.size() * this->entsize; } + size_t getRelativeRelocCount() const { return numRelativeRelocs; } void finalizeContents() override; - int32_t DynamicTag, SizeDynamicTag; + int32_t dynamicTag, sizeDynamicTag; + std::vector<DynamicReloc> relocs; protected: - std::vector<DynamicReloc> Relocs; - size_t NumRelativeRelocs = 0; + size_t numRelativeRelocs = 0; }; template <class ELFT> class RelocationSection final : public RelocationBaseSection { - typedef typename ELFT::Rel Elf_Rel; - typedef typename ELFT::Rela Elf_Rela; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; public: - RelocationSection(StringRef Name, bool Sort); - unsigned getRelocOffset(); - void writeTo(uint8_t *Buf) override; + RelocationSection(StringRef name, bool sort); + void writeTo(uint8_t *buf) override; private: - bool Sort; + bool sort; }; template <class ELFT> class AndroidPackedRelocationSection final : public RelocationBaseSection { - typedef typename ELFT::Rel Elf_Rel; - typedef typename ELFT::Rela Elf_Rela; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; public: - AndroidPackedRelocationSection(StringRef Name); + AndroidPackedRelocationSection(StringRef name); bool updateAllocSize() override; - size_t getSize() const override { return RelocData.size(); } - void writeTo(uint8_t *Buf) override { - memcpy(Buf, RelocData.data(), RelocData.size()); + size_t getSize() const override { return relocData.size(); } + void writeTo(uint8_t *buf) override { + memcpy(buf, relocData.data(), relocData.size()); } private: - SmallVector<char, 0> RelocData; + SmallVector<char, 0> relocData; }; struct RelativeReloc { - uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); } + uint64_t getOffset() const { return inputSec->getVA(offsetInSec); } - const InputSectionBase *InputSec; - uint64_t OffsetInSec; + const InputSectionBase *inputSec; + uint64_t offsetInSec; }; class RelrBaseSection : public SyntheticSection { public: RelrBaseSection(); - bool empty() const override { return Relocs.empty(); } - std::vector<RelativeReloc> Relocs; + bool isNeeded() const override { return !relocs.empty(); } + std::vector<RelativeReloc> relocs; }; // RelrSection is used to encode offsets for relative relocations. @@ -543,65 +554,65 @@ public: // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg // For more details, see the comment in RelrSection::updateAllocSize(). template <class ELFT> class RelrSection final : public RelrBaseSection { - typedef typename ELFT::Relr Elf_Relr; + using Elf_Relr = typename ELFT::Relr; public: RelrSection(); bool updateAllocSize() override; - size_t getSize() const override { return RelrRelocs.size() * this->Entsize; } - void writeTo(uint8_t *Buf) override { - memcpy(Buf, RelrRelocs.data(), getSize()); + size_t getSize() const override { return relrRelocs.size() * this->entsize; } + void writeTo(uint8_t *buf) override { + memcpy(buf, relrRelocs.data(), getSize()); } private: - std::vector<Elf_Relr> RelrRelocs; + std::vector<Elf_Relr> relrRelocs; }; struct SymbolTableEntry { - Symbol *Sym; - size_t StrTabOffset; + Symbol *sym; + size_t strTabOffset; }; class SymbolTableBaseSection : public SyntheticSection { public: - SymbolTableBaseSection(StringTableSection &StrTabSec); + SymbolTableBaseSection(StringTableSection &strTabSec); void finalizeContents() override; - size_t getSize() const override { return getNumSymbols() * Entsize; } - void addSymbol(Symbol *Sym); - unsigned getNumSymbols() const { return Symbols.size() + 1; } - size_t getSymbolIndex(Symbol *Sym); - ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; } + size_t getSize() const override { return getNumSymbols() * entsize; } + void addSymbol(Symbol *sym); + unsigned getNumSymbols() const { return symbols.size() + 1; } + size_t getSymbolIndex(Symbol *sym); + ArrayRef<SymbolTableEntry> getSymbols() const { return symbols; } protected: void sortSymTabSymbols(); // A vector of symbols and their string table offsets. - std::vector<SymbolTableEntry> Symbols; + std::vector<SymbolTableEntry> symbols; - StringTableSection &StrTabSec; + StringTableSection &strTabSec; - llvm::once_flag OnceFlag; - llvm::DenseMap<Symbol *, size_t> SymbolIndexMap; - llvm::DenseMap<OutputSection *, size_t> SectionIndexMap; + llvm::once_flag onceFlag; + llvm::DenseMap<Symbol *, size_t> symbolIndexMap; + llvm::DenseMap<OutputSection *, size_t> sectionIndexMap; }; template <class ELFT> class SymbolTableSection final : public SymbolTableBaseSection { - typedef typename ELFT::Sym Elf_Sym; + using Elf_Sym = typename ELFT::Sym; public: - SymbolTableSection(StringTableSection &StrTabSec); - void writeTo(uint8_t *Buf) override; + SymbolTableSection(StringTableSection &strTabSec); + void writeTo(uint8_t *buf) override; }; class SymtabShndxSection final : public SyntheticSection { public: SymtabShndxSection(); - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; size_t getSize() const override; - bool empty() const override; + bool isNeeded() const override; void finalizeContents() override; }; @@ -611,42 +622,42 @@ class GnuHashTableSection final : public SyntheticSection { public: GnuHashTableSection(); void finalizeContents() override; - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } // Adds symbols to the hash table. // Sorts the input to satisfy GNU hash section requirements. - void addSymbols(std::vector<SymbolTableEntry> &Symbols); + void addSymbols(std::vector<SymbolTableEntry> &symbols); private: // See the comment in writeBloomFilter. enum { Shift2 = 26 }; - void writeBloomFilter(uint8_t *Buf); - void writeHashTable(uint8_t *Buf); + void writeBloomFilter(uint8_t *buf); + void writeHashTable(uint8_t *buf); struct Entry { - Symbol *Sym; - size_t StrTabOffset; - uint32_t Hash; - uint32_t BucketIdx; + Symbol *sym; + size_t strTabOffset; + uint32_t hash; + uint32_t bucketIdx; }; - std::vector<Entry> Symbols; - size_t MaskWords; - size_t NBuckets = 0; - size_t Size = 0; + std::vector<Entry> symbols; + size_t maskWords; + size_t nBuckets = 0; + size_t size = 0; }; class HashTableSection final : public SyntheticSection { public: HashTableSection(); void finalizeContents() override; - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } private: - size_t Size = 0; + size_t size = 0; }; // The PltSection is used for both the Plt and Iplt. The former usually has a @@ -655,67 +666,66 @@ private: // Target->IRelativeRel. class PltSection : public SyntheticSection { public: - PltSection(bool IsIplt); - void writeTo(uint8_t *Buf) override; + PltSection(bool isIplt); + void writeTo(uint8_t *buf) override; size_t getSize() const override; - bool empty() const override { return Entries.empty(); } + bool isNeeded() const override { return !entries.empty(); } void addSymbols(); - template <class ELFT> void addEntry(Symbol &Sym); + template <class ELFT> void addEntry(Symbol &sym); - size_t HeaderSize; + size_t headerSize; private: - unsigned getPltRelocOff() const; - std::vector<std::pair<const Symbol *, unsigned>> Entries; - bool IsIplt; + std::vector<const Symbol *> entries; + bool isIplt; }; class GdbIndexSection final : public SyntheticSection { public: struct AddressEntry { - InputSection *Section; - uint64_t LowAddress; - uint64_t HighAddress; - uint32_t CuIndex; + InputSection *section; + uint64_t lowAddress; + uint64_t highAddress; + uint32_t cuIndex; }; struct CuEntry { - uint64_t CuOffset; - uint64_t CuLength; + uint64_t cuOffset; + uint64_t cuLength; }; struct NameAttrEntry { - llvm::CachedHashStringRef Name; - uint32_t CuIndexAndAttrs; + llvm::CachedHashStringRef name; + uint32_t cuIndexAndAttrs; }; struct GdbChunk { - InputSection *Sec; - std::vector<AddressEntry> AddressAreas; - std::vector<CuEntry> CompilationUnits; + InputSection *sec; + std::vector<AddressEntry> addressAreas; + std::vector<CuEntry> compilationUnits; }; struct GdbSymbol { - llvm::CachedHashStringRef Name; - std::vector<uint32_t> CuVector; - uint32_t NameOff; - uint32_t CuVectorOff; + llvm::CachedHashStringRef name; + std::vector<uint32_t> cuVector; + uint32_t nameOff; + uint32_t cuVectorOff; }; GdbIndexSection(); template <typename ELFT> static GdbIndexSection *create(); - void writeTo(uint8_t *Buf) override; - size_t getSize() const override { return Size; } - bool empty() const override; + void writeTo(uint8_t *buf) override; + size_t getSize() const override { return size; } + bool isNeeded() const override; private: struct GdbIndexHeader { - llvm::support::ulittle32_t Version; - llvm::support::ulittle32_t CuListOff; - llvm::support::ulittle32_t CuTypesOff; - llvm::support::ulittle32_t AddressAreaOff; - llvm::support::ulittle32_t SymtabOff; - llvm::support::ulittle32_t ConstantPoolOff; + llvm::support::ulittle32_t version; + llvm::support::ulittle32_t cuListOff; + llvm::support::ulittle32_t cuTypesOff; + llvm::support::ulittle32_t addressAreaOff; + llvm::support::ulittle32_t symtabOff; + llvm::support::ulittle32_t constantPoolOff; }; void initOutputSize(); @@ -723,12 +733,12 @@ private: // Each chunk contains information gathered from debug sections of a // single object file. - std::vector<GdbChunk> Chunks; + std::vector<GdbChunk> chunks; // A symbol table for this .gdb_index section. - std::vector<GdbSymbol> Symbols; + std::vector<GdbSymbol> symbols; - size_t Size; + size_t size; }; // --eh-frame-hdr option tells linker to construct a header for all the @@ -743,9 +753,10 @@ private: class EhFrameHeader final : public SyntheticSection { public: EhFrameHeader(); - void writeTo(uint8_t *Buf) override; + void write(); + void writeTo(uint8_t *buf) override; size_t getSize() const override; - bool empty() const override; + bool isNeeded() const override; }; // For more information about .gnu.version and .gnu.version_r see: @@ -761,13 +772,15 @@ public: VersionDefinitionSection(); void finalizeContents() override; size_t getSize() const override; - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; private: enum { EntrySize = 28 }; - void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff); + void writeOne(uint8_t *buf, uint32_t index, StringRef name, size_t nameOff); + StringRef getFileDefName(); - unsigned FileDefNameOff; + unsigned fileDefNameOff; + std::vector<unsigned> verDefNameOffs; }; // The .gnu.version section specifies the required version of each symbol in the @@ -776,14 +789,13 @@ private: // 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 SyntheticSection { public: VersionTableSection(); void finalizeContents() override; size_t getSize() const override; - void writeTo(uint8_t *Buf) override; - bool empty() const override; + void writeTo(uint8_t *buf) override; + bool isNeeded() const override; }; // The .gnu.version_r section defines the version identifiers used by @@ -791,25 +803,30 @@ public: // 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 SyntheticSection { - typedef typename ELFT::Verneed Elf_Verneed; - typedef typename ELFT::Vernaux Elf_Vernaux; +template <class ELFT> +class VersionNeedSection final : public SyntheticSection { + using Elf_Verneed = typename ELFT::Verneed; + using Elf_Vernaux = typename ELFT::Vernaux; + + struct Vernaux { + uint64_t hash; + uint32_t verneedIndex; + uint64_t nameStrTab; + }; - // 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; + struct Verneed { + uint64_t nameStrTab; + std::vector<Vernaux> vernauxs; + }; - // The next available version identifier. - unsigned NextIndex; + std::vector<Verneed> verneeds; public: VersionNeedSection(); - void addSymbol(Symbol *Sym); void finalizeContents() override; - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; size_t getSize() const override; - size_t getNeedNum() const { return Needed.size(); } - bool empty() const override; + bool isNeeded() const override; }; // MergeSyntheticSection is a class that allows us to put mergeable sections @@ -818,36 +835,36 @@ public: // attached to regular output sections. class MergeSyntheticSection : public SyntheticSection { public: - void addSection(MergeInputSection *MS); - std::vector<MergeInputSection *> Sections; + void addSection(MergeInputSection *ms); + std::vector<MergeInputSection *> sections; protected: - MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, - uint32_t Alignment) - : SyntheticSection(Flags, Type, Alignment, Name) {} + MergeSyntheticSection(StringRef name, uint32_t type, uint64_t flags, + uint32_t alignment) + : SyntheticSection(flags, type, alignment, name) {} }; class MergeTailSection final : public MergeSyntheticSection { public: - MergeTailSection(StringRef Name, uint32_t Type, uint64_t Flags, - uint32_t Alignment); + MergeTailSection(StringRef name, uint32_t type, uint64_t flags, + uint32_t alignment); size_t getSize() const override; - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; void finalizeContents() override; private: - llvm::StringTableBuilder Builder; + llvm::StringTableBuilder builder; }; class MergeNoTailSection final : public MergeSyntheticSection { public: - MergeNoTailSection(StringRef Name, uint32_t Type, uint64_t Flags, - uint32_t Alignment) - : MergeSyntheticSection(Name, Type, Flags, Alignment) {} + MergeNoTailSection(StringRef name, uint32_t type, uint64_t flags, + uint32_t alignment) + : MergeSyntheticSection(name, type, flags, alignment) {} - size_t getSize() const override { return Size; } - void writeTo(uint8_t *Buf) override; + size_t getSize() const override { return size; } + void writeTo(uint8_t *buf) override; void finalizeContents() override; private: @@ -856,67 +873,68 @@ private: // because DenseMap also uses lower bits to determine a bucket ID. // If we use lower bits, it significantly increases the probability of // hash collisons. - size_t getShardId(uint32_t Hash) { - return Hash >> (32 - llvm::countTrailingZeros(NumShards)); + size_t getShardId(uint32_t hash) { + assert((hash >> 31) == 0); + return hash >> (31 - llvm::countTrailingZeros(numShards)); } // Section size - size_t Size; + size_t size; // String table contents - constexpr static size_t NumShards = 32; - std::vector<llvm::StringTableBuilder> Shards; - size_t ShardOffsets[NumShards]; + constexpr static size_t numShards = 32; + std::vector<llvm::StringTableBuilder> shards; + size_t shardOffsets[numShards]; }; // .MIPS.abiflags section. template <class ELFT> class MipsAbiFlagsSection final : public SyntheticSection { - typedef llvm::object::Elf_Mips_ABIFlags<ELFT> Elf_Mips_ABIFlags; + using Elf_Mips_ABIFlags = llvm::object::Elf_Mips_ABIFlags<ELFT>; public: static MipsAbiFlagsSection *create(); - MipsAbiFlagsSection(Elf_Mips_ABIFlags Flags); + MipsAbiFlagsSection(Elf_Mips_ABIFlags flags); size_t getSize() const override { return sizeof(Elf_Mips_ABIFlags); } - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; private: - Elf_Mips_ABIFlags Flags; + Elf_Mips_ABIFlags flags; }; // .MIPS.options section. template <class ELFT> class MipsOptionsSection final : public SyntheticSection { - typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options; - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; + using Elf_Mips_Options = llvm::object::Elf_Mips_Options<ELFT>; + using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>; public: static MipsOptionsSection *create(); - MipsOptionsSection(Elf_Mips_RegInfo Reginfo); - void writeTo(uint8_t *Buf) override; + MipsOptionsSection(Elf_Mips_RegInfo reginfo); + void writeTo(uint8_t *buf) override; size_t getSize() const override { return sizeof(Elf_Mips_Options) + sizeof(Elf_Mips_RegInfo); } private: - Elf_Mips_RegInfo Reginfo; + Elf_Mips_RegInfo reginfo; }; // MIPS .reginfo section. template <class ELFT> class MipsReginfoSection final : public SyntheticSection { - typedef llvm::object::Elf_Mips_RegInfo<ELFT> Elf_Mips_RegInfo; + using Elf_Mips_RegInfo = llvm::object::Elf_Mips_RegInfo<ELFT>; public: static MipsReginfoSection *create(); - MipsReginfoSection(Elf_Mips_RegInfo Reginfo); + MipsReginfoSection(Elf_Mips_RegInfo reginfo); size_t getSize() const override { return sizeof(Elf_Mips_RegInfo); } - void writeTo(uint8_t *Buf) override; + void writeTo(uint8_t *buf) override; private: - Elf_Mips_RegInfo Reginfo; + Elf_Mips_RegInfo reginfo; }; // This is a MIPS specific section to hold a space within the data segment @@ -926,45 +944,115 @@ private: class MipsRldMapSection : public SyntheticSection { public: MipsRldMapSection(); - size_t getSize() const override { return Config->Wordsize; } - void writeTo(uint8_t *Buf) override {} + size_t getSize() const override { return config->wordsize; } + void writeTo(uint8_t *buf) override {} }; -class ARMExidxSentinelSection : public SyntheticSection { +// Representation of the combined .ARM.Exidx input sections. We process these +// as a SyntheticSection like .eh_frame as we need to merge duplicate entries +// and add terminating sentinel entries. +// +// The .ARM.exidx input sections after SHF_LINK_ORDER processing is done form +// a table that the unwinder can derive (Addresses are encoded as offsets from +// table): +// | Address of function | Unwind instructions for function | +// where the unwind instructions are either a small number of unwind or the +// special EXIDX_CANTUNWIND entry representing no unwinding information. +// When an exception is thrown from an address A, the unwinder searches the +// table for the closest table entry with Address of function <= A. This means +// that for two consecutive table entries: +// | A1 | U1 | +// | A2 | U2 | +// The range of addresses described by U1 is [A1, A2) +// +// There are two cases where we need a linker generated table entry to fixup +// the address ranges in the table +// Case 1: +// - A sentinel entry added with an address higher than all +// executable sections. This was needed to work around libunwind bug pr31091. +// - After address assignment we need to find the highest addressed executable +// section and use the limit of that section so that the unwinder never +// matches it. +// Case 2: +// - InputSections without a .ARM.exidx section (usually from Assembly) +// need a table entry so that they terminate the range of the previously +// function. This is pr40277. +// +// Instead of storing pointers to the .ARM.exidx InputSections from +// InputObjects, we store pointers to the executable sections that need +// .ARM.exidx sections. We can then use the dependentSections of these to +// either find the .ARM.exidx section or know that we need to generate one. +class ARMExidxSyntheticSection : public SyntheticSection { public: - ARMExidxSentinelSection(); - size_t getSize() const override { return 8; } - void writeTo(uint8_t *Buf) override; - bool empty() const override; + ARMExidxSyntheticSection(); + + // Add an input section to the ARMExidxSyntheticSection. Returns whether the + // section needs to be removed from the main input section list. + bool addSection(InputSection *isec); - static bool classof(const SectionBase *D); + size_t getSize() const override { return size; } + void writeTo(uint8_t *buf) override; + bool isNeeded() const override { return !empty; } + // Sort and remove duplicate entries. + void finalizeContents() override; + InputSection *getLinkOrderDep() const; + + static bool classof(const SectionBase *d); + + // Links to the ARMExidxSections so we can transfer the relocations once the + // layout is known. + std::vector<InputSection *> exidxSections; - // The last section referenced by a regular .ARM.exidx section. - // It is found and filled in Writer<ELFT>::resolveShfLinkOrder(). - // The sentinel points at the end of that section. - InputSection *Highest = nullptr; +private: + size_t size; + + // Empty if ExecutableSections contains no dependent .ARM.exidx sections. + bool empty = true; + + // Instead of storing pointers to the .ARM.exidx InputSections from + // InputObjects, we store pointers to the executable sections that need + // .ARM.exidx sections. We can then use the dependentSections of these to + // either find the .ARM.exidx section or know that we need to generate one. + std::vector<InputSection *> executableSections; + + // The executable InputSection with the highest address to use for the + // sentinel. We store separately from ExecutableSections as merging of + // duplicate entries may mean this InputSection is removed from + // ExecutableSections. + InputSection *sentinel = nullptr; }; // A container for one or more linker generated thunks. Instances of these // thunks including ARM interworking and Mips LA25 PI to non-PI thunks. class ThunkSection : public SyntheticSection { public: - // ThunkSection in OS, with desired OutSecOff of Off - ThunkSection(OutputSection *OS, uint64_t Off); + // ThunkSection in OS, with desired outSecOff of Off + ThunkSection(OutputSection *os, uint64_t off); // Add a newly created Thunk to this container: // Thunk is given offset from start of this InputSection // Thunk defines a symbol in this InputSection that can be used as target // of a relocation - void addThunk(Thunk *T); - size_t getSize() const override { return Size; } - void writeTo(uint8_t *Buf) override; + void addThunk(Thunk *t); + size_t getSize() const override { return size; } + void writeTo(uint8_t *buf) override; InputSection *getTargetInputSection() const; bool assignOffsets(); private: - std::vector<Thunk *> Thunks; - size_t Size = 0; + std::vector<Thunk *> thunks; + size_t size = 0; +}; + +// Used to compute outSecOff of .got2 in each object file. This is needed to +// synthesize PLT entries for PPC32 Secure PLT ABI. +class PPC32Got2Section final : public SyntheticSection { +public: + PPC32Got2Section(); + size_t getSize() const override { return 0; } + bool isNeeded() const override; + void finalizeContents() override; + void writeTo(uint8_t *buf) override {} }; // This section is used to store the addresses of functions that are called @@ -975,15 +1063,48 @@ private: class PPC64LongBranchTargetSection final : public SyntheticSection { public: PPC64LongBranchTargetSection(); - void addEntry(Symbol &Sym); + void addEntry(Symbol &sym); size_t getSize() const override; - void writeTo(uint8_t *Buf) override; - bool empty() const override; - void finalizeContents() override { Finalized = true; } + void writeTo(uint8_t *buf) override; + bool isNeeded() const override; + void finalizeContents() override { finalized = true; } private: - std::vector<const Symbol *> Entries; - bool Finalized = false; + std::vector<const Symbol *> entries; + bool finalized = false; +}; + +template <typename ELFT> +class PartitionElfHeaderSection : public SyntheticSection { +public: + PartitionElfHeaderSection(); + size_t getSize() const override; + void writeTo(uint8_t *buf) override; +}; + +template <typename ELFT> +class PartitionProgramHeadersSection : public SyntheticSection { +public: + PartitionProgramHeadersSection(); + size_t getSize() const override; + void writeTo(uint8_t *buf) override; +}; + +class PartitionIndexSection : public SyntheticSection { +public: + PartitionIndexSection(); + size_t getSize() const override; + void finalizeContents() override; + void writeTo(uint8_t *buf) override; +}; + +// Create a dummy .sdata for __global_pointer$ if .sdata does not exist. +class RISCVSdataSection final : public SyntheticSection { +public: + RISCVSdataSection(); + size_t getSize() const override { return 0; } + bool isNeeded() const override; + void writeTo(uint8_t *buf) override {} }; InputSection *createInterpSection(); @@ -991,52 +1112,76 @@ MergeInputSection *createCommentSection(); template <class ELFT> void splitSections(); void mergeSections(); -Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section); - -// Linker generated sections which can be used as inputs. -struct InStruct { - InputSection *ARMAttributes; - BssSection *Bss; - BssSection *BssRelRo; - BuildIdSection *BuildId; - EhFrameHeader *EhFrameHdr; - EhFrameSection *EhFrame; - SyntheticSection *Dynamic; - StringTableSection *DynStrTab; - SymbolTableBaseSection *DynSymTab; - GnuHashTableSection *GnuHashTab; - HashTableSection *HashTab; - InputSection *Interp; - GdbIndexSection *GdbIndex; - GotSection *Got; - GotPltSection *GotPlt; - IgotPltSection *IgotPlt; - PPC64LongBranchTargetSection *PPC64LongBranchTarget; - MipsGotSection *MipsGot; - MipsRldMapSection *MipsRldMap; - PltSection *Plt; - PltSection *Iplt; - RelocationBaseSection *RelaDyn; - RelrBaseSection *RelrDyn; - RelocationBaseSection *RelaPlt; - RelocationBaseSection *RelaIplt; - StringTableSection *ShStrTab; - StringTableSection *StrTab; - SymbolTableBaseSection *SymTab; - SymtabShndxSection *SymTabShndx; - VersionDefinitionSection *VerDef; +template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part); +template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part); + +Defined *addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, + uint64_t size, InputSectionBase §ion); + +void addVerneed(Symbol *ss); + +// Linker generated per-partition sections. +struct Partition { + StringRef name; + uint64_t nameStrTab; + + SyntheticSection *elfHeader; + SyntheticSection *programHeaders; + std::vector<PhdrEntry *> phdrs; + + ARMExidxSyntheticSection *armExidx; + BuildIdSection *buildId; + SyntheticSection *dynamic; + StringTableSection *dynStrTab; + SymbolTableBaseSection *dynSymTab; + EhFrameHeader *ehFrameHdr; + EhFrameSection *ehFrame; + GnuHashTableSection *gnuHashTab; + HashTableSection *hashTab; + RelocationBaseSection *relaDyn; + RelrBaseSection *relrDyn; + VersionDefinitionSection *verDef; + SyntheticSection *verNeed; + VersionTableSection *verSym; + + unsigned getNumber() const { return this - &partitions[0] + 1; } }; -extern InStruct In; +extern Partition *mainPart; -template <class ELFT> struct InX { - static VersionTableSection<ELFT> *VerSym; - static VersionNeedSection<ELFT> *VerNeed; +inline Partition &SectionBase::getPartition() const { + assert(isLive()); + return partitions[partition - 1]; +} + +// Linker generated sections which can be used as inputs and are not specific to +// a partition. +struct InStruct { + InputSection *armAttributes; + BssSection *bss; + BssSection *bssRelRo; + GotSection *got; + GotPltSection *gotPlt; + IgotPltSection *igotPlt; + PPC64LongBranchTargetSection *ppc64LongBranchTarget; + MipsGotSection *mipsGot; + MipsRldMapSection *mipsRldMap; + SyntheticSection *partEnd; + SyntheticSection *partIndex; + PltSection *plt; + PltSection *iplt; + PPC32Got2Section *ppc32Got2; + RISCVSdataSection *riscvSdata; + RelocationBaseSection *relaPlt; + RelocationBaseSection *relaIplt; + StringTableSection *shStrTab; + StringTableSection *strTab; + SymbolTableBaseSection *symTab; + SymtabShndxSection *symTabShndx; }; -template <class ELFT> VersionTableSection<ELFT> *InX<ELFT>::VerSym; -template <class ELFT> VersionNeedSection<ELFT> *InX<ELFT>::VerNeed; +extern InStruct in; + } // namespace elf } // namespace lld |