//===- 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. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_SYMBOLS_H #define LLD_ELF_SYMBOLS_H #include "InputSection.h" #include "Strings.h" #include "lld/Core/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" namespace lld { namespace elf { class ArchiveFile; class BitcodeFile; class InputFile; class LazyObjectFile; template class ObjectFile; template class OutputSection; class OutputSectionBase; template class SharedFile; struct Symbol; // The base class for real symbol classes. class SymbolBody { public: enum Kind { DefinedFirst, DefinedRegularKind = DefinedFirst, SharedKind, DefinedCommonKind, DefinedSyntheticKind, DefinedLast = DefinedSyntheticKind, UndefinedKind, LazyArchiveKind, LazyObjectKind, }; SymbolBody(Kind K) : SymbolKind(K) {} Symbol *symbol(); const Symbol *symbol() const { return const_cast(this)->symbol(); } Kind kind() const { return static_cast(SymbolKind); } bool isUndefined() const { return SymbolKind == UndefinedKind; } bool isDefined() const { return SymbolKind <= DefinedLast; } bool isCommon() const { return SymbolKind == DefinedCommonKind; } bool isLazy() const { return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } bool isShared() const { return SymbolKind == SharedKind; } bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } template bool hasThunk() const; template typename ELFT::uint getVA(typename ELFT::uint Addend = 0) const; template typename ELFT::uint getGotOffset() const; template typename ELFT::uint getGotVA() const; template typename ELFT::uint getGotPltOffset() const; template typename ELFT::uint getGotPltVA() const; template typename ELFT::uint getPltVA() const; template typename ELFT::uint getThunkVA() const; template typename ELFT::uint getSize() const; // The file from which this symbol was created. InputFile *File = nullptr; uint32_t DynsymIndex = 0; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; uint32_t PltIndex = -1; uint32_t GlobalDynIndex = -1; protected: SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); const unsigned SymbolKind : 8; public: // True if the linker has to generate a copy relocation for this shared // symbol or if the symbol should point to its plt entry. unsigned NeedsCopyOrPltAddr : 1; // True if this is a local symbol. unsigned IsLocal : 1; // True if this symbol has an entry in the global part of MIPS GOT. unsigned IsInGlobalMipsGot : 1; // True if this symbol is referenced by 32-bit GOT relocations. unsigned Is32BitMipsGot : 1; // True if this symbol is in the Iplt sub-section of the Plt. unsigned IsInIplt : 1; // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value // The Type field may also have this value. It means that we have not yet seen // a non-Lazy symbol with this name, so we don't know what its type is. The // Type field is normally set to this value for Lazy symbols unless we saw a // weak undefined symbol first, in which case we need to remember the original // symbol's type in order to check for TLS mismatches. enum { UnknownType = 255 }; bool isSection() const { return Type == llvm::ELF::STT_SECTION; } bool isTls() const { return Type == llvm::ELF::STT_TLS; } bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } bool isFile() const { return Type == llvm::ELF::STT_FILE; } protected: StringRefZ Name; }; // The base class for any defined symbols. class Defined : public SymbolBody { public: Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; class DefinedCommon : public Defined { public: DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File); 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 Offset; // The maximum alignment we have seen for this symbol. uint64_t Alignment; uint64_t Size; }; // Regular defined symbols read from object file symbol tables. template class DefinedRegular : public Defined { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::uint uintX_t; public: DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, uintX_t Value, uintX_t Size, InputSectionBase *Section, InputFile *File) : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type), Value(Value), Size(Size), Section(Section ? Section->Repl : NullInputSection) { this->File = File; } // Return true if the symbol is a PIC function. bool isMipsPIC() const; static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedRegularKind; } uintX_t Value; uintX_t Size; // The input section this symbol belongs to. Notice that this is // a reference to a pointer. We are using two levels of indirections // because of ICF. If ICF decides two sections need to be merged, it // manipulates this Section pointers so that they point to the same // section. This is a bit tricky, so be careful to not be confused. // If this is null, the symbol is an absolute symbol. InputSectionBase *&Section; // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. Thunk *ThunkData = nullptr; private: static InputSectionBase *NullInputSection; }; template InputSectionBase *DefinedRegular::NullInputSection; // 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. // If Section is null, this symbol is relative to the image base. class DefinedSynthetic : public Defined { public: DefinedSynthetic(StringRef Name, uint64_t Value, const OutputSectionBase *Section) : Defined(SymbolBody::DefinedSyntheticKind, Name, /*IsLocal=*/false, llvm::ELF::STV_HIDDEN, 0 /* Type */), Value(Value), Section(Section) {} static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::DefinedSyntheticKind; } uint64_t Value; const OutputSectionBase *Section; }; template class Undefined : public SymbolBody { public: Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *F); static bool classof(const SymbolBody *S) { return S->kind() == UndefinedKind; } // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. When linking a DSO undefined // symbols are implicitly imported, the symbol lookup will be performed by // the dynamic loader. A call to an undefined symbol will be given a PLT // entry and on ARM this may need a Thunk if the caller is in Thumb state. Thunk *ThunkData = nullptr; InputFile *file() { return this->File; } }; template class SharedSymbol : public Defined { typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::uint uintX_t; public: static bool classof(const SymbolBody *S) { return S->kind() == SymbolBody::SharedKind; } SharedSymbol(SharedFile *F, StringRef Name, const Elf_Sym &Sym, const Elf_Verdef *Verdef) : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, Sym.st_other, Sym.getType()), Sym(Sym), Verdef(Verdef) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) Type = llvm::ELF::STT_FUNC; this->File = F; } SharedFile *file() { return (SharedFile *)this->File; } const Elf_Sym &Sym; // This field is a pointer to the symbol's version definition. const Elf_Verdef *Verdef; // OffsetInBss is significant only when needsCopy() is true. uintX_t OffsetInBss = 0; // If non-null the symbol has a Thunk that may be used as an alternative // destination for callers of this Symbol. Thunk *ThunkData = nullptr; bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); } }; // 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: static bool classof(const SymbolBody *S) { return S->isLazy(); } // Returns an object file for this symbol, or a nullptr if the file // was already returned. InputFile *fetch(); protected: Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type) : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {} }; // LazyArchive symbols represents symbols in archive files. class LazyArchive : public Lazy { public: LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, uint8_t Type); static bool classof(const SymbolBody *S) { return S->kind() == LazyArchiveKind; } ArchiveFile *file() { return (ArchiveFile *)this->File; } InputFile *fetch(); private: const llvm::object::Archive::Symbol Sym; }; // LazyObject symbols represents symbols in object files between // --start-lib and --end-lib options. class LazyObject : public Lazy { public: LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type); static bool classof(const SymbolBody *S) { return S->kind() == LazyObjectKind; } LazyObjectFile *file() { return (LazyObjectFile *)this->File; } InputFile *fetch(); }; // Some linker-generated symbols need to be created as // DefinedRegular symbols. template struct ElfSym { // The content for __ehdr_start symbol. static DefinedRegular *EhdrStart; // The content for _etext and etext symbols. static DefinedRegular *Etext; static DefinedRegular *Etext2; // The content for _edata and edata symbols. static DefinedRegular *Edata; static DefinedRegular *Edata2; // The content for _end and end symbols. static DefinedRegular *End; static DefinedRegular *End2; // The content for _gp_disp/__gnu_local_gp symbols for MIPS target. static DefinedRegular *MipsGpDisp; static DefinedRegular *MipsLocalGp; static DefinedRegular *MipsGp; }; template DefinedRegular *ElfSym::EhdrStart; template DefinedRegular *ElfSym::Etext; template DefinedRegular *ElfSym::Etext2; template DefinedRegular *ElfSym::Edata; template DefinedRegular *ElfSym::Edata2; template DefinedRegular *ElfSym::End; template DefinedRegular *ElfSym::End2; template DefinedRegular *ElfSym::MipsGpDisp; template DefinedRegular *ElfSym::MipsLocalGp; template DefinedRegular *ElfSym::MipsGp; // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody // stored in the Body field of this object as it resolves symbols. Symbol also // holds computed properties of symbol names. struct Symbol { // Symbol binding. This is on the Symbol to track changes during resolution. // In particular: // An undefined weak is still weak when it resolves to a shared library. // An undefined weak will not fetch archive members, but we have to remember // it is weak. uint8_t Binding; // Version definition index. uint16_t VersionId; // Symbol visibility. This is the computed minimum visibility of all // observed non-DSO symbols. unsigned Visibility : 2; // True if the symbol was used for linking and thus need to be added to the // output file's symbol table. This is true for all symbols except for // unreferenced DSO symbols and bitcode symbols that are unreferenced except // by other bitcode objects. unsigned IsUsedInRegularObj : 1; // If this flag is true and the symbol has protected or default visibility, it // will appear in .dynsym. This flag is set by interposable DSO symbols in // executables, by most symbols in DSOs and executables built with // --export-dynamic, and by dynamic lists. unsigned ExportDynamic : 1; // True if this symbol is specified by --trace-symbol option. unsigned Traced : 1; // This symbol version was found in a version script. unsigned InVersionScript : 1; bool includeInDynsym() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } // This field is used to store the Symbol's SymbolBody. This instantiation of // AlignedCharArrayUnion gives us a struct with a char array field that is // large and aligned enough to store any derived class of SymbolBody. We // assume that the size and alignment of ELF64LE symbols is sufficient for any // ELFT, and we verify this with the static_asserts in replaceBody. llvm::AlignedCharArrayUnion< DefinedCommon, DefinedRegular, DefinedSynthetic, Undefined, SharedSymbol, LazyArchive, LazyObject> Body; SymbolBody *body() { return reinterpret_cast(Body.buffer); } const SymbolBody *body() const { return const_cast(this)->body(); } }; void printTraceSymbol(Symbol *Sym); template void replaceBody(Symbol *S, ArgT &&... Arg) { static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); static_assert(alignof(T) <= alignof(decltype(S->Body)), "Body not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a SymbolBody"); new (S->Body.buffer) T(std::forward(Arg)...); // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } inline Symbol *SymbolBody::symbol() { assert(!isLocal()); return reinterpret_cast(reinterpret_cast(this) - offsetof(Symbol, Body)); } std::string toString(const SymbolBody &B); } // namespace elf } // namespace lld #endif