Index: lld/trunk/ELF/LTO.h
===================================================================
--- lld/trunk/ELF/LTO.h
+++ lld/trunk/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<MemoryBuffer> MB;
+  llvm::StringSet<> InternalizedSyms;
 };
 }
 }
Index: lld/trunk/ELF/LTO.cpp
===================================================================
--- lld/trunk/ELF/LTO.cpp
+++ lld/trunk/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 <class ELFT>
 std::unique_ptr<elf::ObjectFile<ELFT>> 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: lld/trunk/ELF/Symbols.h
===================================================================
--- lld/trunk/ELF/Symbols.h
+++ lld/trunk/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: lld/trunk/test/ELF/lto/internalize-basic.ll
===================================================================
--- lld/trunk/test/ELF/lto/internalize-basic.ll
+++ lld/trunk/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()