aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/lld/ELF/Symbols.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lld/ELF/Symbols.h')
-rw-r--r--contrib/llvm/tools/lld/ELF/Symbols.h455
1 files changed, 294 insertions, 161 deletions
diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h
index dacba133ee8d..d640495b0e01 100644
--- a/contrib/llvm/tools/lld/ELF/Symbols.h
+++ b/contrib/llvm/tools/lld/ELF/Symbols.h
@@ -1,9 +1,8 @@
//===- Symbols.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
//
//===----------------------------------------------------------------------===//
//
@@ -14,6 +13,7 @@
#ifndef LLD_ELF_SYMBOLS_H
#define LLD_ELF_SYMBOLS_H
+#include "InputFiles.h"
#include "InputSection.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Strings.h"
@@ -22,8 +22,14 @@
namespace lld {
namespace elf {
-class Symbol;
+class CommonSymbol;
+class Defined;
class InputFile;
+class LazyArchive;
+class LazyObject;
+class SharedSymbol;
+class Symbol;
+class Undefined;
} // namespace elf
std::string toString(const elf::Symbol &);
@@ -31,15 +37,6 @@ std::string toString(const elf::InputFile *);
namespace elf {
-class ArchiveFile;
-class BitcodeFile;
-class BssSection;
-class InputFile;
-class LazyObjFile;
-template <class ELFT> class ObjFile;
-class OutputSection;
-template <class ELFT> class SharedFile;
-
// This is a StringRef-like container that doesn't run strlen().
//
// ELF string tables contain a lot of null-terminated strings. Most of them
@@ -47,11 +44,11 @@ template <class ELFT> class SharedFile;
// and the linker doesn't use local symbol names for name resolution. So, we
// use this class to represents strings read from string tables.
struct StringRefZ {
- StringRefZ(const char *S) : Data(S), Size(-1) {}
- StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {}
+ StringRefZ(const char *s) : data(s), size(-1) {}
+ StringRefZ(StringRef s) : data(s.data()), size(s.size()) {}
- const char *Data;
- const uint32_t Size;
+ const char *data;
+ const uint32_t size;
};
// The base class for real symbol classes.
@@ -60,85 +57,91 @@ public:
enum Kind {
PlaceholderKind,
DefinedKind,
+ CommonKind,
SharedKind,
UndefinedKind,
LazyArchiveKind,
LazyObjectKind,
};
- Kind kind() const { return static_cast<Kind>(SymbolKind); }
+ Kind kind() const { return static_cast<Kind>(symbolKind); }
// The file from which this symbol was created.
- InputFile *File;
+ InputFile *file;
protected:
- const char *NameData;
- mutable uint32_t NameSize;
+ const char *nameData;
+ mutable uint32_t nameSize;
public:
- uint32_t DynsymIndex = 0;
- uint32_t GotIndex = -1;
- uint32_t PltIndex = -1;
+ uint32_t dynsymIndex = 0;
+ uint32_t gotIndex = -1;
+ uint32_t pltIndex = -1;
- uint32_t GlobalDynIndex = -1;
+ uint32_t globalDynIndex = -1;
// This field is a index to the symbol's version definition.
- uint32_t VerdefIndex = -1;
+ uint32_t verdefIndex = -1;
// Version definition index.
- uint16_t VersionId;
+ uint16_t versionId;
// An index into the .branch_lt section on PPC64.
- uint16_t PPC64BranchltIndex = -1;
+ uint16_t ppc64BranchltIndex = -1;
- // Symbol binding. This is not overwritten by replaceSymbol to track
+ // Symbol binding. This is not overwritten by replace() 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;
+ uint8_t binding;
// The following fields have the same meaning as the ELF symbol attributes.
- uint8_t Type; // symbol type
- uint8_t StOther; // st_other field value
+ uint8_t type; // symbol type
+ uint8_t stOther; // st_other field value
- uint8_t SymbolKind;
+ uint8_t symbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
- unsigned Visibility : 2;
+ 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;
+ // unreferenced DSO symbols, lazy (archive) 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;
+ unsigned exportDynamic : 1;
// False if LTO shouldn't inline whatever this symbol points to. If a symbol
// is overwritten after LTO, LTO shouldn't inline the symbol because it
// doesn't know the final contents of the symbol.
- unsigned CanInline : 1;
+ unsigned canInline : 1;
// True if this symbol is specified by --trace-symbol option.
- unsigned Traced : 1;
+ unsigned traced : 1;
+
+ inline void replace(const Symbol &New);
bool includeInDynsym() const;
uint8_t computeBinding() const;
- bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
+ bool isWeak() const { return binding == llvm::ELF::STB_WEAK; }
+
+ bool isUndefined() const { return symbolKind == UndefinedKind; }
+ bool isCommon() const { return symbolKind == CommonKind; }
+ bool isDefined() const { return symbolKind == DefinedKind; }
+ bool isShared() const { return symbolKind == SharedKind; }
+ bool isPlaceholder() const { return symbolKind == PlaceholderKind; }
- bool isUndefined() const { return SymbolKind == UndefinedKind; }
- bool isDefined() const { return SymbolKind == DefinedKind; }
- bool isShared() const { return SymbolKind == SharedKind; }
- bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
+ bool isLocal() const { return binding == llvm::ELF::STB_LOCAL; }
bool isLazy() const {
- return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+ return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind;
}
// True if this is an undefined weak symbol. This only works once
@@ -149,23 +152,23 @@ public:
}
StringRef getName() const {
- if (NameSize == (uint32_t)-1)
- NameSize = strlen(NameData);
- return {NameData, NameSize};
+ if (nameSize == (uint32_t)-1)
+ nameSize = strlen(nameData);
+ return {nameData, nameSize};
}
- void setName(StringRef S) {
- NameData = S.data();
- NameSize = S.size();
+ void setName(StringRef s) {
+ nameData = s.data();
+ nameSize = s.size();
}
void parseSymbolVersion();
- bool isInGot() const { return GotIndex != -1U; }
- bool isInPlt() const { return PltIndex != -1U; }
- bool isInPPC64Branchlt() const { return PPC64BranchltIndex != 0xffff; }
+ bool isInGot() const { return gotIndex != -1U; }
+ bool isInPlt() const { return pltIndex != -1U; }
+ bool isInPPC64Branchlt() const { return ppc64BranchltIndex != 0xffff; }
- uint64_t getVA(int64_t Addend = 0) const;
+ uint64_t getVA(int64_t addend = 0) const;
uint64_t getGotOffset() const;
uint64_t getGotVA() const;
@@ -177,83 +180,164 @@ public:
uint64_t getSize() const;
OutputSection *getOutputSection() const;
+ // The following two functions are used for symbol resolution.
+ //
+ // You are expected to call mergeProperties for all symbols in input
+ // files so that attributes that are attached to names rather than
+ // indivisual symbol (such as visibility) are merged together.
+ //
+ // Every time you read a new symbol from an input, you are supposed
+ // to call resolve() with the new symbol. That function replaces
+ // "this" object as a result of name resolution if the new symbol is
+ // more appropriate to be included in the output.
+ //
+ // For example, if "this" is an undefined symbol and a new symbol is
+ // a defined symbol, "this" is replaced with the new symbol.
+ void mergeProperties(const Symbol &other);
+ void resolve(const Symbol &other);
+
+ // If this is a lazy symbol, fetch an input file and add the symbol
+ // in the file to the symbol table. Calling this function on
+ // non-lazy object causes a runtime error.
+ void fetch() const;
+
+private:
+ static bool isExportDynamic(Kind k, uint8_t visibility) {
+ if (k == SharedKind)
+ return visibility == llvm::ELF::STV_DEFAULT;
+ return config->shared || config->exportDynamic;
+ }
+
+ void resolveUndefined(const Undefined &other);
+ void resolveCommon(const CommonSymbol &other);
+ void resolveDefined(const Defined &other);
+ template <class LazyT> void resolveLazy(const LazyT &other);
+ void resolveShared(const SharedSymbol &other);
+
+ int compare(const Symbol *other) const;
+
+ inline size_t getSymbolSize() const;
+
protected:
- Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding,
- uint8_t StOther, uint8_t Type)
- : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
- Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
- IsInIplt(false), GotInIgot(false), IsPreemptible(false),
- Used(!Config->GcSections), NeedsTocRestore(false),
- ScriptDefined(false) {}
+ Symbol(Kind k, InputFile *file, StringRefZ name, uint8_t binding,
+ uint8_t stOther, uint8_t type)
+ : file(file), nameData(name.data), nameSize(name.size), binding(binding),
+ type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
+ isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
+ exportDynamic(isExportDynamic(k, visibility)), canInline(false),
+ traced(false), needsPltAddr(false), isInIplt(false), gotInIgot(false),
+ isPreemptible(false), used(!config->gcSections), needsTocRestore(false),
+ scriptDefined(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
- unsigned NeedsPltAddr : 1;
+ unsigned needsPltAddr : 1;
// True if this symbol is in the Iplt sub-section of the Plt and the Igot
// sub-section of the .got.plt or .got.
- unsigned IsInIplt : 1;
+ unsigned isInIplt : 1;
// True if this symbol needs a GOT entry and its GOT entry is actually in
// Igot. This will be true only for certain non-preemptible ifuncs.
- unsigned GotInIgot : 1;
+ unsigned gotInIgot : 1;
// True if this symbol is preemptible at load time.
- unsigned IsPreemptible : 1;
+ unsigned isPreemptible : 1;
// True if an undefined or shared symbol is used from a live section.
- unsigned Used : 1;
+ unsigned used : 1;
// True if a call to this symbol needs to be followed by a restore of the
// PPC64 toc pointer.
- unsigned NeedsTocRestore : 1;
+ unsigned needsTocRestore : 1;
// True if this symbol is defined by a linker script.
- unsigned ScriptDefined : 1;
-
- 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; }
+ unsigned scriptDefined : 1;
+
+ // The partition whose dynamic symbol table contains this symbol's definition.
+ uint8_t partition = 1;
+
+ 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; }
};
// Represents a symbol that is defined in the current output file.
class Defined : public Symbol {
public:
- Defined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther,
- uint8_t Type, uint64_t Value, uint64_t Size, SectionBase *Section)
- : Symbol(DefinedKind, File, Name, Binding, StOther, Type), Value(Value),
- Size(Size), Section(Section) {}
+ Defined(InputFile *file, StringRefZ name, uint8_t binding, uint8_t stOther,
+ uint8_t type, uint64_t value, uint64_t size, SectionBase *section)
+ : Symbol(DefinedKind, file, name, binding, stOther, type), value(value),
+ size(size), section(section) {}
+
+ static bool classof(const Symbol *s) { return s->isDefined(); }
+
+ uint64_t value;
+ uint64_t size;
+ SectionBase *section;
+};
+
+// Represents a common symbol.
+//
+// On Unix, it is traditionally allowed to write variable definitions
+// without initialization expressions (such as "int foo;") to header
+// files. Such definition is called "tentative definition".
+//
+// Using tentative definition is usually considered a bad practice
+// because you should write only declarations (such as "extern int
+// foo;") to header files. Nevertheless, the linker and the compiler
+// have to do something to support bad code by allowing duplicate
+// definitions for this particular case.
+//
+// Common symbols represent variable definitions without initializations.
+// The compiler creates common symbols when it sees varaible definitions
+// without initialization (you can suppress this behavior and let the
+// compiler create a regular defined symbol by -fno-common).
+//
+// The linker allows common symbols to be replaced by regular defined
+// symbols. If there are remaining common symbols after name resolution is
+// complete, they are converted to regular defined symbols in a .bss
+// section. (Therefore, the later passes don't see any CommonSymbols.)
+class CommonSymbol : public Symbol {
+public:
+ CommonSymbol(InputFile *file, StringRefZ name, uint8_t binding,
+ uint8_t stOther, uint8_t type, uint64_t alignment, uint64_t size)
+ : Symbol(CommonKind, file, name, binding, stOther, type),
+ alignment(alignment), size(size) {}
- static bool classof(const Symbol *S) { return S->isDefined(); }
+ static bool classof(const Symbol *s) { return s->isCommon(); }
- uint64_t Value;
- uint64_t Size;
- SectionBase *Section;
+ uint32_t alignment;
+ uint64_t size;
};
class Undefined : public Symbol {
public:
- Undefined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther,
- uint8_t Type)
- : Symbol(UndefinedKind, File, Name, Binding, StOther, Type) {}
+ Undefined(InputFile *file, StringRefZ name, uint8_t binding, uint8_t stOther,
+ uint8_t type, uint32_t discardedSecIdx = 0)
+ : Symbol(UndefinedKind, file, name, binding, stOther, type),
+ discardedSecIdx(discardedSecIdx) {}
- static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
+ static bool classof(const Symbol *s) { return s->kind() == UndefinedKind; }
+
+ // The section index if in a discarded section, 0 otherwise.
+ uint32_t discardedSecIdx;
};
class SharedSymbol : public Symbol {
public:
- static bool classof(const Symbol *S) { return S->kind() == SharedKind; }
-
- SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding,
- uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size,
- uint32_t Alignment, uint32_t VerdefIndex)
- : Symbol(SharedKind, &File, Name, Binding, StOther, Type),
- Alignment(Alignment), Value(Value), Size(Size) {
- this->VerdefIndex = VerdefIndex;
+ static bool classof(const Symbol *s) { return s->kind() == SharedKind; }
+
+ SharedSymbol(InputFile &file, StringRef name, uint8_t binding,
+ uint8_t stOther, uint8_t type, uint64_t value, uint64_t size,
+ uint32_t alignment, uint32_t verdefIndex)
+ : Symbol(SharedKind, &file, name, binding, stOther, type), value(value),
+ size(size), alignment(alignment) {
+ this->verdefIndex = verdefIndex;
// GNU ifunc is a mechanism to allow user-supplied functions to
// resolve PLT slot values at load-time. This is contrary to the
// regular symbol resolution scheme in which symbols are resolved just
@@ -270,18 +354,20 @@ public:
// For DSO symbols, we always call them through PLT slots anyway.
// So there's no difference between GNU ifunc and regular function
// symbols if they are in DSOs. So we can handle GNU_IFUNC as FUNC.
- if (this->Type == llvm::ELF::STT_GNU_IFUNC)
- this->Type = llvm::ELF::STT_FUNC;
+ if (this->type == llvm::ELF::STT_GNU_IFUNC)
+ this->type = llvm::ELF::STT_FUNC;
}
- template <class ELFT> SharedFile<ELFT> &getFile() const {
- return *cast<SharedFile<ELFT>>(File);
- }
+ SharedFile &getFile() const { return *cast<SharedFile>(file); }
- uint32_t Alignment;
+ uint64_t value; // st_value
+ uint64_t size; // st_size
+ uint32_t alignment;
- uint64_t Value; // st_value
- uint64_t Size; // st_size
+ // This is true if there has been at least one undefined reference to the
+ // symbol. The binding may change to STB_WEAK if the first undefined reference
+ // is weak.
+ bool referenced = false;
};
// LazyArchive and LazyObject represent a symbols that is not yet in the link,
@@ -300,121 +386,168 @@ public:
// symbol.
class LazyArchive : public Symbol {
public:
- LazyArchive(InputFile &File, uint8_t Type,
- const llvm::object::Archive::Symbol S)
- : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL,
- llvm::ELF::STV_DEFAULT, Type),
- Sym(S) {}
+ LazyArchive(InputFile &file, const llvm::object::Archive::Symbol s)
+ : Symbol(LazyArchiveKind, &file, s.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE),
+ sym(s) {}
- static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
- InputFile *fetch();
MemoryBufferRef getMemberBuffer();
-private:
- const llvm::object::Archive::Symbol Sym;
+ const llvm::object::Archive::Symbol sym;
};
// LazyObject symbols represents symbols in object files between
// --start-lib and --end-lib options.
class LazyObject : public Symbol {
public:
- LazyObject(InputFile &File, uint8_t Type, StringRef Name)
- : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL,
- llvm::ELF::STV_DEFAULT, Type) {}
+ LazyObject(InputFile &file, StringRef name)
+ : Symbol(LazyObjectKind, &file, name, llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {}
- static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
};
// Some linker-generated symbols need to be created as
// Defined symbols.
struct ElfSym {
// __bss_start
- static Defined *Bss;
+ static Defined *bss;
// etext and _etext
- static Defined *Etext1;
- static Defined *Etext2;
+ static Defined *etext1;
+ static Defined *etext2;
// edata and _edata
- static Defined *Edata1;
- static Defined *Edata2;
+ static Defined *edata1;
+ static Defined *edata2;
// end and _end
- static Defined *End1;
- static Defined *End2;
+ static Defined *end1;
+ static Defined *end2;
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to
// be at some offset from the base of the .got section, usually 0 or
// the end of the .got.
- static Defined *GlobalOffsetTable;
+ static Defined *globalOffsetTable;
// _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS.
- static Defined *MipsGp;
- static Defined *MipsGpDisp;
- static Defined *MipsLocalGp;
+ static Defined *mipsGp;
+ static Defined *mipsGpDisp;
+ static Defined *mipsLocalGp;
// __rel{,a}_iplt_{start,end} symbols.
- static Defined *RelaIpltStart;
- static Defined *RelaIpltEnd;
+ static Defined *relaIpltStart;
+ static Defined *relaIpltEnd;
+
+ // __global_pointer$ for RISC-V.
+ static Defined *riscvGlobalPointer;
+
+ // _TLS_MODULE_BASE_ on targets that support TLSDESC.
+ static Defined *tlsModuleBase;
};
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
- alignas(Defined) char A[sizeof(Defined)];
- alignas(Undefined) char C[sizeof(Undefined)];
- alignas(SharedSymbol) char D[sizeof(SharedSymbol)];
- alignas(LazyArchive) char E[sizeof(LazyArchive)];
- alignas(LazyObject) char F[sizeof(LazyObject)];
+ alignas(Defined) char a[sizeof(Defined)];
+ alignas(CommonSymbol) char b[sizeof(CommonSymbol)];
+ alignas(Undefined) char c[sizeof(Undefined)];
+ alignas(SharedSymbol) char d[sizeof(SharedSymbol)];
+ alignas(LazyArchive) char e[sizeof(LazyArchive)];
+ alignas(LazyObject) char f[sizeof(LazyObject)];
};
-void printTraceSymbol(Symbol *Sym);
-
-template <typename T, typename... ArgT>
-void replaceSymbol(Symbol *S, ArgT &&... Arg) {
- using llvm::ELF::STT_TLS;
+// It is important to keep the size of SymbolUnion small for performance and
+// memory usage reasons. 80 bytes is a soft limit based on the size of Defined
+// on a 64-bit system.
+static_assert(sizeof(SymbolUnion) <= 80, "SymbolUnion too large");
+template <typename T> struct AssertSymbol {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
- assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
- "Not a Symbol");
+};
- Symbol Sym = *S;
+static inline void assertSymbols() {
+ AssertSymbol<Defined>();
+ AssertSymbol<CommonSymbol>();
+ AssertSymbol<Undefined>();
+ AssertSymbol<SharedSymbol>();
+ AssertSymbol<LazyArchive>();
+ AssertSymbol<LazyObject>();
+}
- new (S) T(std::forward<ArgT>(Arg)...);
+void printTraceSymbol(const Symbol *sym);
+
+size_t Symbol::getSymbolSize() const {
+ switch (kind()) {
+ case CommonKind:
+ return sizeof(CommonSymbol);
+ case DefinedKind:
+ return sizeof(Defined);
+ case LazyArchiveKind:
+ return sizeof(LazyArchive);
+ case LazyObjectKind:
+ return sizeof(LazyObject);
+ case SharedKind:
+ return sizeof(SharedSymbol);
+ case UndefinedKind:
+ return sizeof(Undefined);
+ case PlaceholderKind:
+ return sizeof(Symbol);
+ }
+ llvm_unreachable("unknown symbol kind");
+}
- S->VersionId = Sym.VersionId;
- S->Visibility = Sym.Visibility;
- S->IsUsedInRegularObj = Sym.IsUsedInRegularObj;
- S->ExportDynamic = Sym.ExportDynamic;
- S->CanInline = Sym.CanInline;
- S->Traced = Sym.Traced;
- S->ScriptDefined = Sym.ScriptDefined;
+// replace() replaces "this" object with a given symbol by memcpy'ing
+// it over to "this". This function is called as a result of name
+// resolution, e.g. to replace an undefind symbol with a defined symbol.
+void Symbol::replace(const Symbol &New) {
+ using llvm::ELF::STT_TLS;
// Symbols representing thread-local variables must be referenced by
// TLS-aware relocations, and non-TLS symbols must be reference by
// non-TLS relocations, so there's a clear distinction between TLS
// and non-TLS symbols. It is an error if the same symbol is defined
// as a TLS symbol in one file and as a non-TLS symbol in other file.
- bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) ||
- (Sym.Type != STT_TLS && S->Type == STT_TLS);
+ if (symbolKind != PlaceholderKind && !isLazy() && !New.isLazy()) {
+ bool tlsMismatch = (type == STT_TLS && New.type != STT_TLS) ||
+ (type != STT_TLS && New.type == STT_TLS);
+ if (tlsMismatch)
+ error("TLS attribute mismatch: " + toString(*this) + "\n>>> defined in " +
+ toString(New.file) + "\n>>> defined in " + toString(file));
+ }
+
+ Symbol old = *this;
+ memcpy(this, &New, New.getSymbolSize());
+
+ versionId = old.versionId;
+ visibility = old.visibility;
+ isUsedInRegularObj = old.isUsedInRegularObj;
+ exportDynamic = old.exportDynamic;
+ canInline = old.canInline;
+ traced = old.traced;
+ isPreemptible = old.isPreemptible;
+ scriptDefined = old.scriptDefined;
+ partition = old.partition;
- if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy())
- error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " +
- toString(Sym.File) + "\n>>> defined in " + toString(S->File));
+ // Symbol length is computed lazily. If we already know a symbol length,
+ // propagate it.
+ if (nameData == old.nameData && nameSize == 0 && old.nameSize != 0)
+ nameSize = old.nameSize;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
- if (S->Traced)
- printTraceSymbol(S);
+ if (traced)
+ printTraceSymbol(this);
}
-void maybeWarnUnorderableSymbol(const Symbol *Sym);
+void maybeWarnUnorderableSymbol(const Symbol *sym);
} // namespace elf
} // namespace lld