Skip to content

[lld/COFF] Fix -start-lib / -end-lib after reviews.llvm.org/D116434 - #120452

Merged
nico merged 2 commits into
llvm:mainfrom
nico:lld-coff-start-lib
Dec 19, 2024
Merged

nico merged 2 commits into
llvm:mainfrom
nico:lld-coff-start-lib

Conversation

@nico

@nico nico commented Dec 18, 2024

Copy link
Copy Markdown
Contributor

That change forgot to set lazy to false before calling addFile() in forceLazy() which caused addFile() to parse the file we want to force a load for to be added as a lazy object again instead of adding the file to ctx.objFileInstances.

This is caught by a pretty simple test (included).


Seems like nobody uses these flags in practice at the moment.

Fixes https://crbug.com/383531486

@llvmbot

llvmbot commented Dec 18, 2024 •

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-lld-coff
@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-lld

Author: Nico Weber (nico)

Changes

That change forgot to set lazy to false before calling addFile() in forceLazy() which caused addFile() to parse the file we want to force a load for to be added as a lazy object again instead of adding the file to ctx.objFileInstances.

This is caught by a pretty simple test (included).


Seems like nobody uses these flags in practice at the moment.

Fixes https://crbug.com/383531486


Full diff: https://github.com/llvm/llvm-project/pull/120452.diff

2 Files Affected:

  • (modified) lld/COFF/SymbolTable.cpp (+1)
  • (modified) lld/test/COFF/start-lib.ll (+75)
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 6b3375e13e8393..b1d375b2265835 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -116,6 +116,7 @@ static void forceLazy(Symbol *s) {
   }
   case Symbol::Kind::LazyObjectKind: {
     InputFile *file = cast<LazyObject>(s)->file;
+    file->lazy = false;
     file->symtab.addFile(file);
     break;
   }
diff --git a/lld/test/COFF/start-lib.ll b/lld/test/COFF/start-lib.ll
index f4f49ed4e4f6e6..02bf4c254ee185 100644
--- a/lld/test/COFF/start-lib.ll
+++ b/lld/test/COFF/start-lib.ll
@@ -79,3 +79,78 @@ define i32 @bar() {
 
 !llvm.linker.options = !{!0}
 !0 = !{!"/INCLUDE:bar"}
+
+
+; Check that lazy object files trigger loads correctly.
+; If the links succeed, that's enough, no additional tests needed.
+
+; RUN: llc -filetype=obj %t.dir/main2.ll -o %t-main2.obj
+; RUN: llc -filetype=obj %t.dir/foo.ll -o %t-foo.obj
+; RUN: llc -filetype=obj %t.dir/bar.ll -o %t-bar.obj
+; RUN: llc -filetype=obj %t.dir/baz.ll -o %t-baz.obj
+; RUN: opt -thinlto-bc %t.dir/main2.ll -o %t-main2.bc
+; RUN: opt -thinlto-bc %t.dir/foo.ll -o %t-foo.bc
+; RUN: opt -thinlto-bc %t.dir/bar.ll -o %t-bar.bc
+; RUN: opt -thinlto-bc %t.dir/baz.ll -o %t-baz.bc
+
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     %t-main2.obj %t-foo.obj %t-bar.obj %t-baz.obj
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     %t-main2.obj /start-lib %t-foo.obj %t-bar.obj %t-baz.obj /end-lib
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     /start-lib %t-foo.obj %t-bar.obj %t-baz.obj /end-lib %t-main2.obj
+
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     %t-main2.bc %t-foo.bc %t-bar.bc %t-baz.bc
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     %t-main2.bc /start-lib %t-foo.bc %t-bar.bc %t-baz.bc /end-lib
+; RUN: lld-link -out:%t2.exe -entry:main \
+; RUN:     /start-lib %t-foo.bc %t-bar.bc %t-baz.bc /end-lib %t-main2.bc
+
+#--- main2.ll
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare void @bar()
+
+define void @main() {
+  call void () @bar()
+  ret void
+}
+
+
+#--- foo.ll
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @foo() {
+  ret void
+}
+
+
+#--- bar.ll
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; One undef from the lazy obj file before it, one from the one after it.
+declare void @foo()
+declare void @baz()
+
+define void @bar() {
+  call void () @foo()
+  call void () @baz()
+  ret void
+}
+
+
+#--- baz.ll
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @baz() {
+  ret void
+}

@github-actions

github-actions Bot commented Dec 18, 2024 •

Copy link
Copy Markdown

✅ With the latest revision this PR passed the undef deprecator.

@nico

nico commented Dec 18, 2024

Copy link
Copy Markdown
Contributor Author

It complains about undef in this comment:

; One undef from the lazy obj file before it, one from the one after it.

I suppose I'll make it say "undefined symbol", but that check seems a bit overeager

nico added 2 commits December 19, 2024 11:26
That change forgot to set `lazy` to false before calling `addFile()`
in `forceLazy()` which caused `addFile()` to parse the file we want
to force a load for to be added as a lazy object again instead of
adding the file to `ctx.objFileInstances`.

This is caught by a pretty simple test (included).
@nico
nico force-pushed the lld-coff-start-lib branch from 214dcb8 to 511d55a Compare December 19, 2024 16:27
@nico
nico merged commit f8bcd93 into llvm:main Dec 19, 2024
@nico
nico deleted the lld-coff-start-lib branch December 19, 2024 16:30
nico added a commit that referenced this pull request Jan 24, 2025
…434 (#124294)

This is a follow-up to #120452 in a way.

Since lld/COFF does not yet insert all defined in an obj file before all
undefineds (ELF and MachO do this, see #67445 and things linked from
there), it's possible that:

1. We add an obj file a.obj
2. a.obj contains an undefined that's in b.obj, causing b.obj to be
added
3. b.obj contains an undefined that's in a part of a.obj that's not yet
in the symbol table, causing a recursive load of a.obj, which adds the
symbols in there twice, leading to duplicate symbol errors.

For normal archives, `ArchiveFile::addMember()` has a `seen` check to
prevent this. For start-lib lazy objects, we can just check if the
archive is still lazy at the recursive call.

This bug is similar to issue #59162.

(Eventually, we'll probably want to do what the MachO and ELF ports do.)

Includes a test that caused duplicate symbol diagnostics before this
code change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants