Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -356,6 +356,13 @@ return !(isDeclarationForLinker() || isWeakForLinker()); } + /// Returns true if references to this global value can not be resolved + /// at link time to absolute addresses or fixed offsets. + bool isInterposable() const { + return !hasLocalLinkage() && !hasHiddenVisibility() && + (!hasProtectedVisibility() || !(isStrongDefinitionForLinker() || hasCommonLinkage())); + } + // Returns true if the alignment of the value can be unilaterally // increased. bool canIncreaseAlignment() const; Index: lib/Target/X86/X86FastISel.cpp =================================================================== --- lib/Target/X86/X86FastISel.cpp +++ lib/Target/X86/X86FastISel.cpp @@ -641,7 +641,9 @@ Opc = X86::MOV64rm; RC = &X86::GR64RegClass; - if (Subtarget->isPICStyleRIPRel()) + // MO_GETPCREL is used for accessing protected symbols, so + // support that even for non-PIC. + if (Subtarget->isPICStyleRIPRel() || GVFlags == X86II::MO_GOTPCREL) StubAM.Base.Reg = X86::RIP; } else { Opc = X86::MOV32rm; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -12893,7 +12893,9 @@ Result = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, OpFlags); } - if (Subtarget.isPICStyleRIPRel() && + // MO_GETPCREL is used for accessing protected symbols, so + // support that even for non-PIC. + if ((Subtarget.isPICStyleRIPRel() || OpFlags == X86II::MO_GOTPCREL) && (M == CodeModel::Small || M == CodeModel::Kernel)) Result = DAG.getNode(X86ISD::WrapperRIP, dl, PtrVT, Result); else Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -7218,8 +7218,9 @@ if (STI.is64Bit()) return false; - // Only emit a global base reg in PIC mode. - if (TM->getRelocationModel() != Reloc::PIC_) + // A global base register is used only in PIC mode or for + // addressing protected symbol on ELF targets. + if (TM->getRelocationModel() != Reloc::PIC_ && !STI.isTargetELF()) return false; X86MachineFunctionInfo *X86FI = MF.getInfo(); @@ -7237,7 +7238,7 @@ const X86InstrInfo *TII = STI.getInstrInfo(); unsigned PC; - if (STI.isPICStyleGOT()) + if (STI.isPICStyleGOT() || STI.isTargetELF()) PC = RegInfo.createVirtualRegister(&X86::GR32RegClass); else PC = GlobalBaseReg; @@ -7248,7 +7249,7 @@ // If we're using vanilla 'GOT' PIC style, we should use relative addressing // not to pc, but to _GLOBAL_OFFSET_TABLE_ external. - if (STI.isPICStyleGOT()) { + if (STI.isPICStyleGOT() || STI.isTargetELF()) { // Generate addl $__GLOBAL_OFFSET_TABLE_ + [.-piclabel], %some_register BuildMI(FirstMBB, MBBI, DL, TII->get(X86::ADD32ri), GlobalBaseReg) .addReg(PC).addExternalSymbol("_GLOBAL_OFFSET_TABLE_", Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -83,8 +83,8 @@ } else if (!isTargetWin64()) { assert(isTargetELF() && "Unknown rip-relative target"); - // Extra load is needed for all externally visible. - if (!GV->hasLocalLinkage() && GV->hasDefaultVisibility()) + // Extra load is needed if the reference can't be resolved at link time. + if (GV->isInterposable()) return X86II::MO_GOTPCREL; } @@ -92,10 +92,10 @@ } if (isPICStyleGOT()) { // 32-bit ELF targets. - // Extra load is needed for all externally visible. - if (GV->hasLocalLinkage() || GV->hasHiddenVisibility()) - return X86II::MO_GOTOFF; - return X86II::MO_GOT; + // Extra load is needed if the reference can't be resolved at link time. + if (GV->isInterposable()) + return X86II::MO_GOT; + return X86II::MO_GOTOFF; } if (isPICStyleStubPIC()) { // Darwin/32 in PIC mode. @@ -140,6 +140,12 @@ return X86II::MO_NO_FLAG; } + if (!isDef && GV->hasProtectedVisibility() && GV->isInterposable()) { + // Copy relocations for protected symbols are invalid, so force + // using indirect access here. + return is64Bit() ? X86II::MO_GOTPCREL : X86II::MO_GOT; + } + // Direct static reference to global. return X86II::MO_NO_FLAG; } Index: test/CodeGen/X86/protected.ll =================================================================== --- test/CodeGen/X86/protected.ll +++ test/CodeGen/X86/protected.ll @@ -0,0 +1,58 @@ +; RUN: llc < %s -march=x86-64 -O2 | FileCheck %s --check-prefix=CHECK-ELF64 +; RUN: llc < %s -march=x86-64 -O2 -relocation-model=pic | FileCheck %s --check-prefix=CHECK-ELF64 +; fast-isel does not use RIP-relative address by default. +; RUN: llc < %s -march=x86-64 -O0 | FileCheck %s --check-prefix=CHECK-ELF64-ABS +; RUN: llc < %s -march=x86-64 -O0 -relocation-model=pic | FileCheck %s --check-prefix=CHECK-ELF64 + +; RUN: llc < %s -march=x86 -O2 | FileCheck %s --check-prefix=CHECK-ELF32 +; RUN: llc < %s -march=x86 -O2 -relocation-model=pic | FileCheck %s --check-prefix=CHECK-ELF32-PIC +; RUN: llc < %s -march=x86 -O0 | FileCheck %s --check-prefix=CHECK-ELF32 +; RUN: llc < %s -march=x86 -O0 -relocation-model=pic | FileCheck %s --check-prefix=CHECK-ELF32-PIC + +@protected_undef = external protected global i32, align 4 + +define i32 @protected_accessor() { +entry: + %0 = load i32, i32* @protected_undef, align 4 + ret i32 %0 +} + +; CHECK-ELF64: movq protected_undef@GOTPCREL(%rip), %rax +; CHECK-ELF64-NEXT: movl (%rax), %eax +; CHECK-ELF64-ABS: movq protected_undef@GOTPCREL(%rip), %rax +; CHECK-ELF64-ABS-NEXT: movl (%rax), %eax + +; CHECK-ELF32: addl $_GLOBAL_OFFSET_TABLE_+({{.*}}), %eax +; CHECK-ELF32-NEXT: movl protected_undef@GOT(%eax), %eax +; CHECK-ELF32-NEXT: movl (%eax), %eax +; CHECK-ELF32-PIC: addl $_GLOBAL_OFFSET_TABLE_+({{.*}}), %eax +; CHECK-ELF32-PIC-NEXT: movl protected_undef@GOT(%eax), %eax +; CHECK-ELF32-PIC-NEXT: movl (%eax), %eax + +@protected_common = common protected global i32 0, align 4 + +define i32 @protected_accessor2() { +entry: + %0 = load i32, i32* @protected_common, align 4 + ret i32 %0 +} + +; CHECK-ELF64: movl protected_common(%rip), %eax +; CHECK-ELF64-ABS: movl protected_common, %eax +; CHECK-ELF32: movl protected_common, %eax +; CHECK-ELF32-PIC: movl protected_common@GOTOFF(%eax), %eax + +@protected_def = common protected global i32 0, align 4 + +define i32 @protected_accessor3() { +entry: + %0 = load i32, i32* @protected_def, align 4 + ret i32 %0 +} + +; CHECK-ELF64: movl protected_def(%rip), %eax +; CHECK-ELF64-ABS: movl protected_def, %eax + +; CHECK-ELF32: movl protected_def, %eax +; CHECK-ELF32-FAST: movl protected_def, %eax +; CHECK-ELF32-PIC: movl protected_def@GOTOFF(%eax), %eax