Skip to content

Commit 99e7350

Browse files
authored
IRSymTab: Record _GLOBAL_OFFSET_TABLE_ for ELF x86
In ELF, relocatable files generated for x86-32 and some code models of x86-64 (medium, large) may reference the special symbol `_GLOBAL_OFFSET_TABLE_` that is not used in the IR. In an LTO link, if there is no regular relocatable file referencing the special symbol, the linker may not define the symbol and lead to a spurious "undefined symbol" error. Fix #61101: record that `_GLOBAL_OFFSET_TABLE_` is used in the IR symbol table. Note: The `PreservedSymbols` mechanism (https://reviews.llvm.org/D112595) that just sets `FB_used` is not applicable. The `getRuntimeLibcallSymbols` for extracting lazy runtime library symbols is for symbols that are "always" potentially used, but linkers don't have the code model information to make a precise decision. Pull Request: #89463
1 parent 9c4735e commit 99e7350

File tree

8 files changed

+121
-5
lines changed

8 files changed

+121
-5
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; REQUIRES: x86
2+
;; LTO-generated relocatable files may reference _GLOBAL_OFFSET_TABLE_ while
3+
;; the IR does not mention _GLOBAL_OFFSET_TABLE_.
4+
;; Test that there is no spurious "undefined symbol" error.
5+
6+
; RUN: rm -rf %t && mkdir %t && cd %t
7+
; RUN: llvm-as %s -o a.bc
8+
; RUN: ld.lld -pie a.bc -o a
9+
; RUN: llvm-nm a | FileCheck %s
10+
11+
; CHECK: d _GLOBAL_OFFSET_TABLE_
12+
13+
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128"
14+
target triple = "i386-pc-linux-gnu"
15+
16+
@i = global i32 0
17+
18+
define dso_local void @_start() {
19+
entry:
20+
%0 = load i32, ptr @i
21+
%inc = add nsw i32 %0, 1
22+
store i32 %inc, ptr @i
23+
ret void
24+
}
25+
26+
!llvm.module.flags = !{!0, !1}
27+
28+
!0 = !{i32 8, !"PIC Level", i32 2}
29+
!1 = !{i32 7, !"PIE Level", i32 2}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
; REQUIRES: x86
2+
;; LTO-generated relocatable files may reference _GLOBAL_OFFSET_TABLE_ while
3+
;; the IR does not mention _GLOBAL_OFFSET_TABLE_.
4+
;; Test that there is no spurious "undefined symbol" error.
5+
6+
; RUN: rm -rf %t && split-file %s %t && cd %t
7+
; RUN: opt -module-summary b.ll -o b.bc
8+
9+
;; Test Thin LTO.
10+
; RUN: cat a.ll medium.ll | opt -module-summary - -o medium.bc
11+
; RUN: ld.lld -pie --no-relax medium.bc b.bc -o medium
12+
; RUN: llvm-objdump -dt medium | FileCheck %s
13+
14+
;; Test regular LTO.
15+
; RUN: cat a.ll large.ll | llvm-as - -o large.bc
16+
; RUN: ld.lld -pie large.bc b.bc -o large
17+
; RUN: llvm-objdump -dt large | FileCheck %s
18+
19+
;; Explicit reference of _GLOBAL_OFFSET_TABLE_ is fine.
20+
; RUN: cat a.ll medium.ll ref.ll | opt -module-summary - -o ref.bc
21+
; RUN: ld.lld -pie -u ref ref.bc b.bc -y _GLOBAL_OFFSET_TABLE_ -o ref 2>&1 | FileCheck %s --check-prefix=TRACE
22+
; RUN: llvm-objdump -dt ref | FileCheck %s
23+
24+
; TRACE: ref.bc: reference to _GLOBAL_OFFSET_TABLE_
25+
; TRACE-NEXT: ref.bc: reference to _GLOBAL_OFFSET_TABLE_
26+
; TRACE-NEXT: <internal>: definition of _GLOBAL_OFFSET_TABLE_
27+
; TRACE-NEXT: ref.lto.ref.o: reference to _GLOBAL_OFFSET_TABLE_
28+
29+
;; The IR symbol table references _GLOBAL_OFFSET_TABLE_, which causes lld to define the symbol.
30+
; CHECK: .got.plt 0000000000000000 .hidden _GLOBAL_OFFSET_TABLE_
31+
; CHECK: movabsq
32+
33+
;--- a.ll
34+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
35+
target triple = "x86_64-unknown-linux-gnu"
36+
37+
@i = external global i32
38+
39+
define dso_local void @_start() {
40+
entry:
41+
%0 = load i32, ptr @i
42+
%inc = add nsw i32 %0, 1
43+
store i32 %inc, ptr @i
44+
ret void
45+
}
46+
47+
!llvm.module.flags = !{!0, !1, !2, !3}
48+
49+
!0 = !{i32 8, !"PIC Level", i32 2}
50+
!1 = !{i32 7, !"PIE Level", i32 2}
51+
!2 = !{i32 1, !"Large Data Threshold", i64 0}
52+
53+
;--- medium.ll
54+
!3 = !{i32 1, !"Code Model", i32 3}
55+
56+
;--- large.ll
57+
!3 = !{i32 1, !"Code Model", i32 4}
58+
59+
;--- ref.ll
60+
@_GLOBAL_OFFSET_TABLE_ = external global [0 x i8]
61+
62+
define dso_local ptr @ref() {
63+
entry:
64+
ret ptr @_GLOBAL_OFFSET_TABLE_
65+
}
66+
67+
;--- b.ll
68+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
69+
target triple = "x86_64-unknown-linux-gnu"
70+
71+
@i = global i32 0

llvm/lib/Object/ModuleSymbolTable.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,20 @@ void ModuleSymbolTable::CollectAsmSymbols(
175175
AsmSymbol(Key, BasicSymbolRef::Flags(Res));
176176
}
177177
});
178+
179+
// In ELF, object code generated for x86-32 and some code models of x86-64 may
180+
// reference the special symbol _GLOBAL_OFFSET_TABLE_ that is not used in the
181+
// IR. Record it like inline asm symbols.
182+
Triple TT(M.getTargetTriple());
183+
if (!TT.isOSBinFormatELF() || !TT.isX86())
184+
return;
185+
auto CM = M.getCodeModel();
186+
if (TT.getArch() == Triple::x86 || CM == CodeModel::Medium ||
187+
CM == CodeModel::Large) {
188+
AsmSymbol("_GLOBAL_OFFSET_TABLE_",
189+
BasicSymbolRef::Flags(BasicSymbolRef::SF_Undefined |
190+
BasicSymbolRef::SF_Global));
191+
}
178192
}
179193

180194
void ModuleSymbolTable::CollectAsmSymvers(

llvm/test/LTO/X86/codemodel-2.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.o
2-
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
2+
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
33
; RUN: llvm-objdump --no-print-imm-hex -d %t.s.0 | FileCheck %s --check-prefix=CHECK-LARGE
44

55
target triple = "x86_64-unknown-linux-gnu"

llvm/test/LTO/X86/codemodel-3.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
; RUN: llvm-as %s -o %t0.o
22
; RUN: llvm-as < %p/Inputs/codemodel-3.ll > %t1.o
3-
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s
3+
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px -r %t0.o,_GLOBAL_OFFSET_TABLE_, \
4+
; RUN: -r %t1.o,_GLOBAL_OFFSET_TABLE_, %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s
45

56
target triple = "x86_64-unknown-linux-gnu"
67
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

llvm/test/LTO/X86/largedatathreshold-1.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.o
2-
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
2+
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
33
; RUN: llvm-objdump -d %t.s.0 | FileCheck %s
44

55
target triple = "x86_64-unknown-linux-gnu"

llvm/test/LTO/X86/largedatathreshold-2.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; RUN: llvm-as %s -o %t.o
2-
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
2+
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
33
; RUN: llvm-objdump -d %t.s.0 | FileCheck %s
44

55
target triple = "x86_64-unknown-linux-gnu"

llvm/test/LTO/X86/largedatathreshold-3.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
; RUN: llvm-as %s -o %t0.o
22
; RUN: llvm-as < %p/Inputs/largedatathreshold.ll > %t1.o
3-
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s
3+
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px -r %t0.o,_GLOBAL_OFFSET_TABLE_, \
4+
; RUN: -r %t1.o,_GLOBAL_OFFSET_TABLE_, %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s
45

56
; CHECK: 'Large Data Threshold': IDs have conflicting values
67

0 commit comments

Comments
 (0)