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.first, Def.second); + Symtab.addCombinedLTOObject(); if (ErrorCount) return; 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::function_ref isRenamed); std::vector compile(); private: Index: lld/ELF/LTO.cpp =================================================================== --- lld/ELF/LTO.cpp +++ lld/ELF/LTO.cpp @@ -112,7 +112,7 @@ STV_DEFAULT, S->body()->Type, nullptr); } -void BitcodeCompiler::add(BitcodeFile &F) { +void BitcodeCompiler::add(BitcodeFile &F, function_ref isRenamed) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector Syms = F.getSymbols(); @@ -136,6 +136,7 @@ Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) undefine(Sym); + R.LinkerRedefined = isRenamed(B->getName()); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } 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 Alias, StringRef Name); ArrayRef getSymbols() const { return SymVector; } ArrayRef *> getObjectFiles() const { return ObjectFiles; } @@ -135,6 +137,8 @@ // For LTO. std::unique_ptr LTO; + // Save renamed symbols and their original pre-LTO bindings. + llvm::StringMap RenamedSymbols; }; template struct Symtab { static SymbolTable *X; }; Index: lld/ELF/SymbolTable.cpp =================================================================== --- lld/ELF/SymbolTable.cpp +++ lld/ELF/SymbolTable.cpp @@ -117,8 +117,11 @@ // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); + auto isRenamed = [&] (StringRef Name) { + return RenamedSymbols.find(Name) != RenamedSymbols.end(); + }; for (BitcodeFile *F : BitcodeFiles) - LTO->add(*F); + LTO->add(*F, isRenamed); for (InputFile *File : LTO->compile()) { ObjectFile *Obj = cast>(File); @@ -126,6 +129,17 @@ Obj->parse(DummyGroups); ObjectFiles.push_back(Obj); } + + // Restore bindings of renamed symbols. + for (StringMap::iterator i = RenamedSymbols.begin(); + i != RenamedSymbols.end(); + i++) { + SymbolBody *Body = find(i->first()); + if (Body) { + Symbol *Sym = Body->symbol(); + Sym->Binding = i->second; + } + } } template @@ -154,6 +168,31 @@ Symtab.insert({CachedHashStringRef(Name), {-1, true}}); } +static uint8_t getSymbolBinding(SymbolBody *SB) { + uint8_t Binding = STB_WEAK; + if (SB) { + Symbol *S = SB->symbol(); + Binding = S->Binding; + } + return Binding; +} + +template void SymbolTable::addLTOSymbolWrap(StringRef Name) { + std::string WrappedName = "__wrap_" + Name.str(); + std::string RealName = "__real_" + Name.str(); + uint8_t Binding = getSymbolBinding(find(Name)); + RenamedSymbols[WrappedName] = Binding; + RenamedSymbols[RealName] = Binding; + RenamedSymbols[Name] = Binding; +} + +template void SymbolTable::addLTOSymbolAlias(StringRef Alias, + StringRef Name) { + uint8_t Binding = getSymbolBinding(find(Name)); + RenamedSymbols[Name] = Binding; + RenamedSymbols[Name] = Binding; +} + // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::wrap(StringRef Name) { Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -366,7 +366,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), + LinkerRedefined(0) { } /// The linker has chosen this definition of the symbol. unsigned Prevailing : 1; @@ -377,6 +378,10 @@ /// The definition of this symbol is visible outside of the LTO unit. unsigned VisibleToRegularObj : 1; + + /// Linker redefined version of the symbol which appeared in -wrap or -defsym + /// linker option. + unsigned LinkerRedefined : 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.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || (GlobalRes.Partition != GlobalResolution::Unknown && GlobalRes.Partition != Partition)) { GlobalRes.Partition = GlobalResolution::External; @@ -418,7 +418,7 @@ // 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.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || Partition == GlobalResolution::RegularLTO); } @@ -438,6 +438,8 @@ OS << 'l'; if (Res.VisibleToRegularObj) OS << 'x'; + if (Res.LinkerRedefined) + OS << 'r'; OS << '\n'; } OS.flush(); @@ -542,6 +544,8 @@ if (Sym.isUndefined()) continue; Keep.push_back(GV); + if (Res.LinkerRedefined) + GV->setLinkage(GlobalValue::WeakAnyLinkage); switch (GV->getLinkage()) { default: break;