Skip to content

Commit 5b82741

Browse files
authored
[lld][ELF] Error when deplibs adds new input file after LTO (#98565)
Parsing the new input file's symbols might invalidate LTO codegen, but the semantics of deplibs require them to be parsed. Accordingly, report an error unless the file had already been added to the link. Fixes #56070
1 parent 7f06560 commit 5b82741

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

lld/ELF/Driver.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2966,6 +2966,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
29662966
// With this the symbol table should be complete. After this, no new names
29672967
// except a few linker-synthesized ones will be added to the symbol table.
29682968
const size_t numObjsBeforeLTO = ctx.objectFiles.size();
2969+
const size_t numInputFilesBeforeLTO = ctx.driver.files.size();
29692970
compileBitcodeFiles<ELFT>(skipLinkedOutput);
29702971

29712972
// Symbol resolution finished. Report backward reference problems,
@@ -2990,6 +2991,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
29902991
for (const DuplicateSymbol &d : ctx.duplicates)
29912992
reportDuplicate(*d.sym, d.file, d.section, d.value);
29922993

2994+
// ELF dependent libraries may have introduced new input files after LTO has
2995+
// completed. This is an error if the files haven't already been parsed, since
2996+
// changing the symbol table could break the semantic assumptions of LTO.
2997+
auto newInputFiles = ArrayRef(ctx.driver.files).slice(numInputFilesBeforeLTO);
2998+
if (!newInputFiles.empty()) {
2999+
DenseSet<StringRef> oldFilenames;
3000+
for (InputFile *f :
3001+
ArrayRef(ctx.driver.files).slice(0, numInputFilesBeforeLTO))
3002+
oldFilenames.insert(f->getName());
3003+
for (InputFile *newFile : newInputFiles)
3004+
if (!oldFilenames.contains(newFile->getName()))
3005+
errorOrWarn("input file '" + newFile->getName() + "' added after LTO");
3006+
}
3007+
29933008
// Handle --exclude-libs again because lto.tmp may reference additional
29943009
// libcalls symbols defined in an excluded archive. This may override
29953010
// versionId set by scanVersionScript().

lld/test/ELF/deplibs-lto.s

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# REQUIRES: aarch64
2+
3+
# RUN: rm -rf %t && split-file %s %t && cd %t
4+
# RUN: llvm-mc -filetype=obj -triple=aarch64 -o deplibs.o deplibs.s
5+
# RUN: llvm-mc -filetype=obj -triple=aarch64 -o foo.o foo.s
6+
# RUN: llvm-as -o lto.o lto.ll
7+
# RUN: llvm-ar rc libdeplibs.a deplibs.o
8+
# RUN: llvm-ar rc libfoo.a foo.o
9+
10+
## LTO emits a libcall (__aarch64_ldadd4_relax) that is resolved using a
11+
## library (libdeplibs.a) that contains a .deplibs section pointing to a file
12+
## (libfoo.a) not yet added to the link.
13+
# RUN: not ld.lld lto.o -u a -L. -ldeplibs 2>&1 | FileCheck %s
14+
# CHECK: error: input file 'foo.o' added after LTO
15+
16+
## Including the file before LTO prevents the issue.
17+
# RUN: ld.lld lto.o -u a -L. -ldeplibs -lfoo
18+
19+
#--- foo.s
20+
.global foo
21+
foo:
22+
#--- deplibs.s
23+
.global __aarch64_ldadd4_relax
24+
__aarch64_ldadd4_relax:
25+
b foo
26+
.section ".deplibs","MS",@llvm_dependent_libraries,1
27+
.asciz "foo"
28+
#--- lto.ll
29+
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
30+
target triple = "aarch64"
31+
32+
define void @a(i32* nocapture %0) #0 {
33+
%2 = atomicrmw add i32* %0, i32 1 monotonic, align 4
34+
ret void
35+
}
36+
37+
attributes #0 = { "target-features"="+outline-atomics" }

0 commit comments

Comments
 (0)