Skip to content

Commit

Permalink
IRSymTab: Record _GLOBAL_OFFSET_TABLE_ for ELF x86
Browse files Browse the repository at this point in the history
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
  • Loading branch information
MaskRay committed Apr 24, 2024
1 parent 9c4735e commit 99e7350
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 5 deletions.
29 changes: 29 additions & 0 deletions lld/test/ELF/lto/i386-global-offset-table.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; REQUIRES: x86
;; LTO-generated relocatable files may reference _GLOBAL_OFFSET_TABLE_ while
;; the IR does not mention _GLOBAL_OFFSET_TABLE_.
;; Test that there is no spurious "undefined symbol" error.

; RUN: rm -rf %t && mkdir %t && cd %t
; RUN: llvm-as %s -o a.bc
; RUN: ld.lld -pie a.bc -o a
; RUN: llvm-nm a | FileCheck %s

; CHECK: d _GLOBAL_OFFSET_TABLE_

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"
target triple = "i386-pc-linux-gnu"

@i = global i32 0

define dso_local void @_start() {
entry:
%0 = load i32, ptr @i
%inc = add nsw i32 %0, 1
store i32 %inc, ptr @i
ret void
}

!llvm.module.flags = !{!0, !1}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
71 changes: 71 additions & 0 deletions lld/test/ELF/lto/x86-64-global-offset-table.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
; REQUIRES: x86
;; LTO-generated relocatable files may reference _GLOBAL_OFFSET_TABLE_ while
;; the IR does not mention _GLOBAL_OFFSET_TABLE_.
;; Test that there is no spurious "undefined symbol" error.

; RUN: rm -rf %t && split-file %s %t && cd %t
; RUN: opt -module-summary b.ll -o b.bc

;; Test Thin LTO.
; RUN: cat a.ll medium.ll | opt -module-summary - -o medium.bc
; RUN: ld.lld -pie --no-relax medium.bc b.bc -o medium
; RUN: llvm-objdump -dt medium | FileCheck %s

;; Test regular LTO.
; RUN: cat a.ll large.ll | llvm-as - -o large.bc
; RUN: ld.lld -pie large.bc b.bc -o large
; RUN: llvm-objdump -dt large | FileCheck %s

;; Explicit reference of _GLOBAL_OFFSET_TABLE_ is fine.
; RUN: cat a.ll medium.ll ref.ll | opt -module-summary - -o ref.bc
; RUN: ld.lld -pie -u ref ref.bc b.bc -y _GLOBAL_OFFSET_TABLE_ -o ref 2>&1 | FileCheck %s --check-prefix=TRACE
; RUN: llvm-objdump -dt ref | FileCheck %s

; TRACE: ref.bc: reference to _GLOBAL_OFFSET_TABLE_
; TRACE-NEXT: ref.bc: reference to _GLOBAL_OFFSET_TABLE_
; TRACE-NEXT: <internal>: definition of _GLOBAL_OFFSET_TABLE_
; TRACE-NEXT: ref.lto.ref.o: reference to _GLOBAL_OFFSET_TABLE_

;; The IR symbol table references _GLOBAL_OFFSET_TABLE_, which causes lld to define the symbol.
; CHECK: .got.plt 0000000000000000 .hidden _GLOBAL_OFFSET_TABLE_
; CHECK: movabsq

;--- a.ll
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"
target triple = "x86_64-unknown-linux-gnu"

@i = external global i32

define dso_local void @_start() {
entry:
%0 = load i32, ptr @i
%inc = add nsw i32 %0, 1
store i32 %inc, ptr @i
ret void
}

!llvm.module.flags = !{!0, !1, !2, !3}

!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
!2 = !{i32 1, !"Large Data Threshold", i64 0}

;--- medium.ll
!3 = !{i32 1, !"Code Model", i32 3}

;--- large.ll
!3 = !{i32 1, !"Code Model", i32 4}

;--- ref.ll
@_GLOBAL_OFFSET_TABLE_ = external global [0 x i8]

define dso_local ptr @ref() {
entry:
ret ptr @_GLOBAL_OFFSET_TABLE_
}

;--- b.ll
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"
target triple = "x86_64-unknown-linux-gnu"

@i = global i32 0
14 changes: 14 additions & 0 deletions llvm/lib/Object/ModuleSymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ void ModuleSymbolTable::CollectAsmSymbols(
AsmSymbol(Key, BasicSymbolRef::Flags(Res));
}
});

// In ELF, object code generated for x86-32 and some code models of x86-64 may
// reference the special symbol _GLOBAL_OFFSET_TABLE_ that is not used in the
// IR. Record it like inline asm symbols.
Triple TT(M.getTargetTriple());
if (!TT.isOSBinFormatELF() || !TT.isX86())
return;
auto CM = M.getCodeModel();
if (TT.getArch() == Triple::x86 || CM == CodeModel::Medium ||
CM == CodeModel::Large) {
AsmSymbol("_GLOBAL_OFFSET_TABLE_",
BasicSymbolRef::Flags(BasicSymbolRef::SF_Undefined |
BasicSymbolRef::SF_Global));
}
}

void ModuleSymbolTable::CollectAsmSymvers(
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/LTO/X86/codemodel-2.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; RUN: llvm-as %s -o %t.o
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
; RUN: llvm-objdump --no-print-imm-hex -d %t.s.0 | FileCheck %s --check-prefix=CHECK-LARGE

target triple = "x86_64-unknown-linux-gnu"
Expand Down
3 changes: 2 additions & 1 deletion llvm/test/LTO/X86/codemodel-3.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
; RUN: llvm-as %s -o %t0.o
; RUN: llvm-as < %p/Inputs/codemodel-3.ll > %t1.o
; 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
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px -r %t0.o,_GLOBAL_OFFSET_TABLE_, \
; RUN: -r %t1.o,_GLOBAL_OFFSET_TABLE_, %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s

target triple = "x86_64-unknown-linux-gnu"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/LTO/X86/largedatathreshold-1.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; RUN: llvm-as %s -o %t.o
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
; RUN: llvm-objdump -d %t.s.0 | FileCheck %s

target triple = "x86_64-unknown-linux-gnu"
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/LTO/X86/largedatathreshold-2.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; RUN: llvm-as %s -o %t.o
; RUN: llvm-lto2 run -r %t.o,_start,px %t.o -o %t.s
; RUN: llvm-lto2 run -r %t.o,_start,px -r %t.o,_GLOBAL_OFFSET_TABLE_, %t.o -o %t.s
; RUN: llvm-objdump -d %t.s.0 | FileCheck %s

target triple = "x86_64-unknown-linux-gnu"
Expand Down
3 changes: 2 additions & 1 deletion llvm/test/LTO/X86/largedatathreshold-3.ll
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
; RUN: llvm-as %s -o %t0.o
; RUN: llvm-as < %p/Inputs/largedatathreshold.ll > %t1.o
; 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
; RUN: not llvm-lto2 run -r %t0.o,_start,px -r %t1.o,bar,px -r %t0.o,_GLOBAL_OFFSET_TABLE_, \
; RUN: -r %t1.o,_GLOBAL_OFFSET_TABLE_, %t0.o %t1.o -o %t2.s 2>&1 | FileCheck %s

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

Expand Down

0 comments on commit 99e7350

Please sign in to comment.