Skip to content

Commit 83305fa

Browse files
authored
[lld][WebAssembly] Fix bitcode LTO order in archive parsing (#73095)
When doing LTO on multiple archives, the order with which bitcodes are linked to the LTO module is hard to control, given that processing undefined symbols can lead to parsing of an object file, which in turn lead to parsing of another object file before finishing parsing of the previous file. This can result in encountering a non-prevailing comdat first when linking, which can make the the symbol undefined, and the real definition is added later with an additional prefix to avoid duplication (e.g. `__cxx_global_var_init` and `__cxx_global_var_init.2`) So this one-line fix ensures we compile bitcodes in the order that we process comdats, so that when multiple archived bitcode files have the same variable with the same comdat, we make sure that the prevailing comdat will be linked first in the LTO. Fixes #62243.
1 parent 5d57041 commit 83305fa

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
2+
target triple = "wasm32-unknown-unknown"
3+
4+
; Generated from this C++ code and simplified manually:
5+
;
6+
; int foo();
7+
; inline int unused = foo();
8+
;
9+
; int main() {
10+
; return foo();
11+
; }
12+
13+
$unused = comdat any
14+
15+
@unused = linkonce_odr global i32 0, comdat, align 4
16+
@_ZGV6unused = linkonce_odr global i32 0, comdat($unused), align 4
17+
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init, ptr @unused }]
18+
19+
define internal void @__cxx_global_var_init() comdat($unused) {
20+
entry:
21+
%0 = load i8, ptr @_ZGV6unused, align 4
22+
%1 = and i8 %0, 1
23+
%guard.uninitialized = icmp eq i8 %1, 0
24+
br i1 %guard.uninitialized, label %init.check, label %init.end
25+
26+
init.check: ; preds = %entry
27+
store i8 1, ptr @_ZGV6unused, align 4
28+
%call = call i32 @foo()
29+
store i32 %call, ptr @unused, align 4
30+
br label %init.end
31+
32+
init.end: ; preds = %init.check, %entry
33+
ret void
34+
}
35+
36+
declare i32 @foo()
37+
38+
define i32 @main() {
39+
entry:
40+
%call = call i32 @foo()
41+
ret i32 %call
42+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128"
2+
target triple = "wasm32-unknown-unknown"
3+
4+
; Generated from this C++ code and simplified manually:
5+
;
6+
; int foo();
7+
; inline int unused = foo();
8+
;
9+
; int foo() {
10+
; return 42;
11+
; }
12+
13+
$unused = comdat any
14+
15+
@unused = linkonce_odr global i32 0, comdat, align 4
16+
@_ZGV6unused = linkonce_odr global i32 0, comdat($unused), align 4
17+
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init, ptr @unused }]
18+
19+
define internal void @__cxx_global_var_init() comdat($unused) {
20+
entry:
21+
%0 = load i8, ptr @_ZGV6unused, align 4
22+
%1 = and i8 %0, 1
23+
%guard.uninitialized = icmp eq i8 %1, 0
24+
br i1 %guard.uninitialized, label %init.check, label %init.end
25+
26+
init.check: ; preds = %entry
27+
store i8 1, ptr @_ZGV6unused, align 4
28+
%call = call i32 @foo()
29+
store i32 %call, ptr @unused, align 4
30+
br label %init.end
31+
32+
init.end: ; preds = %init.check, %entry
33+
ret void
34+
}
35+
36+
define i32 @foo() {
37+
entry:
38+
ret i32 42
39+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; Check if we handle a variable (here __cxx_global_var_init) in different LTO
2+
; bitcode modules sharing a comdat.
3+
4+
; RUN: llvm-as %S/Inputs/comdat_ordering1.ll -o %t1.o
5+
; RUN: llvm-as %S/Inputs/comdat_ordering2.ll -o %t2.o
6+
; RUN: llvm-ar rcs %t1.a %t1.o
7+
; RUN: llvm-ar rcs %t2.a %t2.o
8+
; RUN: wasm-ld %t1.a %t2.a -o %t.wasm --no-entry --export=main --export=__wasm_call_ctors
9+
; RUN: obj2yaml %t.wasm | FileCheck %s
10+
11+
; CHECK: - Type: CUSTOM
12+
; CHECK-NEXT: Name: name
13+
; CHECK-NEXT: FunctionNames:
14+
; CHECK-NEXT: - Index: 0
15+
; CHECK-NEXT: Name: __wasm_call_ctors
16+
; CHECK-NEXT: - Index: 1
17+
; CHECK-NEXT: Name: __cxx_global_var_init
18+
19+
; CHECK-NOT: Name: __cxx_global_var_init.2

lld/wasm/SymbolTable.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ void SymbolTable::addFile(InputFile *file, StringRef symName) {
5050

5151
// LLVM bitcode file
5252
if (auto *f = dyn_cast<BitcodeFile>(file)) {
53-
f->parse(symName);
53+
// This order, first adding to `bitcodeFiles` and then parsing is necessary.
54+
// See https://github.com/llvm/llvm-project/pull/73095
5455
bitcodeFiles.push_back(f);
56+
f->parse(symName);
5557
return;
5658
}
5759

0 commit comments

Comments
 (0)