Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -1155,9 +1155,12 @@ if ((sym->symbolKind == Symbol::LazyArchiveKind && !cast(sym->file)->parsed) || (sym->symbolKind == Symbol::LazyObjectKind && - cast(sym->file)->extracted)) + cast(sym->file)->extracted)) { sym->replace(und); - else + // Prevent LTO from internalizing the symbol in case there is a + // reference to this symbol from this file. + sym->isUsedInRegularObj = true; + } else sym->resolve(und); continue; } Index: lld/test/ELF/lto/comdat-mixed-archive.test =================================================================== --- /dev/null +++ lld/test/ELF/lto/comdat-mixed-archive.test @@ -0,0 +1,58 @@ +REQUIRES: x86 + +;; This checks a case when an archive contains a bitcode and a regular object +;; files, and a comdat symbol is defined and used in both of them. Previously, +;; lld could lose the flag that the symbol is used in a regular object file +;; which led to the LTO backend internalizing the symbol and the linker +;; reporting an "undefined symbol" error. + +;; In this test, group "foo" in "obj.o" is rejected in favor of "bc.o" but we +;; need to prevent LTO from internalizing "foo" as there is still a reference +;; from outside the group in "obj.o". + +RUN: rm -rf %t.dir +RUN: split-file %s %t.dir +RUN: cd %t.dir + +RUN: llvm-mc -filetype=obj -triple=x86_64 start.s -o start.o +RUN: llvm-mc -filetype=obj -triple=x86_64 obj.s -o obj.o +RUN: llvm-as bc.ll -o bc.o +RUN: llvm-ar rc lib.a obj.o bc.o +RUN: ld.lld start.o lib.a -o /dev/null + +;--- start.s + .global _start, baz +_start: + call baz + +;--- obj.s + .weak foo + .global bar + + .section .text.foo,"axG",@progbits,foo,comdat +foo: + ret + + .section .text.bar,"ax",@progbits +bar: + call foo + +;--- bc.ll +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +$foo = comdat any + +declare void @bar() + +;; Note. "foo" is defined after declaring "bar" so that loading the regular +;; object file "obj.o" is triggered before processing the definition of "foo". +define linkonce_odr void @foo() comdat { + ret void +} + +define void @baz() { + call void @foo() + call void @bar() + ret void +}