Index: ELF/LTO.h =================================================================== --- ELF/LTO.h +++ ELF/LTO.h @@ -47,6 +47,7 @@ llvm::IRMover Mover; std::vector> OwningData; llvm::StringSet<> InternalizedSyms; + llvm::StringSet<> AsmUndefinedRefs; std::string TheTriple; }; } Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ 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,26 @@ replaceBody(S, S->body()->getName(), STV_DEFAULT, S->body()->Type); } +static void handleUndefinedAsmRefs(const BasicSymbolRef &Sym, GlobalValue *GV, + llvm::StringSet<> &AsmUndefinedRefs) { + // GV associated => no asm, bail out. + if (GV) + return; + + // This is an undefined reference to a symbol + // referenced from 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> Buffer; + { + raw_svector_ostream OS(Buffer); + Sym.printName(OS); + } + const char *Name = Buffer.c_str(); + AsmUndefinedRefs.insert(Name); +} + void BitcodeCompiler::add(BitcodeFile &F) { std::unique_ptr Obj = std::move(F.Obj); std::vector Keep; @@ -181,8 +202,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 +294,6 @@ internalize(*GV); } - if (Config->SaveTemps) - saveBCFile(*Combined, ".lto.bc"); - std::string Msg; const Target *T = TargetRegistry::lookupTarget(TheTriple, Msg); if (!T) @@ -287,6 +307,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: test/ELF/lto/asmundef.ll =================================================================== --- test/ELF/lto/asmundef.ll +++ test/ELF/lto/asmundef.ll @@ -0,0 +1,23 @@ +; 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"