Skip to content

Commit

Permalink
[lld][ELF] Error when deplibs adds new input file after LTO
Browse files Browse the repository at this point in the history
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 llvm#56070
  • Loading branch information
mysterymath committed Jul 12, 2024
1 parent 7d1b6b2 commit a750de6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2966,6 +2966,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// With this the symbol table should be complete. After this, no new names
// except a few linker-synthesized ones will be added to the symbol table.
const size_t numObjsBeforeLTO = ctx.objectFiles.size();
const size_t numInputFilesBeforeLTO = ctx.driver.files.size();
compileBitcodeFiles<ELFT>(skipLinkedOutput);

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

// ELF dependent libraries may have introduced new input files after LTO has
// completed. This is an error if the file hadn't already been parsed, since
// it's no longer legal to change the symbol table by parsing it.
auto newInputFiles = ArrayRef(ctx.driver.files).slice(numInputFilesBeforeLTO);
if (!newInputFiles.empty()) {
DenseSet<StringRef> oldFilenames;
for (InputFile *f :
ArrayRef(ctx.driver.files).slice(0, numInputFilesBeforeLTO))
oldFilenames.insert(f->getName());
for (InputFile *newFile : newInputFiles)
if (!oldFilenames.contains(newFile->getName()))
error("input file '" + newFile->getName() + "' added after LTO");
}

// Handle --exclude-libs again because lto.tmp may reference additional
// libcalls symbols defined in an excluded archive. This may override
// versionId set by scanVersionScript().
Expand Down
39 changes: 39 additions & 0 deletions lld/test/ELF/deplibs-lto.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# REQUIRES: x86

# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=aarch64 -o deplibs.o deplibs.s
# RUN: llvm-mc -filetype=obj -triple=aarch64 -o foo.o foo.s
# RUN: llvm-as -o lto.o lto.ll
# RUN: llvm-ar rc libdeplibs.a deplibs.o
# RUN: llvm-ar rc libfoo.a foo.o

## LTO emits a libcall (`__aarch64_ldadd4_relax`) that is resolved using a
## library (libdeplibc.a) that contains a `.deplibs` section pointing to a file
## not yet added to the link.

# RUN: not ld.lld lto.o -u a -L. -ldeplibs 2>&1 | FileCheck %s
# CHECK: error: input file 'foo.o' added after LTO

## Including the file before LTO prevents the issue.

# RUN: ld.lld lto.o -u a -L. -ldeplibs -lfoo

#--- foo.s
.global foo
foo:
#--- deplibs.s
.global __aarch64_ldadd4_relax
__aarch64_ldadd4_relax:
b foo
.section ".deplibs","MS",@llvm_dependent_libraries,1
.asciz "foo"
#--- lto.ll
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64"

define void @a(i32* nocapture %0) #0 {
%2 = atomicrmw add i32* %0, i32 1 monotonic, align 4
ret void
}

attributes #0 = { "target-features"="+outline-atomics" }

0 comments on commit a750de6

Please sign in to comment.