aboutsummaryrefslogtreecommitdiff
path: root/ELF/SymbolTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/SymbolTable.cpp')
-rw-r--r--ELF/SymbolTable.cpp250
1 files changed, 92 insertions, 158 deletions
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 1f5a84ec2c7d..7615e12199fa 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -94,8 +94,20 @@ template <class ELFT> void SymbolTable::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())
return;
+
+ // If a DSO appears more than once on the command line with and without
+ // --as-needed, --no-as-needed takes precedence over --as-needed because a
+ // user can add an extra DSO with --no-as-needed to force it to be added to
+ // the dependency list.
+ DenseMap<StringRef, InputFile *>::iterator It;
+ bool WasInserted;
+ std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F);
+ cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded;
+ if (!WasInserted)
+ return;
+
SharedFiles.push_back(F);
F->parseRest();
return;
@@ -139,77 +151,27 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() {
}
}
-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<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.
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::addSymbolWrap(StringRef Name) {
- Symbol *Sym = find(Name);
- if (!Sym)
- return;
-
- // Do not wrap the same symbol twice.
- for (const WrappedSymbol &S : WrappedSymbols)
- if (S.Sym == Sym)
- return;
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+ // Swap symbols as instructed by -wrap.
+ int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())];
+ int &Idx2 = SymMap[CachedHashStringRef(Real->getName())];
+ int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())];
- Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
- WrappedSymbols.push_back({Sym, Real, Wrap});
+ Idx2 = Idx1;
+ Idx1 = Idx3;
- // 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 these symbols.
- Sym->IsUsedInRegularObj = true;
- Wrap->IsUsedInRegularObj = true;
-}
-
-// 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.
-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 = reinterpret_cast<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);
- }
+ // Now renaming is complete. No one refers Real symbol. We could leave
+ // Real as-is, but if Real is written to the symbol table, that may
+ // contain irrelevant values. So, we copy all values from Sym to Real.
+ StringRef S = Real->getName();
+ memcpy(Real, Sym, sizeof(SymbolUnion));
+ Real->setName(S);
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
@@ -221,7 +183,7 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
}
// Find an existing symbol or create and insert a new one.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
// <name>@@<version> means the symbol is the default version. In that
// case <name>@@<version> will be used to resolve references to <name>.
//
@@ -239,34 +201,34 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
if (SymIndex == -1) {
SymIndex = SymVector.size();
- IsNew = Traced = true;
+ IsNew = true;
+ Traced = true;
}
- Symbol *Sym;
- if (IsNew) {
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->Visibility = STV_DEFAULT;
- Sym->IsUsedInRegularObj = false;
- Sym->ExportDynamic = false;
- Sym->CanInline = true;
- Sym->Traced = Traced;
- Sym->VersionId = Config->DefaultSymbolVersion;
- SymVector.push_back(Sym);
- } else {
- Sym = SymVector[SymIndex];
- }
- return {Sym, IsNew};
+ if (!IsNew)
+ return {SymVector[SymIndex], false};
+
+ auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->SymbolKind = Symbol::PlaceholderKind;
+ Sym->Visibility = STV_DEFAULT;
+ Sym->IsUsedInRegularObj = false;
+ Sym->ExportDynamic = false;
+ Sym->CanInline = true;
+ Sym->Traced = Traced;
+ Sym->VersionId = Config->DefaultSymbolVersion;
+ SymVector.push_back(Sym);
+ return {Sym, true};
}
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
uint8_t Visibility,
bool CanOmitFromDynSym,
InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
@@ -277,21 +239,9 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
if (!File || File->kind() == InputFile::ObjKind)
S->IsUsedInRegularObj = true;
- 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::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>
@@ -301,8 +251,7 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
- std::tie(S, WasInserted) =
- insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+ std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
@@ -314,10 +263,6 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (!Config->GcSections && Binding != STB_WEAK)
- if (auto *SS = dyn_cast<SharedSymbol>(S))
- SS->getFile<ELFT>().IsNeeded = true;
-
if (S->isLazy()) {
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
@@ -450,7 +395,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputFile &File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
+ std::tie(S, WasInserted) = insert(N, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
int Cmp = compareDefined(S, WasInserted, Binding, N);
@@ -487,12 +432,6 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
return S;
}
-static void reportDuplicate(Symbol *Sym, InputFile *NewFile) {
- if (!Config->AllowMultipleDefinition)
- error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
- toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
-}
-
static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
InputSectionBase *ErrSec, uint64_t ErrOffset) {
if (Config->AllowMultipleDefinition)
@@ -500,7 +439,8 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, NewFile);
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
return;
}
@@ -527,12 +467,12 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
error(Msg);
}
-Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File) {
+Defined *SymbolTable::addDefined(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),
+ std::tie(S, WasInserted) = insert(Name, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr,
Value, Name);
@@ -542,7 +482,7 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
else if (Cmp == 0)
reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
Value);
- return S;
+ return cast<Defined>(S);
}
template <typename ELFT>
@@ -554,7 +494,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// unchanged.
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+ std::tie(S, WasInserted) = insert(Name, STV_DEFAULT,
/*CanOmitFromDynSym*/ true, &File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
@@ -562,19 +502,16 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
- if (WasInserted ||
- ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) {
- uint8_t Binding = S->Binding;
- bool WasUndefined = S->isUndefined();
- replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
+ auto Replace = [&](uint8_t Binding) {
+ replaceSymbol<SharedSymbol>(S, File, Name, Binding, 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;
- }
- }
+ };
+
+ if (WasInserted)
+ Replace(Sym.getBinding());
+ else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy()))
+ Replace(S->Binding);
}
Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
@@ -583,13 +520,13 @@ Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F);
+ insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding,
/*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr);
else if (Cmp == 0)
- reportDuplicate(S, &F);
+ reportDuplicate(S, &F, nullptr, 0);
return S;
}
@@ -602,18 +539,14 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-// This is used to handle lazy symbols. May replace existent
-// symbol with lazy version or request to Fetch it.
-template <class ELFT, typename LazyT, typename... ArgT>
-static void replaceOrFetchLazy(StringRef Name, InputFile &File,
- llvm::function_ref<InputFile *()> Fetch,
- ArgT &&... Arg) {
+template <class ELFT>
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = Symtab->insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
if (WasInserted) {
- replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
- std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym);
return;
}
if (!S->isUndefined())
@@ -622,26 +555,37 @@ static void replaceOrFetchLazy(StringRef Name, InputFile &File,
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, S->Type, Sym);
S->Binding = STB_WEAK;
return;
}
- if (InputFile *F = Fetch())
- Symtab->addFile<ELFT>(F);
+ if (InputFile *F = File.fetch(Sym))
+ addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
- replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
- Sym);
-}
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+ if (WasInserted) {
+ replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name);
+ return;
+ }
+ if (!S->isUndefined())
+ return;
-template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
- Name);
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (S->isWeak()) {
+ replaceSymbol<LazyObject>(S, File, S->Type, Name);
+ S->Binding = STB_WEAK;
+ return;
+ }
+
+ if (InputFile *F = File.fetch())
+ addFile<ELFT>(F);
}
template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
@@ -822,16 +766,6 @@ template void SymbolTable::addFile<ELF32BE>(InputFile *);
template void SymbolTable::addFile<ELF64LE>(InputFile *);
template void SymbolTable::addFile<ELF64BE>(InputFile *);
-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,