summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/X86/X86Subtarget.cpp15
-rw-r--r--llvm/lib/Target/X86/X86Subtarget.h8
-rw-r--r--llvm/test/CodeGen/X86/emutls-pie.ll8
-rw-r--r--llvm/test/CodeGen/X86/global-access-pie.ll119
4 files changed, 142 insertions, 8 deletions
diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp
index c8af9725f98..d02a99f081a 100644
--- a/llvm/lib/Target/X86/X86Subtarget.cpp
+++ b/llvm/lib/Target/X86/X86Subtarget.cpp
@@ -83,8 +83,12 @@ ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const {
} else if (!isTargetWin64()) {
assert(isTargetELF() && "Unknown rip-relative target");
- // Extra load is needed for all externally visible globals.
- if (!GV->hasLocalLinkage() && GV->hasDefaultVisibility())
+ // Extra load is needed for all externally visible globals except with
+ // PIE as the definition of the global in an executable is not
+ // overridden.
+
+ if (!GV->hasLocalLinkage() && GV->hasDefaultVisibility() &&
+ !isGlobalDefinedInPIE(GV, TM))
return X86II::MO_GOTPCREL;
}
@@ -92,8 +96,11 @@ ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const {
}
if (isPICStyleGOT()) { // 32-bit ELF targets.
- // Extra load is needed for all externally visible.
- if (GV->hasLocalLinkage() || GV->hasHiddenVisibility())
+ // Extra load is needed for all externally visible globals except with
+ // PIE as the definition of the global in an executable is not overridden.
+
+ if (GV->hasLocalLinkage() || GV->hasHiddenVisibility() ||
+ isGlobalDefinedInPIE(GV, TM))
return X86II::MO_GOTOFF;
return X86II::MO_GOT;
}
diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h
index 7713656722a..170e5c383ae 100644
--- a/llvm/lib/Target/X86/X86Subtarget.h
+++ b/llvm/lib/Target/X86/X86Subtarget.h
@@ -548,6 +548,14 @@ public:
}
}
+ /// Determine if this global is defined in a Position Independent
+ /// Executable (PIE) where its definition cannot be interposed.
+ bool isGlobalDefinedInPIE(const GlobalValue *GV,
+ const TargetMachine &TM) const {
+ return TM.Options.PositionIndependentExecutable &&
+ !GV->isDeclarationForLinker();
+ }
+
/// ClassifyGlobalReference - Classify a global variable reference for the
/// current subtarget according to how we should reference it in a non-pcrel
/// context.
diff --git a/llvm/test/CodeGen/X86/emutls-pie.ll b/llvm/test/CodeGen/X86/emutls-pie.ll
index 45e5c38c0d8..d94ff64da91 100644
--- a/llvm/test/CodeGen/X86/emutls-pie.ll
+++ b/llvm/test/CodeGen/X86/emutls-pie.ll
@@ -39,7 +39,7 @@ entry:
define i32 @f1() {
; X32-LABEL: f1:
-; X32: movl __emutls_v.i@GOT(%ebx), %eax
+; X32: leal __emutls_v.i@GOTOFF(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X32-NEXT: movl (%eax), %eax
@@ -47,7 +47,7 @@ define i32 @f1() {
; X32-NEXT: popl %ebx
; X32-NEXT: retl
; X64-LABEL: f1:
-; X64: movq __emutls_v.i@GOTPCREL(%rip), %rdi
+; X64: leaq __emutls_v.i(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: popq %rcx
@@ -60,11 +60,11 @@ entry:
define i32* @f2() {
; X32-LABEL: f2:
-; X32: movl __emutls_v.i@GOT(%ebx), %eax
+; X32: leal __emutls_v.i@GOTOFF(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X64-LABEL: f2:
-; X64: movq __emutls_v.i@GOTPCREL(%rip), %rdi
+; X64: leaq __emutls_v.i(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
entry:
diff --git a/llvm/test/CodeGen/X86/global-access-pie.ll b/llvm/test/CodeGen/X86/global-access-pie.ll
new file mode 100644
index 00000000000..39c986eac34
--- /dev/null
+++ b/llvm/test/CodeGen/X86/global-access-pie.ll
@@ -0,0 +1,119 @@
+; RUN: llc < %s -march=x86-64 -mcpu=generic -mtriple=x86_64-linux-gnu -relocation-model=pic -enable-pie \
+; RUN: | FileCheck -check-prefix=X64 %s
+; RUN: llc < %s -emulated-tls -march=x86 -mcpu=generic -mtriple=i386-linux-gnu -relocation-model=pic -enable-pie \
+; RUN: | FileCheck -check-prefix=X32 %s
+
+; External Linkage
+@a = global i32 0, align 4
+
+define i32 @my_access_global_a() #0 {
+; X32-LABEL: my_access_global_a:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %eax
+; X32-NEXT: movl a@GOTOFF(%eax), %eax
+; X64-LABEL: my_access_global_a:
+; X64: movl a(%rip), %eax
+
+entry:
+ %0 = load i32, i32* @a, align 4
+ ret i32 %0
+}
+
+; WeakAny Linkage
+@b = weak global i32 0, align 4
+
+define i32 @my_access_global_b() #0 {
+; X32-LABEL: my_access_global_b:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %eax
+; X32-NEXT: movl b@GOTOFF(%eax), %eax
+; X64-LABEL: my_access_global_b:
+; X64: movl b(%rip), %eax
+
+entry:
+ %0 = load i32, i32* @b, align 4
+ ret i32 %0
+}
+
+; Internal Linkage
+@c = internal global i32 0, align 4
+
+define i32 @my_access_global_c() #0 {
+; X32-LABEL: my_access_global_c:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %eax
+; X32-NEXT: movl c@GOTOFF(%eax), %eax
+; X64-LABEL: my_access_global_c:
+; X64: movl c(%rip), %eax
+
+entry:
+ %0 = load i32, i32* @c, align 4
+ ret i32 %0
+}
+
+; External Linkage, only declaration.
+@d = external global i32, align 4
+
+define i32 @my_access_global_load_d() #0 {
+; X32-LABEL: my_access_global_load_d:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %eax
+; X32-NEXT: movl d@GOT(%eax), %eax
+; X32-NEXT: movl (%eax), %eax
+; X64-LABEL: my_access_global_load_d:
+; X64: movq d@GOTPCREL(%rip), %rax
+; X64-NEXT: movl (%rax), %eax
+
+entry:
+ %0 = load i32, i32* @d, align 4
+ ret i32 %0
+}
+
+; External Linkage, only declaration, store a value.
+
+define i32 @my_access_global_store_d() #0 {
+; X32-LABEL: my_access_global_store_d:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %eax
+; X32-NEXT: movl d@GOT(%eax), %eax
+; X32-NEXT: movl $2, (%eax)
+; X64-LABEL: my_access_global_store_d:
+; X64: movq d@GOTPCREL(%rip), %rax
+; X64-NEXT: movl $2, (%rax)
+
+entry:
+ store i32 2, i32* @d, align 4
+ ret i32 0
+}
+
+; External Linkage, function pointer access.
+declare i32 @access_fp(i32 ()*)
+declare i32 @foo()
+
+define i32 @my_access_fp_foo() #0 {
+; X32-LABEL: my_access_fp_foo:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %ebx
+; X32-NEXT: movl foo@GOT(%ebx), %eax
+; X64-LABEL: my_access_fp_foo:
+; X64: movq foo@GOTPCREL(%rip), %rdi
+
+entry:
+ %call = call i32 @access_fp(i32 ()* @foo)
+ ret i32 %call
+}
+
+; LinkOnceODR Linkage, function pointer access.
+
+$bar = comdat any
+
+define linkonce_odr i32 @bar() comdat {
+entry:
+ ret i32 0
+}
+
+define i32 @my_access_fp_bar() #0 {
+; X32-LABEL: my_access_fp_bar:
+; X32: addl $_GLOBAL_OFFSET_TABLE_{{.*}}, %ebx
+; X32-NEXT: leal bar@GOTOFF(%ebx), %eax
+; X64-LABEL: my_access_fp_bar:
+; X64: leaq bar(%rip), %rdi
+
+entry:
+ %call = call i32 @access_fp(i32 ()* @bar)
+ ret i32 %call
+}
OpenPOWER on IntegriCloud