Index: llvm/trunk/lib/Target/X86/X86Subtarget.h =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.h +++ llvm/trunk/lib/Target/X86/X86Subtarget.h @@ -548,6 +548,14 @@ } } + /// 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. Index: llvm/trunk/lib/Target/X86/X86Subtarget.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.cpp +++ llvm/trunk/lib/Target/X86/X86Subtarget.cpp @@ -83,8 +83,12 @@ } 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 @@ } 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; } Index: llvm/trunk/test/CodeGen/X86/emutls-pie.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/emutls-pie.ll +++ llvm/trunk/test/CodeGen/X86/emutls-pie.ll @@ -39,7 +39,7 @@ 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 @@ ; 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 @@ 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: Index: llvm/trunk/test/CodeGen/X86/global-access-pie.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/global-access-pie.ll +++ llvm/trunk/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 +}