Skip to content

Commit 7f9a004

Browse files
authored
[LLD] [COFF] Error out if new LTO objects are pulled in after the main LTO compilation (#71337)
Normally, this shouldn't happen. It can happen in exceptional circumstances, if the compiled output of a bitcode object file references symbols that weren't listed as undefined in the bitcode object file itself. This can at least happen in the following cases: - A custom SEH personality is set via asm() - Compiler generated calls to builtin helper functions, such as __chkstk, or __rt_sdiv on arm Both of these produce undefined references to symbols after compiling to a regular object file, that aren't visible on the level of the IR object file. This is only an issue if the referenced symbols are provided as LTO objects themselves; loading regular object files after the LTO compilation works fine. Custom SEH personalities are rare, but one CRT startup file in mingw-w64 does this. The referenced pesonality function is usually provided via an import library, but for WinStore targets, a local dummy reimplementation in C is used, which can be an LTO object. Generated calls to builtins is very common, but the builtins aren't usually provided as LTO objects (compiler-rt's builtins explicitly pass -fno-lto when building), and many of the builtins are provided as raw .S assembly files, which don't get built as LTO objects anyway, even if built with -flto. If hitting this unusual, but possible, situation, error out cleanly with a clear message rather than crashing.
1 parent 303370e commit 7f9a004

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

lld/COFF/SymbolTable.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ void SymbolTable::addFile(InputFile *file) {
6161
if (auto *f = dyn_cast<ObjFile>(file)) {
6262
ctx.objFileInstances.push_back(f);
6363
} else if (auto *f = dyn_cast<BitcodeFile>(file)) {
64+
if (ltoCompilationDone) {
65+
error("LTO object file " + toString(file) + " linked in after "
66+
"doing LTO compilation.");
67+
}
6468
ctx.bitcodeFileInstances.push_back(f);
6569
} else if (auto *f = dyn_cast<ImportFile>(file)) {
6670
ctx.importFileInstances.push_back(f);
@@ -876,6 +880,7 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
876880
}
877881

878882
void SymbolTable::compileBitcodeFiles() {
883+
ltoCompilationDone = true;
879884
if (ctx.bitcodeFileInstances.empty())
880885
return;
881886

lld/COFF/SymbolTable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class SymbolTable {
133133

134134
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> symMap;
135135
std::unique_ptr<BitcodeCompiler> lto;
136+
bool ltoCompilationDone = false;
136137

137138
COFFLinkerContext &ctx;
138139
};

lld/test/COFF/lto-late-arm.ll

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; REQUIRES: arm
2+
3+
;; A bitcode file can generate undefined references to symbols that weren't
4+
;; listed as undefined on the bitcode file itself, when lowering produces
5+
;; calls to e.g. builtin helper functions. If these functions are provided
6+
;; as LTO bitcode, the linker would hit an unhandled state. (In practice,
7+
;; compiler-rt builtins are always compiled with -fno-lto, so this shouldn't
8+
;; happen.)
9+
10+
; RUN: rm -rf %t.dir
11+
; RUN: split-file %s %t.dir
12+
; RUN: llvm-as %t.dir/main.ll -o %t.main.obj
13+
; RUN: llvm-as %t.dir/sdiv.ll -o %t.sdiv.obj
14+
; RUN: llvm-ar rcs %t.sdiv.lib %t.sdiv.obj
15+
16+
; RUN: env LLD_IN_TEST=1 not lld-link /entry:entry %t.main.obj %t.sdiv.lib /out:%t.exe /subsystem:console 2>&1 | FileCheck %s
17+
18+
; CHECK: error: LTO object file lto-late-arm.ll.tmp.sdiv.lib(lto-late-arm.ll.tmp.sdiv.obj) linked in after doing LTO compilation.
19+
20+
;--- main.ll
21+
target datalayout = "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
22+
target triple = "thumbv7-w64-windows-gnu"
23+
24+
@num = dso_local global i32 100
25+
26+
define dso_local arm_aapcs_vfpcc i32 @entry(i32 %param) {
27+
entry:
28+
%0 = load i32, ptr @num
29+
%div = sdiv i32 %0, %param
30+
ret i32 %div
31+
}
32+
;--- sdiv.ll
33+
target datalayout = "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
34+
target triple = "thumbv7-w64-windows-gnu"
35+
36+
define dso_local arm_aapcs_vfpcc void @__rt_sdiv() {
37+
entry:
38+
ret void
39+
}

lld/test/COFF/lto-late-personality.ll

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; REQUIRES: x86
2+
3+
;; A bitcode file can generate undefined references to symbols that weren't
4+
;; listed as undefined on the bitcode file itself, if there's a reference to
5+
;; an unexpected personality routine via asm(). If the personality function
6+
;; is provided as LTO bitcode, the linker would hit an unhandled state.
7+
8+
; RUN: rm -rf %t.dir
9+
; RUN: split-file %s %t.dir
10+
; RUN: llvm-as %t.dir/main.ll -o %t.main.obj
11+
; RUN: llvm-as %t.dir/other.ll -o %t.other.obj
12+
; RUN: llvm-as %t.dir/personality.ll -o %t.personality.obj
13+
; RUN: llvm-ar rcs %t.personality.lib %t.personality.obj
14+
15+
; RUN: env LLD_IN_TEST=1 not lld-link /entry:entry %t.main.obj %t.other.obj %t.personality.lib /out:%t.exe /subsystem:console /opt:lldlto=0 /debug:symtab 2>&1 | FileCheck %s
16+
17+
; CHECK: error: LTO object file lto-late-personality.ll.tmp.personality.lib(lto-late-personality.ll.tmp.personality.obj) linked in after doing LTO compilation.
18+
19+
;--- main.ll
20+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
21+
target triple = "x86_64-w64-windows-gnu"
22+
23+
define i32 @entry() {
24+
entry:
25+
tail call void @other()
26+
tail call void asm sideeffect ".seh_handler __C_specific_handler, @except\0A", "~{dirflag},~{fpsr},~{flags}"()
27+
ret i32 0
28+
}
29+
30+
declare dso_local void @other()
31+
32+
;--- other.ll
33+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
34+
target triple = "x86_64-w64-windows-gnu"
35+
36+
define dso_local void @other() {
37+
entry:
38+
ret void
39+
}
40+
41+
;--- personality.ll
42+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
43+
target triple = "x86_64-w64-windows-gnu"
44+
45+
define void @__C_specific_handler() {
46+
entry:
47+
ret void
48+
}

0 commit comments

Comments
 (0)