Index: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ include/llvm/IR/Module.h @@ -838,6 +838,13 @@ Metadata *getProfileSummary(); /// @} + /// Returns true if PLT should be avoided for RTLib calls. + bool getRtLibUseGOT() const; + + /// Set that PLT should be avoid for RTLib calls. + void setRtLibUseGOT(); + + /// Take ownership of the given memory buffer. void setOwnedMemoryBuffer(std::unique_ptr MB); }; Index: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ lib/IR/Module.cpp @@ -510,6 +510,15 @@ OwnedMemoryBuffer = std::move(MB); } +bool Module::getRtLibUseGOT() const { + auto *Val = cast_or_null(getModuleFlag("RtLibUseGOT")); + return Val && (cast(Val->getValue())->getZExtValue() > 0); +} + +void Module::setRtLibUseGOT() { + addModuleFlag(ModFlagBehavior::Max, "RtLibUseGOT", 1); +} + GlobalVariable *llvm::collectUsedGlobalVariables( const Module &M, SmallPtrSetImpl &Set, bool CompilerUsed) { const char *Name = CompilerUsed ? "llvm.compiler.used" : "llvm.used"; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -3772,6 +3772,14 @@ Callee = DAG.getTargetExternalSymbol( S->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlags); + + if (OpFlags == X86II::MO_GOTPCREL) { + Callee = DAG.getNode(X86ISD::WrapperRIP, dl, + getPointerTy(DAG.getDataLayout()), Callee); + Callee = DAG.getLoad( + getPointerTy(DAG.getDataLayout()), dl, DAG.getEntryNode(), Callee, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); + } } else if (Subtarget.isTarget64BitILP32() && Callee->getValueType(0) == MVT::i32) { // Zero-extend the 32-bit Callee address into a 64-bit according to x32 ABI Index: lib/Target/X86/X86Subtarget.cpp =================================================================== --- lib/Target/X86/X86Subtarget.cpp +++ lib/Target/X86/X86Subtarget.cpp @@ -157,8 +157,11 @@ // In Regcall calling convention those registers are used for passing // parameters. Thus we need to prevent lazy binding in Regcall. return X86II::MO_GOTPCREL; - if (F && F->hasFnAttribute(Attribute::NonLazyBind) && is64Bit()) - return X86II::MO_GOTPCREL; + // If PLT must be avoided then the call should be via GOTPCREL. + if (((F && F->hasFnAttribute(Attribute::NonLazyBind)) || + (!F && M.getRtLibUseGOT())) && + is64Bit()) + return X86II::MO_GOTPCREL; return X86II::MO_PLT; } Index: test/CodeGen/X86/no-plt.ll =================================================================== --- test/CodeGen/X86/no-plt.ll +++ test/CodeGen/X86/no-plt.ll @@ -3,6 +3,18 @@ ; RUN: llc < %s -mcpu=generic -mtriple=x86_64-linux-gnu \ ; RUN: | FileCheck -check-prefix=X64 --check-prefix=STATIC %s +define void @memset_call(i8* nocapture %a, i8 %c, i32 %n) { +; X64: callq *memset@GOTPCREL(%rip) + call void @llvm.memset.p0i8.i32(i8* %a, i8 %c, i32 %n, i1 false) + ret void +} + +define void @memcpy_call(i8* nocapture %a, i8* nocapture readonly %b, i64 %n) { +; X64: callq *memcpy@GOTPCREL(%rip) + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 %n, i32 1, i1 false) + ret void +} + define i32 @main() { ; X64: callq *foo@GOTPCREL(%rip) ; PIC: callq bar@PLT @@ -20,3 +32,8 @@ declare i32 @foo() nonlazybind declare i32 @bar() declare hidden i32 @baz() nonlazybind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) +declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i1) + +!llvm.module.flags = !{!1} +!1 = !{i32 7, !"RtLibUseGOT", i32 1}