diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -165,6 +165,8 @@ BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") +BUILTIN(__builtin_ppc_kill_canary, "v", "") + // This is just a placeholder, the types and attributes are wrong. BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -122,6 +122,7 @@ Builder.defineMacro("__fetch_and_orlp", "__builtin_ppc_fetch_and_orlp"); Builder.defineMacro("__fetch_and_swap", "__builtin_ppc_fetch_and_swap"); Builder.defineMacro("__fetch_and_swaplp", "__builtin_ppc_fetch_and_swaplp"); + Builder.defineMacro("__kill_canary", "__builtin_ppc_kill_canary"); Builder.defineMacro("__ldarx", "__builtin_ppc_ldarx"); Builder.defineMacro("__lwarx", "__builtin_ppc_lwarx"); Builder.defineMacro("__lharx", "__builtin_ppc_lharx"); diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c b/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/PowerPC/builtins-ppc-stackprotect.c @@ -0,0 +1,23 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -O2 -triple powerpc64-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -triple powerpc64le-unknown-linux-gnu \ +// RUN: -emit-llvm %s -o - -target-cpu pwr8 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -triple powerpc-unknown-aix \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -O2 -triple powerpc64-unknown-aix \ +// RUN: -emit-llvm %s -o - -target-cpu pwr7 | \ +// RUN: FileCheck %s + +void test_builtin_ppc_kill_canary() { + // CHECK: call void @llvm.ppc.kill.canary() + __builtin_ppc_kill_canary(); +} + +void test_kill_canary() { + // CHECK: call void @llvm.ppc.kill.canary() + __kill_canary(); +} diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -217,6 +217,11 @@ : Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_float_ty, llvm_float_ty, llvm_vararg_ty], [IntrNoMem]>; + def int_ppc_kill_canary + : ClangBuiltin<"__builtin_ppc_kill_canary">, + Intrinsic<[], + [], + [IntrWriteMem, IntrHasSideEffects]>; } let TargetPrefix = "ppc" in { // All PPC intrinsics start with "llvm.ppc.". diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -11127,6 +11127,84 @@ } break; } + case Intrinsic::ppc_kill_canary: { + MachineFunction &MF = DAG.getMachineFunction(); + const Module *M = MF.getMMI().getModule(); + + /* If SafeStack or !StackProtector, kill_canary not supported */ + if (MF.getFunction().hasFnAttribute(Attribute::SafeStack) || + !MF.getFunction().hasStackProtectorFnAttr()) { + DAG.ReplaceAllUsesOfValueWith( + SDValue(Op.getNode(), 0), + Op->getOperand(0)); // prepare node for deletion + break; + } + + EVT VT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + EVT MemVT = + DAG.getTargetLoweringInfo().getPointerMemTy(DAG.getDataLayout()); + + SDValue Load; + SDValue Store; + + const uint64_t XORWord = 0xFFFFFFFF; // XORing with 0b111...111 will never + // result in the original word + + // try getting canary word as global value if it exists + GlobalValue *GV = (Subtarget.isAIXABI()) + ? M->getGlobalVariable(AIXSSPCanaryWordName) + : M->getNamedValue("__stack_chk_guard"); + if (GV == nullptr) { // linux uses LOAD_STACK_GUARD node instead of having a + // canary word global value + if (useLoadStackGuardNode()) { + MachineSDNode *LSG = DAG.getMachineNode(PPC::LOAD_STACK_GUARD, DL, VT, + Op->getOperand(0)); + if (VT != MemVT) { + Load = DAG.getPtrExtOrTrunc(SDValue(LSG, 0), DL, MemVT); + } else { + Load = SDValue(LSG, 0); + } + + /* frame index used to determine stack guard location if + * LOAD_STACK_GUARD is used */ + MachineFrameInfo &MFI = MF.getFrameInfo(); + int SPI = MFI.getStackProtectorIndex(); // should return -1 + PPCFunctionInfo *FuncInfo = MF.getInfo(); + SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), VT); + + // XOR canary word and store back + Store = DAG.getStore( + Op->getOperand(0), DL, + DAG.getNode(ISD::XOR, DL, VT, Load, + DAG.getConstant(XORWord, DL, VT)), + DAG.getNode( // add frame index, stack protector index, return node + // result + ISD::ADD, DL, VT, FIN, DAG.getConstant(SPI, DL, VT)), + MachinePointerInfo()); + } else { + DAG.ReplaceAllUsesOfValueWith(SDValue(Op.getNode(), 0), + Op->getOperand(0)); + break; + } + + } else { // on aix, load from global value + VT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(), + GV->getType(), true); + SDValue CanaryLoc = DAG.getGlobalAddress(GV, DL, VT); + + // Load from global value + Load = DAG.getLoad(VT, DL, Op->getOperand(0), CanaryLoc, + MachinePointerInfo()); + + // XOR canary word and store back + Store = DAG.getStore( + Op->getOperand(0), DL, + DAG.getNode(ISD::XOR, DL, VT, Load, DAG.getConstant(XORWord, DL, VT)), + CanaryLoc, MachinePointerInfo()); + } + + return Store; + } default: break; } diff --git a/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-aix.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-aix \ +; RUN: --ppc-asm-full-reg-names < %s | FileCheck %s + +declare void @llvm.ppc.kill.canary() +define dso_local void @test_kill_canary() { +; CHECK-LABEL: test_kill_canary: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: blr +entry: + call void @llvm.ppc.kill.canary() + ret void +} + +attributes #0 = { sspreq } +; Function Attrs: sspreq +define dso_local void @test_kill_canary_ssp() #0 { +; CHECK-LABEL: test_kill_canary_ssp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -128(r1) +; CHECK-NEXT: ld r3, L..C0(r2) # @__ssp_canary_word +; CHECK-NEXT: ld r4, 0(r3) +; CHECK-NEXT: std r4, 120(r1) +; CHECK-NEXT: ld r4, 0(r3) +; CHECK-NEXT: xori r4, r4, 65535 +; CHECK-NEXT: xoris r4, r4, 65535 +; CHECK-NEXT: std r4, 0(r3) +; CHECK-NEXT: ld r3, 0(r3) +; CHECK-NEXT: ld r4, 120(r1) +; CHECK-NEXT: cmpld r3, r4 +; CHECK-NEXT: bne cr0, L..BB1_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: addi r1, r1, 128 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +; CHECK-NEXT: L..BB1_2: # %entry +; CHECK-NEXT: bl .__stack_chk_fail[PR] +; CHECK-NEXT: nop +entry: + call void @llvm.ppc.kill.canary() + ret void +} diff --git a/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/kill-canary-intrinsic-linux.ll @@ -0,0 +1,46 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux \ +; RUN: --ppc-asm-full-reg-names < %s | FileCheck %s + +declare void @llvm.ppc.kill.canary() +define dso_local void @test_kill_canary() { +; CHECK-LABEL: test_kill_canary: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: blr +entry: + call void @llvm.ppc.kill.canary() + ret void +} + +attributes #0 = { sspreq } +; Function Attrs: sspreq +define dso_local void @test_kill_canary_ssp() #0 { +; CHECK-LABEL: test_kill_canary_ssp: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mflr r0 +; CHECK-NEXT: std r0, 16(r1) +; CHECK-NEXT: stdu r1, -128(r1) +; CHECK-NEXT: .cfi_def_cfa_offset 128 +; CHECK-NEXT: .cfi_offset lr, 16 +; CHECK-NEXT: ld r3, -28688(r13) +; CHECK-NEXT: std r3, 120(r1) +; CHECK-NEXT: ld r3, -28688(r13) +; CHECK-NEXT: xori r3, r3, 65535 +; CHECK-NEXT: xoris r3, r3, 65535 +; CHECK-NEXT: std r3, 120(r1) +; CHECK-NEXT: ld r3, 120(r1) +; CHECK-NEXT: ld r4, -28688(r13) +; CHECK-NEXT: cmpld r4, r3 +; CHECK-NEXT: bne cr0, .LBB1_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: addi r1, r1, 128 +; CHECK-NEXT: ld r0, 16(r1) +; CHECK-NEXT: mtlr r0 +; CHECK-NEXT: blr +; CHECK-NEXT: .LBB1_2: # %entry +; CHECK-NEXT: bl __stack_chk_fail +; CHECK-NEXT: nop +entry: + call void @llvm.ppc.kill.canary() + ret void +}