|  | //===- InputFiles.h ---------------------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                             The LLVM Linker | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLD_ELF_INPUT_FILES_H | 
|  | #define LLD_ELF_INPUT_FILES_H | 
|  |  | 
|  | #include "Config.h" | 
|  | #include "lld/Common/ErrorHandler.h" | 
|  | #include "lld/Common/LLVM.h" | 
|  | #include "lld/Common/Reproduce.h" | 
|  | #include "llvm/ADT/CachedHashString.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" | 
|  | #include "llvm/IR/Comdat.h" | 
|  | #include "llvm/Object/Archive.h" | 
|  | #include "llvm/Object/ELF.h" | 
|  | #include "llvm/Object/IRObjectFile.h" | 
|  | #include "llvm/Support/Threading.h" | 
|  | #include <map> | 
|  |  | 
|  | namespace llvm { | 
|  | class TarWriter; | 
|  | struct DILineInfo; | 
|  | namespace lto { | 
|  | class InputFile; | 
|  | } | 
|  | } // namespace llvm | 
|  |  | 
|  | namespace lld { | 
|  | namespace elf { | 
|  | class InputFile; | 
|  | class InputSectionBase; | 
|  | } | 
|  |  | 
|  | // Returns "<internal>", "foo.a(bar.o)" or "baz.o". | 
|  | std::string toString(const elf::InputFile *F); | 
|  |  | 
|  | namespace elf { | 
|  |  | 
|  | using llvm::object::Archive; | 
|  |  | 
|  | class Symbol; | 
|  |  | 
|  | // If -reproduce option is given, all input files are written | 
|  | // to this tar archive. | 
|  | extern llvm::TarWriter *Tar; | 
|  |  | 
|  | // Opens a given file. | 
|  | llvm::Optional<MemoryBufferRef> readFile(StringRef Path); | 
|  |  | 
|  | // The root class of input files. | 
|  | class InputFile { | 
|  | public: | 
|  | enum Kind { | 
|  | ObjKind, | 
|  | SharedKind, | 
|  | LazyObjKind, | 
|  | ArchiveKind, | 
|  | BitcodeKind, | 
|  | BinaryKind, | 
|  | }; | 
|  |  | 
|  | Kind kind() const { return FileKind; } | 
|  |  | 
|  | bool isElf() const { | 
|  | Kind K = kind(); | 
|  | return K == ObjKind || K == SharedKind; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | // Returns object file symbols. It is a runtime error to call this | 
|  | // function on files of other types. | 
|  | ArrayRef<Symbol *> getSymbols() { | 
|  | 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; | 
|  |  | 
|  | // 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; | 
|  |  | 
|  | // Cache for toString(). Only toString() should use this member. | 
|  | mutable std::string ToStringCache; | 
|  |  | 
|  | 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 | 
|  | // 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; | 
|  |  | 
|  | // Index of MIPS GOT built for this file. | 
|  | llvm::Optional<size_t> MipsGotIndex; | 
|  |  | 
|  | protected: | 
|  | InputFile(Kind K, MemoryBufferRef M); | 
|  | std::vector<InputSectionBase *> Sections; | 
|  | std::vector<Symbol *> Symbols; | 
|  |  | 
|  | private: | 
|  | const Kind FileKind; | 
|  | }; | 
|  |  | 
|  | template <typename ELFT> 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(); } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | Elf_Sym_Range getGlobalELFSyms(); | 
|  | Elf_Sym_Range getELFSyms() const { return ELFSyms; } | 
|  |  | 
|  | 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); | 
|  | }; | 
|  |  | 
|  | // .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; | 
|  |  | 
|  | StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, | 
|  | const Elf_Shdr &Sec); | 
|  | ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec); | 
|  |  | 
|  | public: | 
|  | static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } | 
|  |  | 
|  | ArrayRef<Symbol *> getLocalSymbols(); | 
|  | ArrayRef<Symbol *> getGlobalSymbols(); | 
|  |  | 
|  | ObjFile(MemoryBufferRef M, StringRef ArchiveName); | 
|  | void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); | 
|  |  | 
|  | Symbol &getSymbol(uint32_t SymbolIndex) const { | 
|  | if (SymbolIndex >= this->Symbols.size()) | 
|  | fatal(toString(this) + ": invalid symbol index"); | 
|  | return *this->Symbols[SymbolIndex]; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | // 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; | 
|  |  | 
|  | // 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; | 
|  |  | 
|  | // True if the file defines functions compiled with | 
|  | // -fsplit-stack. Usually 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; | 
|  |  | 
|  | // Pointer to this input file's .llvm_addrsig section, if it has one. | 
|  | const Elf_Shdr *AddrsigSec = nullptr; | 
|  |  | 
|  | private: | 
|  | void | 
|  | initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); | 
|  | 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); | 
|  |  | 
|  | // .shstrtab contents. | 
|  | 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; | 
|  | struct VarLoc { | 
|  | const llvm::DWARFDebugLine::LineTable *LT; | 
|  | unsigned File; | 
|  | unsigned Line; | 
|  | }; | 
|  | llvm::DenseMap<StringRef, VarLoc> VariableLoc; | 
|  | llvm::once_flag InitDwarfLine; | 
|  | }; | 
|  |  | 
|  | // LazyObjFile is analogous to ArchiveFile in the sense that | 
|  | // the file contains lazy symbols. The difference is that | 
|  | // LazyObjFile wraps a single file instead of multiple files. | 
|  | // | 
|  | // This class is used for --start-lib and --end-lib options which | 
|  | // instruct the linker to link object files between them with the | 
|  | // archive file semantics. | 
|  | class LazyObjFile : public InputFile { | 
|  | public: | 
|  | 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; } | 
|  |  | 
|  | template <class ELFT> void parse(); | 
|  | MemoryBufferRef getBuffer(); | 
|  | InputFile *fetch(); | 
|  | bool AddedToLink = false; | 
|  |  | 
|  | private: | 
|  | template <class ELFT> void addElfSymbols(); | 
|  |  | 
|  | 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(); | 
|  |  | 
|  | // 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 | 
|  | // more than once.) | 
|  | InputFile *fetch(const Archive::Symbol &Sym); | 
|  |  | 
|  | private: | 
|  | 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; | 
|  | }; | 
|  |  | 
|  | // .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; | 
|  |  | 
|  | public: | 
|  | std::vector<const Elf_Verdef *> Verdefs; | 
|  | std::string SoName; | 
|  |  | 
|  | static bool classof(const InputFile *F) { | 
|  | return F->kind() == Base::SharedKind; | 
|  | } | 
|  |  | 
|  | SharedFile(MemoryBufferRef M, StringRef DefaultSoName); | 
|  |  | 
|  | 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(); | 
|  |  | 
|  | struct NeededVer { | 
|  | // The string table offset of the version name in the output file. | 
|  | size_t StrTab; | 
|  |  | 
|  | // The version identifier for this version name. | 
|  | uint16_t Index; | 
|  | }; | 
|  |  | 
|  | // 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 --as-needed | 
|  | bool IsNeeded; | 
|  | }; | 
|  |  | 
|  | class BinaryFile : public InputFile { | 
|  | public: | 
|  | 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); | 
|  |  | 
|  | inline bool isBitcode(MemoryBufferRef MB) { | 
|  | return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode; | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | } // namespace elf | 
|  | } // namespace lld | 
|  |  | 
|  | #endif |