Index: ELF/LTO.h =================================================================== --- ELF/LTO.h +++ ELF/LTO.h @@ -23,6 +23,7 @@ #include "lld/Core/LLVM.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Linker/IRMover.h" @@ -46,6 +47,7 @@ llvm::IRMover Mover{Combined}; SmallString<0> OwningData; std::unique_ptr MB; + llvm::StringSet<> InternalizedSyms; }; } } Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -97,6 +97,18 @@ GV->setLinkage(GlobalValue::WeakODRLinkage); break; } + + // We collect the set of symbols we want to internalize here + // and change the linkage after the IRMover executed, i.e. after + // we imported the symbols and satisfied undefined references + // to it. We can't just change linkage here because otherwise + // the IRMover will just rename the symbol. + // Shared libraries need to be handled slightly differently. + // For now, let's be conservative and just never internalize + // symbols when creating a shared library. + if (!Config->Shared && !B->isUsedInRegularObj()) + InternalizedSyms.insert(GV->getName()); + Keep.push_back(GV); } @@ -104,10 +116,22 @@ [](GlobalValue &, IRMover::ValueAdder) {}); } +static void internalize(GlobalValue &GV) { + assert(!GV.hasLocalLinkage() && + "Trying to internalize a symbol with local linkage!") ; + GV.setLinkage(GlobalValue::InternalLinkage); +} + // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile. template std::unique_ptr> BitcodeCompiler::compile() { + for (const auto &Name : InternalizedSyms) { + GlobalValue *GV = Combined.getNamedValue(Name.first()); + assert(GV); + internalize(*GV); + } + if (Config->SaveTemps) saveBCFile(Combined, ".lto.bc"); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -120,7 +120,8 @@ IsFunc = Type == llvm::ELF::STT_FUNC; IsTls = Type == llvm::ELF::STT_TLS; IsGnuIFunc = Type == llvm::ELF::STT_GNU_IFUNC; - IsUsedInRegularObj = K != SharedKind && K != LazyKind; + IsUsedInRegularObj = + K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; } const unsigned SymbolKind : 8; Index: test/ELF/lto/internalize-basic.ll =================================================================== --- test/ELF/lto/internalize-basic.ll +++ test/ELF/lto/internalize-basic.ll @@ -0,0 +1,21 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps +; RUN: llvm-dis < %t2.lto.bc | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @_start() { + ret void +} + +define hidden void @foo() { + ret void +} + +; Check that _start is not internalized. +; CHECK: define void @_start() + +; Check that foo function is correctly internalized. +; CHECK: define internal void @foo()