Index: lld/ELF/Driver.cpp =================================================================== --- lld/ELF/Driver.cpp +++ lld/ELF/Driver.cpp @@ -969,6 +969,14 @@ Symtab.scanShlibUndefined(); Symtab.scanVersionScript(); + // Pass wrapped symbols to LTO + for (auto *Arg : Args.filtered(OPT_wrap)) + Symtab.addLTOSymbolWrap(Arg->getValue()); + + // Pass alias symbols to LTO + for (std::pair &Def : getDefsym(Args)) + Symtab.addLTOSymbolAlias(Def.second); + Symtab.addCombinedLTOObject(); if (ErrorCount) return; Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -558,8 +558,8 @@ if (Sym->st_shndx == SHN_UNDEF) return make(Name, /*IsLocal=*/true, StOther, Type, this); - return make(Name, /*IsLocal=*/true, StOther, Type, Value, - Size, Sec, this); + return make(Name, /*IsLocal=*/true, /*IsBitcode*/false, + StOther, Type, Value, Size, Sec, this); } StringRef Name = check(Sym->getName(this->StringTable), toString(this)); Index: lld/ELF/LTO.h =================================================================== --- lld/ELF/LTO.h +++ lld/ELF/LTO.h @@ -43,7 +43,7 @@ BitcodeCompiler(); ~BitcodeCompiler(); - void add(BitcodeFile &F); + void add(BitcodeFile &F, llvm::StringMap &RenamedSymbols); std::vector compile(); private: Index: lld/ELF/LTO.cpp =================================================================== --- lld/ELF/LTO.cpp +++ lld/ELF/LTO.cpp @@ -107,12 +107,7 @@ BitcodeCompiler::~BitcodeCompiler() = default; -static void undefine(Symbol *S) { - replaceBody(S, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type, nullptr); -} - -void BitcodeCompiler::add(BitcodeFile &F) { +void BitcodeCompiler::add(BitcodeFile &F, llvm::StringMap &RenamedSymbols) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector Syms = F.getSymbols(); @@ -134,8 +129,7 @@ R.VisibleToRegularObj = Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); - if (R.Prevailing) - undefine(Sym); + R.IsRenamed = RenamedSymbols.find(B->getName()) != RenamedSymbols.end(); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -79,8 +79,9 @@ // as variables in linker scripts. Doing so allows us to write expressions // like this: `alignment = 16; . = ALIGN(., alignment)` uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; - replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, - STT_NOTYPE, SymValue, 0, Sec, nullptr); + replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, + /*IsBitcode*/false, Visibility, STT_NOTYPE, + SymValue, 0, Sec, nullptr); return Sym->body(); } Index: lld/ELF/SymbolTable.h =================================================================== --- lld/ELF/SymbolTable.h +++ lld/ELF/SymbolTable.h @@ -39,6 +39,8 @@ public: void addFile(InputFile *File); void addCombinedLTOObject(); + void addLTOSymbolWrap(StringRef Name); + void addLTOSymbolAlias(StringRef Name); ArrayRef getSymbols() const { return SymVector; } ArrayRef *> getObjectFiles() const { return ObjectFiles; } @@ -135,6 +137,8 @@ // For LTO. std::unique_ptr LTO; + llvm::StringMap RenamedSymbols; + bool PostLTO = false; }; template struct Symtab { static SymbolTable *X; }; Index: lld/ELF/SymbolTable.cpp =================================================================== --- lld/ELF/SymbolTable.cpp +++ lld/ELF/SymbolTable.cpp @@ -118,8 +118,9 @@ // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) - LTO->add(*F); + LTO->add(*F, RenamedSymbols); + PostLTO = true; for (InputFile *File : LTO->compile()) { ObjectFile *Obj = cast>(File); DenseSet DummyGroups; @@ -154,6 +155,18 @@ Symtab.insert({CachedHashStringRef(Name), {-1, true}}); } +template void SymbolTable::addLTOSymbolWrap(StringRef Name) { + Twine WrappedName = "__wrap_" + Name; + Twine RealName = "__real_" + Name; + RenamedSymbols[WrappedName.str()] = true; + RenamedSymbols[RealName.str()] = true; + RenamedSymbols[Name] = true; +} + +template void SymbolTable::addLTOSymbolAlias(StringRef Name) { + RenamedSymbols[Name] = true; +} + // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::wrap(StringRef Name) { @@ -299,11 +312,11 @@ // We have a new defined symbol with the specified binding. Return 1 if the new // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are // strong defined symbols. -static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { +static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, bool postLTO) { if (WasInserted) return 1; SymbolBody *Body = S->body(); - if (Body->isLazy() || !Body->isInCurrentDSO()) + if ((postLTO && Body->isBitcode()) || Body->isLazy() || !Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; @@ -317,13 +330,19 @@ // is a conflict. If the new symbol wins, also update the binding. template static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, - bool IsAbsolute, typename ELFT::uint Value) { - if (int Cmp = compareDefined(S, WasInserted, Binding)) { - if (Cmp > 0) - S->Binding = Binding; + bool IsAbsolute, typename ELFT::uint Value, + bool postLTO) { + SymbolBody *B = S->body(); + if (int Cmp = compareDefined(S, WasInserted, Binding, postLTO)) { + if (Cmp > 0) { + if ((postLTO && B->isBitcode()) && + Binding == STB_WEAK && S->Binding != STB_WEAK) + ; + else + S->Binding = Binding; + } return Cmp; } - SymbolBody *B = S->body(); if (isa(B)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) @@ -346,7 +365,7 @@ bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); - int Cmp = compareDefined(S, WasInserted, Binding); + int Cmp = compareDefined(S, WasInserted, Binding, PostLTO); if (Cmp > 0) { S->Binding = Binding; replaceBody(S, N, Size, Alignment, StOther, Type, File); @@ -424,10 +443,10 @@ std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, - Section == nullptr, Value); + Section == nullptr, Value, PostLTO); if (Cmp > 0) - replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, - Value, Size, Section, File); + replaceBody(S, Name, /*IsLocal=*/false, /*IsBitcode*/false, + StOther, Type, Value, Size, Section, File); else if (Cmp == 0) reportDuplicate(S->body(), dyn_cast_or_null(Section), Value); @@ -470,10 +489,11 @@ std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, - /*IsAbs*/ false, /*Value*/ 0); + /*IsAbs*/ false, /*Value*/ 0, + PostLTO); if (Cmp > 0) - replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, - nullptr, F); + replaceBody(S, Name, /*IsLocal=*/false, /*IsBitcode*/true, + StOther, Type, 0, 0, nullptr, F); else if (Cmp == 0) reportDuplicate(S->body(), F); return S; Index: lld/ELF/Symbols.h =================================================================== --- lld/ELF/Symbols.h +++ lld/ELF/Symbols.h @@ -67,6 +67,7 @@ bool isShared() const { return SymbolKind == SharedKind; } bool isInCurrentDSO() const { return !isUndefined() && !isShared(); } bool isLocal() const { return IsLocal; } + bool isBitcode() const { return IsBitcode; } bool isPreemptible() const; StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } @@ -95,8 +96,8 @@ uint32_t GlobalDynIndex = -1; protected: - SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type); + SymbolBody(Kind K, StringRefZ Name, bool IsLocal, bool IsBitcode, + uint8_t StOther, uint8_t Type); const unsigned SymbolKind : 8; @@ -124,6 +125,9 @@ // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + // True if symbol was defined in a bitcode object + unsigned IsBitcode : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value @@ -149,7 +153,8 @@ // The base class for any defined symbols. class Defined : public SymbolBody { public: - Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); + Defined(Kind K, StringRefZ Name, bool IsLocal, bool IsBitcode, + uint8_t StOther, uint8_t Type); static bool classof(const SymbolBody *S) { return S->isDefined(); } }; @@ -175,10 +180,10 @@ // Regular defined symbols read from object file symbol tables. class DefinedRegular : public Defined { public: - DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, SectionBase *Section, - InputFile *File) - : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type), + DefinedRegular(StringRefZ Name, bool IsLocal, bool IsBitcode, + uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, + SectionBase *Section, InputFile *File) + : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, IsBitcode, StOther, Type), Value(Value), Size(Size), Section(Section) { this->File = File; } @@ -213,7 +218,8 @@ SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type, const void *ElfSym, const void *Verdef) - : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type), + : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, + /*IsBitcode*/false, StOther, Type), Verdef(Verdef), ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) @@ -265,7 +271,8 @@ protected: Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type) - : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {} + : SymbolBody(K, Name, /*IsLocal=*/false, /*IsBitcode*/false, + llvm::ELF::STV_DEFAULT, Type) {} }; // LazyArchive symbols represents symbols in archive files. Index: lld/ELF/Symbols.cpp =================================================================== --- lld/ELF/Symbols.cpp +++ lld/ELF/Symbols.cpp @@ -122,11 +122,12 @@ llvm_unreachable("invalid symbol kind"); } -SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) +SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, bool IsBitcode, + uint8_t StOther, uint8_t Type) : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} + IsInIgot(false), IsBitcode(IsBitcode), Type(Type), StOther(StOther), + Name(Name) {} // Returns true if a symbol can be replaced at load-time by a symbol // with the same name defined in other ELF executable or DSO. @@ -259,9 +260,9 @@ error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } -Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) - : SymbolBody(K, Name, IsLocal, StOther, Type) {} +Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, bool IsBitcode, + uint8_t StOther, uint8_t Type) + : SymbolBody(K, Name, IsLocal, IsBitcode, StOther, Type) {} template bool DefinedRegular::isMipsPIC() const { if (!Section || !isFunc()) @@ -277,14 +278,15 @@ Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, InputFile *File) - : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { + : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, /*IsBitcode*/false, + StOther, Type) { this->File = File; } DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t StOther, uint8_t Type, InputFile *File) - : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, - Type), + : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, + /*IsBitcode*/false, StOther, Type), Alignment(Alignment), Size(Size) { this->File = File; } Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ lld/ELF/SyntheticSections.cpp @@ -295,8 +295,9 @@ SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, uint64_t Size, InputSectionBase *Section) { - auto *S = make(Name, /*IsLocal*/ true, STV_DEFAULT, Type, - Value, Size, Section, nullptr); + auto *S = make(Name, /*IsLocal*/ true, /*IsBitcode*/ false, + STV_DEFAULT, Type, Value, Size, Section, + nullptr); if (InX::SymTab) InX::SymTab->addSymbol(S); return S; Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -560,8 +560,9 @@ continue; auto *Sym = - make("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, - /*Value=*/0, /*Size=*/0, IS, nullptr); + make("", /*IsLocal=*/true, /*IsBitcode*/false, + /*StOther=*/0, STT_SECTION, /*Value=*/0, + /*Size=*/0, IS, nullptr); InX::SymTab->addSymbol(Sym); } } Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -308,6 +308,7 @@ bool VisibleOutsideThinLTO = false; bool UnnamedAddr = true; + bool IsRenamed = false; /// This field keeps track of the partition number of this global. The /// regular LTO object is partition 0, while each ThinLTO object has its own @@ -366,7 +367,8 @@ /// each global symbol based on its internal resolution of that symbol. struct SymbolResolution { SymbolResolution() - : Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0) { + : Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0), + IsRenamed(0) { } /// The linker has chosen this definition of the symbol. unsigned Prevailing : 1; @@ -377,6 +379,10 @@ /// The definition of this symbol is visible outside of the LTO unit. unsigned VisibleToRegularObj : 1; + + /// Renamed version of the symbol which appeared in -wrap or -defsym linker + /// option. + unsigned IsRenamed : 1; }; } // namespace lto Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -407,7 +407,7 @@ // Set the partition to external if we know it is used elsewhere, e.g. // it is visible to a regular object, is referenced from llvm.compiler_used, // or was already recorded as being referenced from a different partition. - if (Res.VisibleToRegularObj || Sym.isUsed() || + if (Res.IsRenamed || Res.VisibleToRegularObj || Sym.isUsed() || (GlobalRes.Partition != GlobalResolution::Unknown && GlobalRes.Partition != Partition)) { GlobalRes.Partition = GlobalResolution::External; @@ -418,8 +418,9 @@ // Flag as visible outside of ThinLTO if visible from a regular object or // if this is a reference in the regular LTO partition. GlobalRes.VisibleOutsideThinLTO |= - (Res.VisibleToRegularObj || Sym.isUsed() || + (Res.IsRenamed || Res.VisibleToRegularObj || Sym.isUsed() || Partition == GlobalResolution::RegularLTO); + GlobalRes.IsRenamed = Res.IsRenamed; } static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, @@ -438,6 +439,8 @@ OS << 'l'; if (Res.VisibleToRegularObj) OS << 'x'; + if (Res.IsRenamed) + OS << 'r'; OS << '\n'; } OS.flush(); @@ -689,6 +692,8 @@ : GlobalValue::UnnamedAddr::None); if (R.second.Partition == 0) GV->setLinkage(GlobalValue::InternalLinkage); + if (R.second.IsRenamed == true) + GV->setLinkage(GlobalValue::WeakAnyLinkage); } if (Conf.PostInternalizeModuleHook &&