diff --git a/lld/test/ELF/lto/i386-global-offset-table.ll b/lld/test/ELF/lto/i386-global-offset-table.ll new file mode 100644 index 0000000000000..3fa11f6e6d40d --- /dev/null +++ b/lld/test/ELF/lto/i386-global-offset-table.ll @@ -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} diff --git a/lld/test/ELF/lto/x86-64-global-offset-table.ll b/lld/test/ELF/lto/x86-64-global-offset-table.ll new file mode 100644 index 0000000000000..4b0f638b409e1 --- /dev/null +++ b/lld/test/ELF/lto/x86-64-global-offset-table.ll @@ -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: : 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 diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp b/llvm/lib/Object/ModuleSymbolTable.cpp index 07f76688fa43e..d8f520ad02c2f 100644 --- a/llvm/lib/Object/ModuleSymbolTable.cpp +++ b/llvm/lib/Object/ModuleSymbolTable.cpp @@ -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( diff --git a/llvm/test/LTO/X86/codemodel-2.ll b/llvm/test/LTO/X86/codemodel-2.ll index 5cd9731606f2b..fc1074bcf2235 100644 --- a/llvm/test/LTO/X86/codemodel-2.ll +++ b/llvm/test/LTO/X86/codemodel-2.ll @@ -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" diff --git a/llvm/test/LTO/X86/codemodel-3.ll b/llvm/test/LTO/X86/codemodel-3.ll index 947221e9f36dc..13702dfbca2da 100644 --- a/llvm/test/LTO/X86/codemodel-3.ll +++ b/llvm/test/LTO/X86/codemodel-3.ll @@ -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" diff --git a/llvm/test/LTO/X86/largedatathreshold-1.ll b/llvm/test/LTO/X86/largedatathreshold-1.ll index e3be5c11baaac..dfd8319511b61 100644 --- a/llvm/test/LTO/X86/largedatathreshold-1.ll +++ b/llvm/test/LTO/X86/largedatathreshold-1.ll @@ -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" diff --git a/llvm/test/LTO/X86/largedatathreshold-2.ll b/llvm/test/LTO/X86/largedatathreshold-2.ll index 103c066b744d0..59438bbdb5027 100644 --- a/llvm/test/LTO/X86/largedatathreshold-2.ll +++ b/llvm/test/LTO/X86/largedatathreshold-2.ll @@ -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" diff --git a/llvm/test/LTO/X86/largedatathreshold-3.ll b/llvm/test/LTO/X86/largedatathreshold-3.ll index 3c0653db334d8..fea7987ff1556 100644 --- a/llvm/test/LTO/X86/largedatathreshold-3.ll +++ b/llvm/test/LTO/X86/largedatathreshold-3.ll @@ -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