Skip to content

Commit d9b8120

Browse files
authored
[lld/COFF] Fix -start-lib / -end-lib more after reviews.llvm.org/D116434 (#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.
1 parent 544a3cb commit d9b8120

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

lld/COFF/InputFiles.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ void ArchiveFile::addMember(const Archive::Symbol &sym) {
151151
toCOFFString(symtab.ctx, sym));
152152

153153
// Return an empty buffer if we have already returned the same buffer.
154+
// FIXME: Remove this once we resolve all defineds before all undefineds in
155+
// ObjFile::initializeSymbols().
154156
if (!seen.insert(c.getChildOffset()).second)
155157
return;
156158

lld/COFF/SymbolTable.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ static void forceLazy(Symbol *s) {
5656
}
5757
case Symbol::Kind::LazyObjectKind: {
5858
InputFile *file = cast<LazyObject>(s)->file;
59+
// FIXME: Remove this once we resolve all defineds before all undefineds in
60+
// ObjFile::initializeSymbols().
61+
if (!file->lazy)
62+
return;
5963
file->lazy = false;
6064
file->symtab.ctx.driver.addFile(file);
6165
break;

lld/test/COFF/start-lib.ll

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,72 @@ target triple = "x86_64-pc-windows-msvc"
173173
define void @baz() {
174174
ret void
175175
}
176+
177+
178+
; Check cycles between symbols in two /start-lib files.
179+
; If the links succeed and does not emit duplicate symbol diagnostics,
180+
; that's enough.
181+
182+
; RUN: llc -filetype=obj %t.dir/main3.ll -o %t-main3.obj
183+
; RUN: llc -filetype=obj %t.dir/cycle1.ll -o %t-cycle1.obj
184+
; RUN: llc -filetype=obj %t.dir/cycle2.ll -o %t-cycle2.obj
185+
; RUN: opt -thinlto-bc %t.dir/main3.ll -o %t-main3.bc
186+
; RUN: opt -thinlto-bc %t.dir/cycle1.ll -o %t-cycle1.bc
187+
; RUN: opt -thinlto-bc %t.dir/cycle2.ll -o %t-cycle2.bc
188+
189+
; RUN: lld-link -out:%t3.exe -entry:main \
190+
; RUN: %t-main3.obj %t-cycle1.obj %t-cycle2.obj
191+
; RUN: lld-link -out:%t3.exe -entry:main \
192+
; RUN: %t-main3.obj /start-lib %t-cycle1.obj %t-cycle2.obj /end-lib
193+
; RUN: lld-link -out:%t3.exe -entry:main \
194+
; RUN: /start-lib %t-cycle1.obj %t-cycle2.obj /end-lib %t-main3.obj
195+
196+
; RUN: lld-link -out:%t3.exe -entry:main \
197+
; RUN: %t-main3.bc %t-cycle1.bc %t-cycle2.bc
198+
; RUN: lld-link -out:%t3.exe -entry:main \
199+
; RUN: %t-main3.bc /start-lib %t-cycle1.bc %t-cycle2.bc /end-lib
200+
; RUN: lld-link -out:%t3.exe -entry:main \
201+
; RUN: /start-lib %t-cycle1.bc %t-cycle2.bc /end-lib %t-main3.bc
202+
203+
#--- main3.ll
204+
205+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
206+
target triple = "x86_64-pc-windows-msvc"
207+
208+
declare void @foo1()
209+
210+
define void @main() {
211+
call void () @foo1()
212+
ret void
213+
}
214+
215+
#--- cycle1.ll
216+
217+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
218+
target triple = "x86_64-pc-windows-msvc"
219+
220+
declare void @bar()
221+
222+
define void @foo1() {
223+
; cycle1.ll pulls in cycle2.ll for bar(), and cycle2.ll then pulls in
224+
; cycle1.ll again for foo2().
225+
call void () @bar()
226+
ret void
227+
}
228+
229+
define void @foo2() {
230+
ret void
231+
}
232+
233+
234+
#--- cycle2.ll
235+
236+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
237+
target triple = "x86_64-pc-windows-msvc"
238+
239+
declare void @foo2()
240+
241+
define void @bar() {
242+
call void () @foo2()
243+
ret void
244+
}

0 commit comments

Comments
 (0)