diff options
Diffstat (limited to 'ELF/SymbolTable.cpp')
-rw-r--r-- | ELF/SymbolTable.cpp | 250 |
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, |