aboutsummaryrefslogtreecommitdiff
path: root/deps/lld/ELF/SymbolTable.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-03-08 10:59:54 -0500
committerAndrew Kelley <superjoe30@gmail.com>2018-03-08 10:59:54 -0500
commit3200ebc2ea5f6bb51130cbc69d6533144a9f4ddc (patch)
treee234c061c28a95c35afbb35b80b89e3114ecdeb9 /deps/lld/ELF/SymbolTable.cpp
parent2e010c60ae006944ae20ab8b3445598471c9f1e8 (diff)
parentb57cb04afc1898c3b21ef3486709f0c0aa285433 (diff)
downloadzig-3200ebc2ea5f6bb51130cbc69d6533144a9f4ddc.tar.gz
zig-3200ebc2ea5f6bb51130cbc69d6533144a9f4ddc.zip
Merge branch 'llvm6'
Zig now depends on LLVM 6.0.0. The latest commit that depends on LLVM 5.0.1 is 2e010c60ae006944ae20ab8b3445598471c9f1e8.
Diffstat (limited to 'deps/lld/ELF/SymbolTable.cpp')
-rw-r--r--deps/lld/ELF/SymbolTable.cpp626
1 files changed, 340 insertions, 286 deletions
diff --git a/deps/lld/ELF/SymbolTable.cpp b/deps/lld/ELF/SymbolTable.cpp
index 0c932400f0..c3a00bea4a 100644
--- a/deps/lld/ELF/SymbolTable.cpp
+++ b/deps/lld/ELF/SymbolTable.cpp
@@ -16,10 +16,12 @@
#include "SymbolTable.h"
#include "Config.h"
-#include "Error.h"
#include "LinkerScript.h"
-#include "Memory.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
+#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;
@@ -29,11 +31,21 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
+SymbolTable *elf::Symtab;
+
+static InputFile *getFirstElf() {
+ if (!ObjectFiles.empty())
+ return ObjectFiles[0];
+ if (!SharedFiles.empty())
+ return SharedFiles[0];
+ return nullptr;
+}
+
// All input object files must be for the same architecture
// (e.g. it does not make sense to link x86 object files with
// MIPS object files.) This function checks for that error.
-template <class ELFT> static bool isCompatible(InputFile *F) {
- if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F))
+static bool isCompatible(InputFile *F) {
+ if (!F->isElf() && !isa<BitcodeFile>(F))
return true;
if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) {
@@ -46,22 +58,19 @@ template <class ELFT> static bool isCompatible(InputFile *F) {
if (!Config->Emulation.empty())
error(toString(F) + " is incompatible with " + Config->Emulation);
else
- error(toString(F) + " is incompatible with " + toString(Config->FirstElf));
+ error(toString(F) + " is incompatible with " + toString(getFirstElf()));
return false;
}
// Add symbols in File to the symbol table.
-template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
- if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File))
- Config->FirstElf = File;
-
- if (!isCompatible<ELFT>(File))
+template <class ELFT> void SymbolTable::addFile(InputFile *File) {
+ if (!isCompatible(File))
return;
// Binary file
if (auto *F = dyn_cast<BinaryFile>(File)) {
BinaryFiles.push_back(F);
- F->parse<ELFT>();
+ F->parse();
return;
}
@@ -72,7 +81,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
}
// Lazy object file
- if (auto *F = dyn_cast<LazyObjectFile>(File)) {
+ if (auto *F = dyn_cast<LazyObjFile>(File)) {
F->parse<ELFT>();
return;
}
@@ -84,7 +93,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (ErrorCount || !SoNames.insert(F->SoName).second)
+ if (errorCount() || !SoNames.insert(F->SoName).second)
return;
SharedFiles.push_back(F);
F->parseRest();
@@ -99,9 +108,8 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
}
// Regular object file
- auto *F = cast<ObjectFile<ELFT>>(File);
- ObjectFiles.push_back(F);
- F->parse(ComdatGroups);
+ ObjectFiles.push_back(File);
+ cast<ObjFile<ELFT>>(File)->parse(ComdatGroups);
}
// This function is where all the optimizations of link-time
@@ -111,7 +119,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) {
// using LLVM functions and replaces bitcode symbols with the results.
// Because all bitcode files that consist of a program are passed
// to the compiler at once, it can do whole-program optimization.
-template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
+template <class ELFT> void SymbolTable::addCombinedLTOObject() {
if (BitcodeFiles.empty())
return;
@@ -121,82 +129,76 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() {
LTO->add(*F);
for (InputFile *File : LTO->compile()) {
- ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File);
DenseSet<CachedHashStringRef> DummyGroups;
- Obj->parse(DummyGroups);
- ObjectFiles.push_back(Obj);
+ cast<ObjFile<ELFT>>(File)->parse(DummyGroups);
+ ObjectFiles.push_back(File);
}
}
-template <class ELFT>
-DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name,
- uint8_t Visibility,
- uint8_t Binding) {
+Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility,
+ uint8_t Binding) {
Symbol *Sym =
addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
- return cast<DefinedRegular>(Sym->body());
-}
-
-// Add Name as an "ignored" symbol. An ignored symbol is a regular
-// linker-synthesized defined symbol, but is only defined if needed.
-template <class ELFT>
-DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name,
- uint8_t Visibility) {
- SymbolBody *S = find(Name);
- if (!S || S->isInCurrentDSO())
- return nullptr;
- return addAbsolute(Name, Visibility);
+ return cast<Defined>(Sym);
}
// Set a flag for --trace-symbol so that we can print out a log message
// if a new symbol with the same name is inserted into the symbol table.
-template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) {
- Symtab.insert({CachedHashStringRef(Name), {-1, true}});
+void SymbolTable::trace(StringRef Name) {
+ SymMap.insert({CachedHashStringRef(Name), -1});
}
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
// Used to implement --wrap.
-template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) {
- SymbolBody *B = find(Name);
- if (!B)
+template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) {
+ Symbol *Sym = find(Name);
+ if (!Sym)
return;
- Symbol *Sym = B->symbol();
- Symbol *Real = addUndefined(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name));
+ Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
+ WrappedSymbols.push_back({Sym, Real, Wrap});
- // Tell LTO not to eliminate this symbol
- Wrap->IsUsedInRegularObj = true;
-
- Config->RenamedSymbols[Real] = {Sym, Real->Binding};
- Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding};
-}
-
-// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM.
-template <class ELFT>
-void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, StringRef Name) {
- SymbolBody *B = find(Name);
- if (!B) {
- error("-defsym: undefined symbol: " + Name);
- return;
- }
- Symbol *Sym = B->symbol();
- Symbol *AliasSym = addUndefined(Alias);
+ // We want to tell LTO not to inline symbols to be overwritten
+ // because LTO doesn't know the final symbol contents after renaming.
+ Real->CanInline = false;
+ Sym->CanInline = false;
- // Tell LTO not to eliminate this symbol
+ // Tell LTO not to eliminate these symbols.
Sym->IsUsedInRegularObj = true;
- Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding};
+ Wrap->IsUsedInRegularObj = true;
}
-// Apply symbol renames created by -wrap and -defsym. The renames are created
-// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform
-// LTO (if LTO is running) not to include these symbols in IPO. Now that the
+// Apply symbol renames created by -wrap. The renames are created
+// before LTO in addSymbolWrap() to have a chance to inform LTO (if
+// LTO is running) not to include these symbols in IPO. Now that the
// symbols are finalized, we can perform the replacement.
-template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() {
- for (auto &KV : Config->RenamedSymbols) {
- Symbol *Dst = KV.first;
- Symbol *Src = KV.second.Target;
- Dst->body()->copy(Src->body());
- Dst->Binding = KV.second.OriginalBinding;
+void SymbolTable::applySymbolWrap() {
+ // This function rotates 3 symbols:
+ //
+ // __real_sym becomes sym
+ // sym becomes __wrap_sym
+ // __wrap_sym becomes __real_sym
+ //
+ // The last part is special in that we don't want to change what references to
+ // __wrap_sym point to, we just want have __real_sym in the symbol table.
+
+ for (WrappedSymbol &W : WrappedSymbols) {
+ // First, make a copy of __real_sym.
+ Symbol *Real = nullptr;
+ if (W.Real->isDefined()) {
+ Real = (Symbol *)make<SymbolUnion>();
+ memcpy(Real, W.Real, sizeof(SymbolUnion));
+ }
+
+ // Replace __real_sym with sym and sym with __wrap_sym.
+ memcpy(W.Real, W.Sym, sizeof(SymbolUnion));
+ memcpy(W.Sym, W.Wrap, sizeof(SymbolUnion));
+
+ // We now have two copies of __wrap_sym. Drop one.
+ W.Wrap->IsUsedInRegularObj = false;
+
+ if (Real)
+ SymVector.push_back(Real);
}
}
@@ -209,48 +211,50 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
}
// Find an existing symbol or create and insert a new one.
-template <class ELFT>
-std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) {
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
// <name>@@<version> means the symbol is the default version. In that
// case <name>@@<version> will be used to resolve references to <name>.
- size_t Pos = Name.find("@@");
- if (Pos != StringRef::npos)
+ //
+ // Since this is a hot path, the following string search code is
+ // optimized for speed. StringRef::find(char) is much faster than
+ // StringRef::find(StringRef).
+ size_t Pos = Name.find('@');
+ if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@')
Name = Name.take_front(Pos);
- auto P = Symtab.insert(
- {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)});
- SymIndex &V = P.first->second;
+ auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
+ int &SymIndex = P.first->second;
bool IsNew = P.second;
+ bool Traced = false;
- if (V.Idx == -1) {
- IsNew = true;
- V = SymIndex((int)SymVector.size(), true);
+ if (SymIndex == -1) {
+ SymIndex = SymVector.size();
+ IsNew = Traced = true;
}
Symbol *Sym;
if (IsNew) {
- Sym = make<Symbol>();
+ Sym = (Symbol *)make<SymbolUnion>();
Sym->InVersionScript = false;
- Sym->Binding = STB_WEAK;
Sym->Visibility = STV_DEFAULT;
Sym->IsUsedInRegularObj = false;
Sym->ExportDynamic = false;
- Sym->Traced = V.Traced;
+ Sym->CanInline = true;
+ Sym->Traced = Traced;
Sym->VersionId = Config->DefaultSymbolVersion;
SymVector.push_back(Sym);
} else {
- Sym = SymVector[V.Idx];
+ Sym = SymVector[SymIndex];
}
return {Sym, IsNew};
}
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
-template <class ELFT>
-std::pair<Symbol *, bool>
-SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
- bool CanOmitFromDynSym, InputFile *File) {
- bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind;
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
+ uint8_t Visibility,
+ bool CanOmitFromDynSym,
+ InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
@@ -261,32 +265,30 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility,
if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic))
S->ExportDynamic = true;
- if (IsUsedInRegularObj)
+ if (!File || File->kind() == InputFile::ObjKind)
S->IsUsedInRegularObj = true;
- if (!WasInserted && S->body()->Type != SymbolBody::UnknownType &&
- ((Type == STT_TLS) != S->body()->isTls())) {
- error("TLS attribute mismatch: " + toString(*S->body()) +
- "\n>>> defined in " + toString(S->body()->File) +
- "\n>>> defined in " + toString(File));
+ if (!WasInserted && S->Type != Symbol::UnknownType &&
+ ((Type == STT_TLS) != S->isTls())) {
+ error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " +
+ toString(S->File) + "\n>>> defined in " + toString(File));
}
return {S, WasInserted};
}
-template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) {
- return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
+template <class ELFT> Symbol *SymbolTable::addUndefined(StringRef Name) {
+ return addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT,
+ /*Type*/ 0,
+ /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
}
static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
template <class ELFT>
-Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
- uint8_t Binding, uint8_t StOther,
- uint8_t Type, bool CanOmitFromDynSym,
- InputFile *File) {
+Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, InputFile *File) {
Symbol *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
@@ -294,26 +296,24 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
insert(Name, Type, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted ||
- (isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) {
- S->Binding = Binding;
- replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File);
+ if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
+ replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
return S;
}
+ if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
+ S->Binding = Binding;
if (Binding != STB_WEAK) {
- SymbolBody *B = S->body();
- if (B->isShared() || B->isLazy() || B->isUndefined())
- S->Binding = Binding;
- if (auto *SS = dyn_cast<SharedSymbol>(B))
- cast<SharedFile<ELFT>>(SS->File)->IsUsed = true;
+ if (auto *SS = dyn_cast<SharedSymbol>(S))
+ if (!Config->GcSections)
+ SS->getFile<ELFT>().IsNeeded = true;
}
- if (auto *L = dyn_cast<Lazy>(S->body())) {
- // An undefined weak will not fetch archive members, but we have to remember
- // its type. See also comment in addLazyArchive.
- if (S->isWeak())
+ if (auto *L = dyn_cast<Lazy>(S)) {
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (Binding == STB_WEAK)
L->Type = Type;
else if (InputFile *F = L->fetch())
- addFile(F);
+ addFile<ELFT>(F);
}
return S;
}
@@ -325,11 +325,11 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal,
// .symver foo,foo@@@VER
// we can delete this hack.
static int compareVersion(Symbol *S, StringRef Name) {
- if (Name.find("@@") != StringRef::npos &&
- S->body()->getName().find("@@") == StringRef::npos)
+ bool A = Name.contains("@@");
+ bool B = S->getName().contains("@@");
+ if (A && !B)
return 1;
- if (Name.find("@@") == StringRef::npos &&
- S->body()->getName().find("@@") != StringRef::npos)
+ if (!A && B)
return -1;
return 0;
}
@@ -341,13 +341,10 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
StringRef Name) {
if (WasInserted)
return 1;
- SymbolBody *Body = S->body();
- if (!Body->isInCurrentDSO())
+ if (!S->isDefined())
return 1;
-
if (int R = compareVersion(S, Name))
return R;
-
if (Binding == STB_WEAK)
return -1;
if (S->isWeak())
@@ -358,22 +355,18 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding,
// We have a new non-common defined symbol with the specified binding. Return 1
// if the new symbol should win, -1 if the new symbol should lose, or 0 if there
// is a conflict. If the new symbol wins, also update the binding.
-template <typename ELFT>
static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
- bool IsAbsolute, typename ELFT::uint Value,
+ bool IsAbsolute, uint64_t Value,
StringRef Name) {
- if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) {
- if (Cmp > 0)
- S->Binding = Binding;
+ if (int Cmp = compareDefined(S, WasInserted, Binding, Name))
return Cmp;
- }
- SymbolBody *B = S->body();
- if (isa<DefinedCommon>(B)) {
- // Non-common symbols take precedence over common symbols.
- if (Config->WarnCommon)
- warn("common " + S->body()->getName() + " is overridden");
- return 1;
- } else if (auto *R = dyn_cast<DefinedRegular>(B)) {
+ if (auto *R = dyn_cast<Defined>(S)) {
+ if (R->Section && isa<BssSection>(R->Section)) {
+ // Non-common symbols take precedence over common symbols.
+ if (Config->WarnCommon)
+ warn("common " + S->getName() + " is overridden");
+ return 1;
+ }
if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute &&
R->Value == Value)
return -1;
@@ -381,34 +374,39 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding,
return 0;
}
-template <class ELFT>
-Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size,
- uint32_t Alignment, uint8_t Binding,
- uint8_t StOther, uint8_t Type,
- InputFile *File) {
+Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
+ uint8_t Binding, uint8_t StOther, uint8_t Type,
+ InputFile &File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
- /*CanOmitFromDynSym*/ false, File);
+ /*CanOmitFromDynSym*/ false, &File);
int Cmp = compareDefined(S, WasInserted, Binding, N);
if (Cmp > 0) {
- S->Binding = Binding;
- replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+ auto *Bss = make<BssSection>("COMMON", Size, Alignment);
+ Bss->File = &File;
+ Bss->Live = !Config->GcSections;
+ InputSections.push_back(Bss);
+
+ replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss);
} else if (Cmp == 0) {
- auto *C = dyn_cast<DefinedCommon>(S->body());
- if (!C) {
+ auto *D = cast<Defined>(S);
+ auto *Bss = dyn_cast_or_null<BssSection>(D->Section);
+ if (!Bss) {
// Non-common symbols take precedence over common symbols.
if (Config->WarnCommon)
- warn("common " + S->body()->getName() + " is overridden");
+ warn("common " + S->getName() + " is overridden");
return S;
}
if (Config->WarnCommon)
- warn("multiple common of " + S->body()->getName());
+ warn("multiple common of " + D->getName());
- Alignment = C->Alignment = std::max(C->Alignment, Alignment);
- if (Size > C->Size)
- replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File);
+ Bss->Alignment = std::max(Bss->Alignment, Alignment);
+ if (Size > Bss->Size) {
+ D->File = Bss->File = &File;
+ D->Size = Bss->Size = Size;
+ }
}
return S;
}
@@ -420,17 +418,16 @@ static void warnOrError(const Twine &Msg) {
error(Msg);
}
-static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) {
+static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
}
-template <class ELFT>
-static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
- typename ELFT::uint ErrOffset) {
- DefinedRegular *D = dyn_cast<DefinedRegular>(Sym);
- if (!D || !D->Section || !ErrSec) {
- reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr);
+static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec,
+ uint64_t ErrOffset) {
+ Defined *D = cast<Defined>(Sym);
+ if (!D->Section || !ErrSec) {
+ reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr);
return;
}
@@ -442,10 +439,10 @@ static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
// >>> defined at baz.c:563
// >>> baz.o in archive libbaz.a
auto *Sec1 = cast<InputSectionBase>(D->Section);
- std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value);
- std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value);
- std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset);
- std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset);
+ std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value);
+ std::string Obj1 = Sec1->getObjMsg(D->Value);
+ std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset);
+ std::string Obj2 = ErrSec->getObjMsg(ErrOffset);
std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at ";
if (!Src1.empty())
@@ -457,145 +454,135 @@ static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec,
warnOrError(Msg);
}
-template <typename ELFT>
-Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther,
- uint8_t Type, uint64_t Value,
- uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File) {
+Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
- int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- Section == nullptr, Value, Name);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr,
+ Value, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type,
- Value, Size, Section, File);
+ replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size,
+ Section);
else if (Cmp == 0)
- reportDuplicate<ELFT>(S->body(),
- dyn_cast_or_null<InputSectionBase>(Section), Value);
+ reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value);
return S;
}
template <typename ELFT>
-void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name,
- const Elf_Sym &Sym,
- const typename ELFT::Verdef *Verdef) {
+void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
+ const typename ELFT::Sym &Sym, uint32_t Alignment,
+ uint32_t VerdefIndex) {
// DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT
// as the visibility, which will leave the visibility in the symbol table
// unchanged.
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
- /*CanOmitFromDynSym*/ true, File);
+ /*CanOmitFromDynSym*/ true, &File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
S->ExportDynamic = true;
- SymbolBody *Body = S->body();
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted ||
- (isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) {
- replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym,
- Verdef);
- if (!S->isWeak())
- File->IsUsed = true;
+ if (WasInserted || ((S->isUndefined() || S->isLazy()) &&
+ S->getVisibility() == STV_DEFAULT)) {
+ uint8_t Binding = S->Binding;
+ bool WasUndefined = S->isUndefined();
+ replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
+ Sym.getType(), Sym.st_value, Sym.st_size,
+ Alignment, VerdefIndex);
+ if (!WasInserted) {
+ S->Binding = Binding;
+ if (!S->isWeak() && !Config->GcSections && WasUndefined)
+ File.IsNeeded = true;
+ }
}
}
-template <class ELFT>
-Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding,
- uint8_t StOther, uint8_t Type,
- bool CanOmitFromDynSym, BitcodeFile *F) {
+Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanOmitFromDynSym, BitcodeFile &F) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F);
- int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding,
- /*IsAbs*/ false, /*Value*/ 0, Name);
+ insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F);
+ int Cmp = compareDefinedNonCommon(S, WasInserted, Binding,
+ /*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
- replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0,
- nullptr, F);
+ replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr);
else if (Cmp == 0)
- reportDuplicate(S->body(), F);
+ reportDuplicate(S, &F);
return S;
}
-template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
- auto It = Symtab.find(CachedHashStringRef(Name));
- if (It == Symtab.end())
+Symbol *SymbolTable::find(StringRef Name) {
+ auto It = SymMap.find(CachedHashStringRef(Name));
+ if (It == SymMap.end())
return nullptr;
- SymIndex V = It->second;
- if (V.Idx == -1)
+ if (It->second == -1)
return nullptr;
- return SymVector[V.Idx]->body();
+ return SymVector[It->second];
}
template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) {
- if (SymbolBody *S = find(Name))
- if (S->isInCurrentDSO())
- return S;
- return nullptr;
-}
-
-template <class ELFT>
-Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F,
- const object::Archive::Symbol Sym) {
+Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
- StringRef Name = Sym.getName();
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
- replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType);
+ replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType);
return S;
}
- if (!S->body()->isUndefined())
+ if (!S->isUndefined())
return S;
- // Weak undefined symbols should not fetch members from archives. If we were
- // to keep old symbol we would not know that an archive member was available
- // if a strong undefined symbol shows up afterwards in the link. If a strong
- // undefined symbol never shows up, this lazy symbol will get to the end of
- // the link and must be treated as the weak undefined one. We already marked
- // this symbol as used when we added it to the symbol table, but we also need
- // to preserve its type. FIXME: Move the Type field to Symbol.
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
if (S->isWeak()) {
- replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type);
+ replaceSymbol<LazyArchive>(S, F, Sym, S->Type);
+ S->Binding = STB_WEAK;
return S;
}
- std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym);
+ std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym);
if (!MBInfo.first.getBuffer().empty())
- addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second));
+ addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second));
return S;
}
template <class ELFT>
-void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) {
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
- replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType);
+ replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType);
return;
}
- if (!S->body()->isUndefined())
+ if (!S->isUndefined())
return;
// See comment for addLazyArchive above.
if (S->isWeak())
- replaceBody<LazyObject>(S, Name, Obj, S->body()->Type);
+ replaceSymbol<LazyObject>(S, Obj, Name, S->Type);
else if (InputFile *F = Obj.fetch())
- addFile(F);
+ addFile<ELFT>(F);
}
-// Process undefined (-u) flags by loading lazy symbols named by those flags.
-template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
- for (StringRef S : Config->Undefined)
- if (auto *L = dyn_cast_or_null<Lazy>(find(S)))
+// If we already saw this symbol, force loading its file.
+template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) {
+ if (Symbol *B = find(Name)) {
+ // Mark the symbol not to be eliminated by LTO
+ // even if it is a bitcode symbol.
+ B->IsUsedInRegularObj = true;
+ if (auto *L = dyn_cast<Lazy>(B))
if (InputFile *File = L->fetch())
- addFile(File);
+ addFile<ELFT>(File);
+ }
}
// This function takes care of the case in which shared libraries depend on
@@ -605,19 +592,19 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() {
// We need to put such symbols to the main program's .dynsym so that
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
-template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
- for (SharedFile<ELFT> *File : SharedFiles) {
- for (StringRef U : File->getUndefinedSymbols()) {
- SymbolBody *Sym = find(U);
+template <class ELFT> void SymbolTable::scanShlibUndefined() {
+ for (InputFile *F : SharedFiles) {
+ for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) {
+ Symbol *Sym = find(U);
if (!Sym || !Sym->isDefined())
continue;
- Sym->symbol()->ExportDynamic = true;
+ Sym->ExportDynamic = true;
// If -dynamic-list is given, the default version is set to
// VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym.
// Set to VER_NDX_GLOBAL so the symbol will be handled as if it were
// specified by -dynamic-list.
- Sym->symbol()->VersionId = VER_NDX_GLOBAL;
+ Sym->VersionId = VER_NDX_GLOBAL;
}
}
}
@@ -635,37 +622,32 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
// other than trying to match a pattern against all demangled symbols.
// So, if "extern C++" feature is used, we need to demangle all known
// symbols.
-template <class ELFT>
-StringMap<std::vector<SymbolBody *>> &SymbolTable<ELFT>::getDemangledSyms() {
+StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
if (!DemangledSyms) {
DemangledSyms.emplace();
for (Symbol *Sym : SymVector) {
- SymbolBody *B = Sym->body();
- if (B->isUndefined())
+ if (!Sym->isDefined())
continue;
- if (Optional<std::string> S = demangle(B->getName()))
- (*DemangledSyms)[*S].push_back(B);
+ if (Optional<std::string> S = demangleItanium(Sym->getName()))
+ (*DemangledSyms)[*S].push_back(Sym);
else
- (*DemangledSyms)[B->getName()].push_back(B);
+ (*DemangledSyms)[Sym->getName()].push_back(Sym);
}
}
return *DemangledSyms;
}
-template <class ELFT>
-std::vector<SymbolBody *> SymbolTable<ELFT>::findByVersion(SymbolVersion Ver) {
+std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) {
if (Ver.IsExternCpp)
return getDemangledSyms().lookup(Ver.Name);
- if (SymbolBody *B = find(Ver.Name))
- if (!B->isUndefined())
+ if (Symbol *B = find(Ver.Name))
+ if (B->isDefined())
return {B};
return {};
}
-template <class ELFT>
-std::vector<SymbolBody *>
-SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) {
- std::vector<SymbolBody *> Res;
+std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) {
+ std::vector<Symbol *> Res;
StringMatcher M(Ver.Name);
if (Ver.IsExternCpp) {
@@ -675,18 +657,16 @@ SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) {
return Res;
}
- for (Symbol *Sym : SymVector) {
- SymbolBody *B = Sym->body();
- if (!B->isUndefined() && M.match(B->getName()))
- Res.push_back(B);
- }
+ for (Symbol *Sym : SymVector)
+ if (Sym->isDefined() && M.match(Sym->getName()))
+ Res.push_back(Sym);
return Res;
}
// If there's only one anonymous version definition in a version
// script file, the script does not actually define any symbol version,
// but just specifies symbols visibilities.
-template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
+void SymbolTable::handleAnonymousVersion() {
for (SymbolVersion &Ver : Config->VersionScriptGlobals)
assignExactVersion(Ver, VER_NDX_GLOBAL, "global");
for (SymbolVersion &Ver : Config->VersionScriptGlobals)
@@ -697,17 +677,33 @@ template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() {
assignWildcardVersion(Ver, VER_NDX_LOCAL);
}
+// Handles -dynamic-list.
+void SymbolTable::handleDynamicList() {
+ for (SymbolVersion &Ver : Config->DynamicList) {
+ std::vector<Symbol *> Syms;
+ if (Ver.HasWildcard)
+ Syms = findAllByVersion(Ver);
+ else
+ Syms = findByVersion(Ver);
+
+ for (Symbol *B : Syms) {
+ if (!Config->Shared)
+ B->ExportDynamic = true;
+ else if (B->includeInDynsym())
+ B->IsPreemptible = true;
+ }
+ }
+}
+
// Set symbol versions to symbols. This function handles patterns
// containing no wildcard characters.
-template <class ELFT>
-void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
- uint16_t VersionId,
- StringRef VersionName) {
+void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId,
+ StringRef VersionName) {
if (Ver.HasWildcard)
return;
// Get a list of symbols which we need to assign the version to.
- std::vector<SymbolBody *> Syms = findByVersion(Ver);
+ std::vector<Symbol *> Syms = findByVersion(Ver);
if (Syms.empty()) {
if (Config->NoUndefinedVersion)
error("version script assignment of '" + VersionName + "' to symbol '" +
@@ -716,14 +712,13 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
}
// Assign the version.
- for (SymbolBody *B : Syms) {
+ for (Symbol *Sym : Syms) {
// Skip symbols containing version info because symbol versions
// specified by symbol names take precedence over version scripts.
// See parseSymbolVersion().
- if (B->getName().find('@') != StringRef::npos)
+ if (Sym->getName().contains('@'))
continue;
- Symbol *Sym = B->symbol();
if (Sym->InVersionScript)
warn("duplicate symbol '" + Ver.Name + "' in version script");
Sym->VersionId = VersionId;
@@ -731,25 +726,24 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver,
}
}
-template <class ELFT>
-void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver,
- uint16_t VersionId) {
+void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) {
if (!Ver.HasWildcard)
return;
// Exact matching takes precendence over fuzzy matching,
// so we set a version to a symbol only if no version has been assigned
// to the symbol. This behavior is compatible with GNU.
- for (SymbolBody *B : findAllByVersion(Ver))
- if (B->symbol()->VersionId == Config->DefaultSymbolVersion)
- B->symbol()->VersionId = VersionId;
+ for (Symbol *B : findAllByVersion(Ver))
+ if (B->VersionId == Config->DefaultSymbolVersion)
+ B->VersionId = VersionId;
}
// This function processes version scripts by updating VersionId
// member of symbols.
-template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
+void SymbolTable::scanVersionScript() {
// Handle edge cases first.
handleAnonymousVersion();
+ handleDynamicList();
// Now we have version definitions, so we need to set version ids to symbols.
// Each version definition has a glob pattern, and all symbols that match
@@ -773,10 +767,70 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
// can contain versions in the form of <name>@<version>.
// Let them parse and update their names to exclude version suffix.
for (Symbol *Sym : SymVector)
- Sym->body()->parseSymbolVersion();
-}
-
-template class elf::SymbolTable<ELF32LE>;
-template class elf::SymbolTable<ELF32BE>;
-template class elf::SymbolTable<ELF64LE>;
-template class elf::SymbolTable<ELF64BE>;
+ Sym->parseSymbolVersion();
+}
+
+template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef);
+template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef);
+template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef);
+template void SymbolTable::addSymbolWrap<ELF64BE>(StringRef);
+
+template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef);
+template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef);
+template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef);
+template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef);
+
+template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t,
+ uint8_t, bool, InputFile *);
+
+template void SymbolTable::addCombinedLTOObject<ELF32LE>();
+template void SymbolTable::addCombinedLTOObject<ELF32BE>();
+template void SymbolTable::addCombinedLTOObject<ELF64LE>();
+template void SymbolTable::addCombinedLTOObject<ELF64BE>();
+
+template Symbol *
+SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template Symbol *
+SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template Symbol *
+SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+template Symbol *
+SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &,
+ const object::Archive::Symbol);
+
+template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &);
+template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &);
+
+template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &,
+ const typename ELF32LE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &,
+ const typename ELF32BE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &,
+ const typename ELF64LE::Sym &,
+ uint32_t Alignment, uint32_t);
+template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &,
+ const typename ELF64BE::Sym &,
+ uint32_t Alignment, uint32_t);
+
+template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef);
+template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef);
+template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef);
+template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef);
+
+template void SymbolTable::scanShlibUndefined<ELF32LE>();
+template void SymbolTable::scanShlibUndefined<ELF32BE>();
+template void SymbolTable::scanShlibUndefined<ELF64LE>();
+template void SymbolTable::scanShlibUndefined<ELF64BE>();