//===- Symbols.h ------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // All symbols are handled as SymbolBodies regardless of their types. // This file defines various types of SymbolBodies. // // File-scope symbols in ELF objects are the only exception of SymbolBody // instantiation. We will never create SymbolBodies for them for performance // reason. They are often represented as nullptrs. This is fine for symbol // resolution because the symbol table naturally cares only about // externally-visible symbols. For relocations, you have to deal with both // local and non-local functions, and we have two different functions // where we need them. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYMBOLS_H #define LLD_ELF_SYMBOLS_H #include "InputSection.h" #include "lld/Core/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" namespace lld { namespace elf2 { class ArchiveFile; class InputFile; class SymbolBody; template class ObjectFile; template class OutputSection; template class OutputSectionBase; template class SharedFile; // Initializes global objects defined in this file. // Called at the beginning of main(). void initSymbols(); // A real symbol object, SymbolBody, is usually accessed indirectly // through a Symbol. There's always one Symbol for each symbol name. // The resolver updates SymbolBody pointers as it resolves symbols. struct Symbol { SymbolBody *Body; }; // The base class for real symbol classes. class SymbolBody { public: enum Kind { DefinedFirst, DefinedRegularKind = DefinedFirst, SharedKind, DefinedElfLast = SharedKind, DefinedCommonKind, DefinedSyntheticKind, DefinedLast = DefinedSyntheticKind, UndefinedElfKind, UndefinedKind, LazyKind }; Kind kind() const { return static_cast(SymbolKind); } bool isWeak() const { return IsWeak; } bool isUndefined() const { return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } bool isCommon() const { return SymbolKind == DefinedCommonKind; } bool isLazy() const { return SymbolKind == LazyKind; } bool isShared() const { return SymbolKind == SharedKind; } bool isUsedInRegularObj() const { return IsUsedInRegularObj; } bool isUsedInDynamicReloc() const { return IsUsedInDynamicReloc; } void setUsedInDynamicReloc() { IsUsedInDynamicReloc = true; } bool isTls() const { return IsTls; } // Returns the symbol name. StringRef getName() const { return Name; } uint8_t getVisibility() const { return Visibility; } unsigned DynamicSymbolTableIndex = 0; uint32_t GlobalDynIndex = -1; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; bool hasGlobalDynIndex() { return GlobalDynIndex != uint32_t(-1); } bool isInGot() const { return GotIndex != -1U; } bool isInGotPlt() const { return GotPltIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } // A SymbolBody has a backreference to a Symbol. Originally they are // doubly-linked. A backreference will never change. But the pointer // in the Symbol may be mutated by the resolver. If you have a // pointer P to a SymbolBody and are not sure whether the resolver // has chosen the object among other objects having the same name, // you can access P->Backref->Body to get the resolver's result. void setBackref(Symbol *P) { Backref = P; } SymbolBody *repl() { return Backref ? Backref->Body : this; } // Decides which symbol should "win" in the symbol table, this or // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if // they are duplicate (conflicting) symbols. template int compare(SymbolBody *Other); protected: SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, bool IsTls) : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility), IsTls(IsTls), Name(Name) { IsUsedInRegularObj = K != SharedKind && K != LazyKind; IsUsedInDynamicReloc = 0; } const unsigned SymbolKind : 8; unsigned IsWeak : 1; unsigned Visibility : 2; // True if the symbol was used for linking and thus need to be // added to the output file's symbol table. It is usually true, // but if it is a shared symbol that were not referenced by anyone, // it can be false. unsigned IsUsedInRegularObj : 1; // If true, the symbol is added to .dynsym symbol table. unsigned IsUsedInDynamicReloc : 1; unsigned IsTls : 1; StringRef Name; Symbol *Backref = nullptr; }; // The base class for any defined symbols. class Defined : public SymbolBody { public: Defined(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility, bool IsTls); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; // Any defined symbol from an ELF file. template class DefinedElf : public Defined { protected: typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; public: DefinedElf(Kind K, StringRef N, const Elf_Sym &Sym) : Defined(K, N, Sym.getBinding() == llvm::ELF::STB_WEAK, Sym.getVisibility(), Sym.getType() == llvm::ELF::STT_TLS), Sym(Sym) {} const Elf_Sym &Sym; static bool classof(const SymbolBody *S) { return S->kind() <= DefinedElfLast; } }; class DefinedCommon : public Defined { public: DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak, uint8_t Visibility); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedCommonKind; } // The output offset of this common symbol in the output bss. Computed by the // writer. uint64_t OffsetInBSS; // The maximum alignment we have seen for this symbol. uint64_t MaxAlignment; uint64_t Size; }; // Regular defined symbols read from object file symbol tables. template class DefinedRegular : public DefinedElf { typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; public: DefinedRegular(StringRef N, const Elf_Sym &Sym, InputSectionBase *Section) : DefinedElf(SymbolBody::DefinedRegularKind, N, Sym), Section(Section) {} static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedRegularKind; } // If this is null, the symbol is absolute. InputSectionBase *Section; }; // DefinedSynthetic is a class to represent linker-generated ELF symbols. // The difference from the regular symbol is that DefinedSynthetic symbols // don't belong to any input files or sections. Thus, its constructor // takes an output section to calculate output VA, etc. template class DefinedSynthetic : public Defined { public: typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::uintX_t uintX_t; DefinedSynthetic(StringRef N, uintX_t Value, OutputSectionBase &Section); static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; } uintX_t Value; const OutputSectionBase &Section; }; // Undefined symbol. class Undefined : public SymbolBody { typedef SymbolBody::Kind Kind; bool CanKeepUndefined; protected: Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, bool IsTls); public: Undefined(StringRef N, bool IsWeak, uint8_t Visibility, bool CanKeepUndefined); static bool classof(const SymbolBody *S) { return S->isUndefined(); } bool canKeepUndefined() const { return CanKeepUndefined; } }; template class UndefinedElf : public Undefined { typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; public: UndefinedElf(StringRef N, const Elf_Sym &Sym); const Elf_Sym &Sym; static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::UndefinedElfKind; } }; template class SharedSymbol : public DefinedElf { typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::uintX_t uintX_t; public: static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::SharedKind; } SharedSymbol(SharedFile *F, StringRef Name, const Elf_Sym &Sym) : DefinedElf(SymbolBody::SharedKind, Name, Sym), File(F) {} SharedFile *File; // True if the linker has to generate a copy relocation for this shared // symbol. OffsetInBSS is significant only when NeedsCopy is true. bool NeedsCopy = false; uintX_t OffsetInBSS = 0; }; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined // symbol. If the resolver finds both Undefined and Lazy for // the same name, it will ask the Lazy to load a file. class Lazy : public SymbolBody { public: Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S) : SymbolBody(LazyKind, S.getName(), false, llvm::ELF::STV_DEFAULT, false), File(F), Sym(S) {} static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } // Returns an object file for this symbol, or a nullptr if the file // was already returned. std::unique_ptr getMember(); void setWeak() { IsWeak = true; } void setUsedInRegularObj() { IsUsedInRegularObj = true; } private: ArchiveFile *File; const llvm::object::Archive::Symbol Sym; }; // Some linker-generated symbols need to be created as // DefinedRegular symbols, so they need Elf_Sym symbols. // Here we allocate such Elf_Sym symbols statically. template struct ElfSym { typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; // Used to represent an undefined symbol which we don't want // to add to the output file's symbol table. static Elf_Sym IgnoreUndef; // The content for _end and end symbols. static Elf_Sym End; // The content for _gp symbol for MIPS target. static Elf_Sym MipsGp; // __rel_iplt_start/__rel_iplt_end for signaling // where R_[*]_IRELATIVE relocations do live. static Elf_Sym RelaIpltStart; static Elf_Sym RelaIpltEnd; }; template typename ElfSym::Elf_Sym ElfSym::IgnoreUndef; template typename ElfSym::Elf_Sym ElfSym::End; template typename ElfSym::Elf_Sym ElfSym::MipsGp; template typename ElfSym::Elf_Sym ElfSym::RelaIpltStart; template typename ElfSym::Elf_Sym ElfSym::RelaIpltEnd; } // namespace elf2 } // namespace lld #endif