summaryrefslogtreecommitdiff
path: root/ELF/InputFiles.h
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/InputFiles.h')
-rw-r--r--ELF/InputFiles.h358
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