Index: lld/trunk/ELF/CMakeLists.txt =================================================================== --- lld/trunk/ELF/CMakeLists.txt +++ lld/trunk/ELF/CMakeLists.txt @@ -31,6 +31,7 @@ Core IPO Linker + LTO Object Option Passes Index: lld/trunk/ELF/LTO.h =================================================================== --- lld/trunk/ELF/LTO.h +++ lld/trunk/ELF/LTO.h @@ -47,6 +47,7 @@ llvm::IRMover Mover; std::vector> OwningData; llvm::StringSet<> InternalizedSyms; + llvm::StringSet<> AsmUndefinedRefs; std::string TheTriple; }; } Index: lld/trunk/ELF/LTO.cpp =================================================================== --- lld/trunk/ELF/LTO.cpp +++ lld/trunk/ELF/LTO.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" +#include "llvm/LTO/UpdateCompilerUsed.h" #include "llvm/Linker/IRMover.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/StringSaver.h" @@ -153,6 +154,21 @@ replaceBody(S, S->body()->getName(), STV_DEFAULT, S->body()->Type); } +static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV, + StringSet<> &AsmUndefinedRefs) { + // GV associated => not an assembly symbol, bail out. + if (GV) + return; + + // This is an undefined reference to a symbol in asm. We put that in + // compiler.used, so that we can preserve it from being dropped from + // the output, without necessarily preventing its internalization. + SmallString<64> Name; + raw_svector_ostream OS(Name); + Sym.printName(OS); + AsmUndefinedRefs.insert(Name.str()); +} + void BitcodeCompiler::add(BitcodeFile &F) { std::unique_ptr Obj = std::move(F.Obj); std::vector Keep; @@ -181,8 +197,10 @@ if (BitcodeFile::shouldSkip(Flags)) continue; Symbol *S = Syms[BodyIndex++]; - if (Flags & BasicSymbolRef::SF_Undefined) + if (Flags & BasicSymbolRef::SF_Undefined) { + handleUndefinedAsmRefs(Sym, GV, AsmUndefinedRefs); continue; + } auto *B = dyn_cast(S->body()); if (!B || B->File != &F) continue; @@ -271,9 +289,6 @@ internalize(*GV); } - if (Config->SaveTemps) - saveBCFile(*Combined, ".lto.bc"); - std::string Msg; const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg); if (!T) @@ -291,6 +306,14 @@ }; std::unique_ptr TM = CreateTargetMachine(); + + // Update llvm.compiler.used so that optimizations won't strip + // off AsmUndefinedReferences. + UpdateCompilerUsed(*Combined, *TM, AsmUndefinedRefs); + + if (Config->SaveTemps) + saveBCFile(*Combined, ".lto.bc"); + runLTOPasses(*Combined, *TM); if (HasError) return {}; Index: lld/trunk/test/ELF/lto/asmundef.ll =================================================================== --- lld/trunk/test/ELF/lto/asmundef.ll +++ lld/trunk/test/ELF/lto/asmundef.ll @@ -0,0 +1,25 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps +; RUN: llvm-dis %t.lto.bc -o - | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm ".weak patatino" +module asm ".equ patatino, foo" + +declare void @patatino() + +define void @foo() { + ret void +} + +define void @_start() { + call void @patatino() + ret void +} + +; CHECK: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" +; CHECK: define internal void @foo +