diff options
Diffstat (limited to 'ELF/InputFiles.h')
-rw-r--r-- | ELF/InputFiles.h | 358 |
1 files changed, 190 insertions, 168 deletions
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 5094ddd804a5f..5ccc3d402b376 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -1,9 +1,8 @@ //===- InputFiles.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 // //===----------------------------------------------------------------------===// @@ -40,7 +39,7 @@ class InputSectionBase; } // Returns "<internal>", "foo.a(bar.o)" or "baz.o". -std::string toString(const elf::InputFile *F); +std::string toString(const elf::InputFile *f); namespace elf { @@ -50,10 +49,13 @@ class Symbol; // If -reproduce option is given, all input files are written // to this tar archive. -extern std::unique_ptr<llvm::TarWriter> Tar; +extern std::unique_ptr<llvm::TarWriter> tar; // Opens a given file. -llvm::Optional<MemoryBufferRef> readFile(StringRef Path); +llvm::Optional<MemoryBufferRef> readFile(StringRef path); + +// Add symbols in File to the symbol table. +void parseFile(InputFile *file); // The root class of input files. class InputFile { @@ -67,192 +69,230 @@ public: BinaryKind, }; - Kind kind() const { return FileKind; } + Kind kind() const { return fileKind; } bool isElf() const { - Kind K = kind(); - return K == ObjKind || K == SharedKind; + Kind k = kind(); + return k == ObjKind || k == SharedKind; } - StringRef getName() const { return MB.getBufferIdentifier(); } - MemoryBufferRef MB; + StringRef getName() const { return mb.getBufferIdentifier(); } + MemoryBufferRef mb; // Returns sections. It is a runtime error to call this function // on files that don't have the notion of sections. ArrayRef<InputSectionBase *> getSections() const { - assert(FileKind == ObjKind || FileKind == BinaryKind); - return Sections; + assert(fileKind == ObjKind || fileKind == BinaryKind); + return sections; } // Returns object file symbols. It is a runtime error to call this // function on files of other types. ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); } - std::vector<Symbol *> &getMutableSymbols() { - assert(FileKind == BinaryKind || FileKind == ObjKind || - FileKind == BitcodeKind); - return Symbols; + MutableArrayRef<Symbol *> getMutableSymbols() { + assert(fileKind == BinaryKind || fileKind == ObjKind || + fileKind == BitcodeKind); + return symbols; } // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. - std::string ArchiveName; + std::string archiveName; // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. - ELFKind EKind = ELFNoneKind; - uint16_t EMachine = llvm::ELF::EM_NONE; - uint8_t OSABI = 0; + ELFKind ekind = ELFNoneKind; + uint16_t emachine = llvm::ELF::EM_NONE; + uint8_t osabi = 0; + uint8_t abiVersion = 0; // Cache for toString(). Only toString() should use this member. - mutable std::string ToStringCache; + mutable std::string toStringCache; - std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, - uint64_t Offset); + std::string getSrcMsg(const Symbol &sym, InputSectionBase &sec, + uint64_t offset); // True if this is an argument for --just-symbols. Usually false. - bool JustSymbols = false; - - // GroupId is used for --warn-backrefs which is an optional error + bool justSymbols = false; + + // outSecOff of .got2 in the current file. This is used by PPC32 -fPIC/-fPIE + // to compute offsets in PLT call stubs. + uint32_t ppc32Got2OutSecOff = 0; + + // On PPC64 we need to keep track of which files contain small code model + // relocations that access the .toc section. To minimize the chance of a + // relocation overflow, files that do contain said relocations should have + // their .toc sections sorted closer to the .got section than files that do + // not contain any small code model relocations. Thats because the toc-pointer + // is defined to point at .got + 0x8000 and the instructions used with small + // code model relocations support immediates in the range [-0x8000, 0x7FFC], + // making the addressable range relative to the toc pointer + // [.got, .got + 0xFFFC]. + bool ppc64SmallCodeModelTocRelocs = false; + + // groupId is used for --warn-backrefs which is an optional error // checking feature. All files within the same --{start,end}-group or // --{start,end}-lib get the same group ID. Otherwise, each file gets a new // group ID. For more info, see checkDependency() in SymbolTable.cpp. - uint32_t GroupId; - static bool IsInGroup; - static uint32_t NextGroupId; + uint32_t groupId; + static bool isInGroup; + static uint32_t nextGroupId; // Index of MIPS GOT built for this file. - llvm::Optional<size_t> MipsGotIndex; + llvm::Optional<size_t> mipsGotIndex; + + std::vector<Symbol *> symbols; protected: - InputFile(Kind K, MemoryBufferRef M); - std::vector<InputSectionBase *> Sections; - std::vector<Symbol *> Symbols; + InputFile(Kind k, MemoryBufferRef m); + std::vector<InputSectionBase *> sections; private: - const Kind FileKind; + const Kind fileKind; }; -template <typename ELFT> class ELFFileBase : public InputFile { +class ELFFileBase : public InputFile { public: - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::Word Elf_Word; - typedef typename ELFT::SymRange Elf_Sym_Range; + ELFFileBase(Kind k, MemoryBufferRef m); + static bool classof(const InputFile *f) { return f->isElf(); } - ELFFileBase(Kind K, MemoryBufferRef M); - static bool classof(const InputFile *F) { return F->isElf(); } - - llvm::object::ELFFile<ELFT> getObj() const { - return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer())); + template <typename ELFT> llvm::object::ELFFile<ELFT> getObj() const { + return check(llvm::object::ELFFile<ELFT>::create(mb.getBuffer())); } - StringRef getStringTable() const { return StringTable; } - - uint32_t getSectionIndex(const Elf_Sym &Sym) const; + StringRef getStringTable() const { return stringTable; } - Elf_Sym_Range getGlobalELFSyms(); - Elf_Sym_Range getELFSyms() const { return ELFSyms; } + template <typename ELFT> typename ELFT::SymRange getELFSyms() const { + return typename ELFT::SymRange( + reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms); + } + template <typename ELFT> typename ELFT::SymRange getGlobalELFSyms() const { + return getELFSyms<ELFT>().slice(firstGlobal); + } protected: - ArrayRef<Elf_Sym> ELFSyms; - uint32_t FirstGlobal = 0; - ArrayRef<Elf_Word> SymtabSHNDX; - StringRef StringTable; - void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab); + // Initializes this class's member variables. + template <typename ELFT> void init(); + + const void *elfSyms = nullptr; + size_t numELFSyms = 0; + uint32_t firstGlobal = 0; + StringRef stringTable; }; // .o file. -template <class ELFT> class ObjFile : public ELFFileBase<ELFT> { - typedef ELFFileBase<ELFT> Base; - typedef typename ELFT::Rel Elf_Rel; - typedef typename ELFT::Rela Elf_Rela; - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Word Elf_Word; - typedef typename ELFT::CGProfile Elf_CGProfile; - - StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, - const Elf_Shdr &Sec); - ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec); +template <class ELFT> class ObjFile : public ELFFileBase { + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Sym = typename ELFT::Sym; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Word = typename ELFT::Word; + using Elf_CGProfile = typename ELFT::CGProfile; public: - static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } + static bool classof(const InputFile *f) { return f->kind() == ObjKind; } + + llvm::object::ELFFile<ELFT> getObj() const { + return this->ELFFileBase::getObj<ELFT>(); + } ArrayRef<Symbol *> getLocalSymbols(); ArrayRef<Symbol *> getGlobalSymbols(); - ObjFile(MemoryBufferRef M, StringRef ArchiveName); - void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); + ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) { + this->archiveName = archiveName; + } + + void parse(bool ignoreComdats = false); - Symbol &getSymbol(uint32_t SymbolIndex) const { - if (SymbolIndex >= this->Symbols.size()) + StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> sections, + const Elf_Shdr &sec); + + Symbol &getSymbol(uint32_t symbolIndex) const { + if (symbolIndex >= this->symbols.size()) fatal(toString(this) + ": invalid symbol index"); - return *this->Symbols[SymbolIndex]; + return *this->symbols[symbolIndex]; } - template <typename RelT> Symbol &getRelocTargetSym(const RelT &Rel) const { - uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); - return getSymbol(SymIndex); + uint32_t getSectionIndex(const Elf_Sym &sym) const; + + template <typename RelT> Symbol &getRelocTargetSym(const RelT &rel) const { + uint32_t symIndex = rel.getSymbol(config->isMips64EL); + return getSymbol(symIndex); } llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t); - llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name); + llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef name); // MIPS GP0 value defined by this file. This value represents the gp value // used to create the relocatable object and required to support // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. - uint32_t MipsGp0 = 0; + uint32_t mipsGp0 = 0; + + uint32_t andFeatures = 0; // Name of source file obtained from STT_FILE symbol value, // or empty string if there is no such symbol in object file // symbol table. - StringRef SourceFile; + StringRef sourceFile; // True if the file defines functions compiled with // -fsplit-stack. Usually false. - bool SplitStack = false; + bool splitStack = false; // True if the file defines functions compiled with -fsplit-stack, // but had one or more functions with the no_split_stack attribute. - bool SomeNoSplitStack = false; + bool someNoSplitStack = false; // Pointer to this input file's .llvm_addrsig section, if it has one. - const Elf_Shdr *AddrsigSec = nullptr; + const Elf_Shdr *addrsigSec = nullptr; // SHT_LLVM_CALL_GRAPH_PROFILE table - ArrayRef<Elf_CGProfile> CGProfile; + ArrayRef<Elf_CGProfile> cgProfile; private: - void - initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); + void initializeSections(bool ignoreComdats); void initializeSymbols(); void initializeJustSymbols(); void initializeDwarf(); - InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); - InputSectionBase *createInputSection(const Elf_Shdr &Sec); - StringRef getSectionName(const Elf_Shdr &Sec); - - bool shouldMerge(const Elf_Shdr &Sec); - Symbol *createSymbol(const Elf_Sym *Sym); + InputSectionBase *getRelocTarget(const Elf_Shdr &sec); + InputSectionBase *createInputSection(const Elf_Shdr &sec); + StringRef getSectionName(const Elf_Shdr &sec); + + bool shouldMerge(const Elf_Shdr &sec); + + // Each ELF symbol contains a section index which the symbol belongs to. + // However, because the number of bits dedicated for that is limited, a + // symbol can directly point to a section only when the section index is + // equal to or smaller than 65280. + // + // If an object file contains more than 65280 sections, the file must + // contain .symtab_shndx section. The section contains an array of + // 32-bit integers whose size is the same as the number of symbols. + // Nth symbol's section index is in the Nth entry of .symtab_shndx. + // + // The following variable contains the contents of .symtab_shndx. + // If the section does not exist (which is common), the array is empty. + ArrayRef<Elf_Word> shndxTable; // .shstrtab contents. - StringRef SectionStringTable; + StringRef sectionStringTable; // Debugging information to retrieve source file and line for error // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. - std::unique_ptr<llvm::DWARFContext> Dwarf; - std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables; + std::unique_ptr<llvm::DWARFContext> dwarf; + std::vector<const llvm::DWARFDebugLine::LineTable *> lineTables; struct VarLoc { - const llvm::DWARFDebugLine::LineTable *LT; - unsigned File; - unsigned Line; + const llvm::DWARFDebugLine::LineTable *lt; + unsigned file; + unsigned line; }; - llvm::DenseMap<StringRef, VarLoc> VariableLoc; - llvm::once_flag InitDwarfLine; + llvm::DenseMap<StringRef, VarLoc> variableLoc; + llvm::once_flag initDwarfLine; }; // LazyObjFile is analogous to ArchiveFile in the sense that @@ -264,118 +304,100 @@ private: // archive file semantics. class LazyObjFile : public InputFile { public: - LazyObjFile(MemoryBufferRef M, StringRef ArchiveName, - uint64_t OffsetInArchive) - : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) { - this->ArchiveName = ArchiveName; + LazyObjFile(MemoryBufferRef m, StringRef archiveName, + uint64_t offsetInArchive) + : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) { + this->archiveName = archiveName; } - static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; } + static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; } template <class ELFT> void parse(); - MemoryBufferRef getBuffer(); - InputFile *fetch(); - bool AddedToLink = false; + void fetch(); private: - uint64_t OffsetInArchive; + uint64_t offsetInArchive; }; // An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: - explicit ArchiveFile(std::unique_ptr<Archive> &&File); - static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - template <class ELFT> void parse(); + explicit ArchiveFile(std::unique_ptr<Archive> &&file); + static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } + void parse(); // Pulls out an object file that contains a definition for Sym and // returns it. If the same file was instantiated before, this - // function returns a nullptr (so we don't instantiate the same file + // function does nothing (so we don't instantiate the same file // more than once.) - InputFile *fetch(const Archive::Symbol &Sym); + void fetch(const Archive::Symbol &sym); private: - std::unique_ptr<Archive> File; - llvm::DenseSet<uint64_t> Seen; + std::unique_ptr<Archive> file; + llvm::DenseSet<uint64_t> seen; }; class BitcodeFile : public InputFile { public: - BitcodeFile(MemoryBufferRef M, StringRef ArchiveName, - uint64_t OffsetInArchive); - static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - template <class ELFT> - void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); - std::unique_ptr<llvm::lto::InputFile> Obj; + BitcodeFile(MemoryBufferRef m, StringRef archiveName, + uint64_t offsetInArchive); + static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } + template <class ELFT> void parse(); + std::unique_ptr<llvm::lto::InputFile> obj; }; // .so file. -template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { - typedef ELFFileBase<ELFT> Base; - typedef typename ELFT::Dyn Elf_Dyn; - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::SymRange Elf_Sym_Range; - typedef typename ELFT::Verdef Elf_Verdef; - typedef typename ELFT::Versym Elf_Versym; - - const Elf_Shdr *VersymSec = nullptr; - const Elf_Shdr *VerdefSec = nullptr; - +class SharedFile : public ELFFileBase { public: - std::vector<const Elf_Verdef *> Verdefs; - std::string SoName; + SharedFile(MemoryBufferRef m, StringRef defaultSoName) + : ELFFileBase(SharedKind, m), soName(defaultSoName), + isNeeded(!config->asNeeded) {} - static bool classof(const InputFile *F) { - return F->kind() == Base::SharedKind; - } + // This is actually a vector of Elf_Verdef pointers. + std::vector<const void *> verdefs; - SharedFile(MemoryBufferRef M, StringRef DefaultSoName); + // If the output file needs Elf_Verneed data structures for this file, this is + // a vector of Elf_Vernaux version identifiers that map onto the entries in + // Verdefs, otherwise it is empty. + std::vector<unsigned> vernauxs; - void parseSoName(); - void parseRest(); - uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym); - std::vector<const Elf_Verdef *> parseVerdefs(); - std::vector<uint32_t> parseVersyms(); + static unsigned vernauxNum; - struct NeededVer { - // The string table offset of the version name in the output file. - size_t StrTab; + std::vector<StringRef> dtNeeded; + std::string soName; - // The version identifier for this version name. - uint16_t Index; - }; + static bool classof(const InputFile *f) { return f->kind() == SharedKind; } + + template <typename ELFT> void parse(); - // Mapping from Elf_Verdef data structures to information about Elf_Vernaux - // data structures in the output file. - std::map<const Elf_Verdef *, NeededVer> VerdefMap; + // Used for --no-allow-shlib-undefined. + bool allNeededIsKnown; // Used for --as-needed - bool IsNeeded; + bool isNeeded; }; class BinaryFile : public InputFile { public: - explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} - static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } + explicit BinaryFile(MemoryBufferRef m) : InputFile(BinaryKind, m) {} + static bool classof(const InputFile *f) { return f->kind() == BinaryKind; } void parse(); }; -InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", - uint64_t OffsetInArchive = 0); -InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); +InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "", + uint64_t offsetInArchive = 0); -inline bool isBitcode(MemoryBufferRef MB) { - return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode; +inline bool isBitcode(MemoryBufferRef mb) { + return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; } -std::string replaceThinLTOSuffix(StringRef Path); +std::string replaceThinLTOSuffix(StringRef path); -extern std::vector<BinaryFile *> BinaryFiles; -extern std::vector<BitcodeFile *> BitcodeFiles; -extern std::vector<LazyObjFile *> LazyObjFiles; -extern std::vector<InputFile *> ObjectFiles; -extern std::vector<InputFile *> SharedFiles; +extern std::vector<BinaryFile *> binaryFiles; +extern std::vector<BitcodeFile *> bitcodeFiles; +extern std::vector<LazyObjFile *> lazyObjFiles; +extern std::vector<InputFile *> objectFiles; +extern std::vector<SharedFile *> sharedFiles; } // namespace elf } // namespace lld |