Author: Dominik Steenken Date: 2026-05-29T09:17:49+02:00 New Revision: 64bc1fae11d6591739ed0c14f1f3464ae7bc24ac
URL: https://github.com/llvm/llvm-project/commit/64bc1fae11d6591739ed0c14f1f3464ae7bc24ac DIFF: https://github.com/llvm/llvm-project/commit/64bc1fae11d6591739ed0c14f1f3464ae7bc24ac.diff LOG: [SystemZ] Global Stackprotector and associated location section (#169317) This commit allows `-mstack-protector-guard=global` for `s390x`. It also adds a new arch-specific option `-mstack-protector-guard-record`, analogous to `-mrecord-mcount`, which will cause `clang` to emit a `__stack_protector_loc` section containing all the locations in the output binary that load the stack guard address, for the purposes of later rewriting of those loads by the kernel. This new option only works together with the `global` stack protector. In order to minimize exposure of the stack guard, both the storing of the stack guard onto the stack, and the later comparison of that value against the reference value, are handled via direct mem-to-mem instructions, those being `mvc` and `clc`. This is achieved by introducing two new pseudo instructions, `MOVE_STACK_GUARD` and `COMPARE_STACK_GUARD`, which are inserted by the DAGCombiner after SelectionDAG construction. These pseudos stick around throughout the entire backend pipeline, and are lowered only in the AsmPrinter. This commit also adds tests for both kinds of stack protectors (tls and global), for the proper insertion of the pseudos, the proper emission of the, `__stack_protector_loc` section, as well as the option compatibility checks for the new options. Added: clang/test/CodeGen/SystemZ/stack-guard-global-option.c llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll llvm/test/CodeGen/SystemZ/stack-guard-tls.ll Modified: clang/include/clang/Basic/CodeGenOptions.def clang/include/clang/Options/Options.td clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/test/Driver/stack-protector-guard.c llvm/include/llvm/IR/Module.h llvm/lib/IR/Module.cpp llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp llvm/lib/Target/SystemZ/SystemZAsmPrinter.h llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp llvm/lib/Target/SystemZ/SystemZISelLowering.cpp llvm/lib/Target/SystemZ/SystemZISelLowering.h llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp llvm/lib/Target/SystemZ/SystemZInstrInfo.h llvm/lib/Target/SystemZ/SystemZInstrInfo.td llvm/lib/Target/SystemZ/SystemZOperators.td Removed: llvm/test/CodeGen/SystemZ/stack-guard.ll ################################################################################ diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index aa36de6edecbf..6cce4ada1dfd1 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -167,6 +167,7 @@ CODEGENOPT(InstrumentForProfiling , 1, 0, Benign) ///< Set when -pg is enabled. CODEGENOPT(CallFEntry , 1, 0, Benign) ///< Set when -mfentry is enabled. CODEGENOPT(MNopMCount , 1, 0, Benign) ///< Set when -mnop-mcount is enabled. CODEGENOPT(RecordMCount , 1, 0, Benign) ///< Set when -mrecord-mcount is enabled. +CODEGENOPT(StackProtectorGuardRecord, 1, 0, Benign) ///< Set when -mstack-protector-guard-record is enabled. CODEGENOPT(PackedStack , 1, 0, Benign) ///< Set when -mpacked-stack is enabled. CODEGENOPT(LessPreciseFPMAD , 1, 0, Benign) ///< Enable less precise MAD instructions to ///< be generated. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 6fc8806ba683c..5dab4af7618fc 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -6106,6 +6106,14 @@ def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg="> Visibility<[ClangOption, CC1Option]>, HelpText<"Use the given reg for addressing the stack-protector guard">, MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">>; +def mstackprotector_guard_record + : Flag<["-"], "mstack-protector-guard-record">, + HelpText< + "Generate a __stack_protector_loc section entry for each load of " + "the stack-protector guard address.">, + Visibility<[ClangOption, CC1Option]>, + Group<m_Group>, + MarshallingInfoFlag<CodeGenOpts<"StackProtectorGuardRecord">>; def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86/SystemZ only)">, Visibility<[ClangOption, CC1Option]>, Group<m_Group>, MarshallingInfoFlag<CodeGenOpts<"CallFEntry">>; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b8841f75a5c19..627d2376f1288 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1717,6 +1717,14 @@ void CodeGenModule::Release() { if (getCodeGenOpts().StackProtectorGuardValueWidth != UINT_MAX) getModule().setStackProtectorGuardValueWidth( getCodeGenOpts().StackProtectorGuardValueWidth); + if (getCodeGenOpts().StackProtectorGuardRecord) { + if (getModule().getStackProtectorGuard() != "global") { + Diags.Report(diag::err_opt_not_valid_without_opt) + << "-mstack-protector-guard-record" + << "-mstack-protector-guard=global"; + } + getModule().setStackProtectorGuardRecord(true); + } if (getCodeGenOpts().StackAlignment) getModule().setOverrideStackAlignment(getCodeGenOpts().StackAlignment); if (getCodeGenOpts().SkipRaxSetup) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0f915e9f222f7..df49877d4bf62 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3504,22 +3504,24 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, } const std::string &TripleStr = EffectiveTriple.getTriple(); + StringRef GuardValue; if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) { - StringRef Value = A->getValue(); + GuardValue = A->getValue(); if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && !EffectiveTriple.isARM() && !EffectiveTriple.isThumb() && - !EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC()) + !EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC() && + !EffectiveTriple.isSystemZ()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() || - EffectiveTriple.isThumb()) && - Value != "tls" && Value != "global") { + EffectiveTriple.isThumb() || EffectiveTriple.isSystemZ()) && + GuardValue != "tls" && GuardValue != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) - << A->getOption().getName() << Value << "tls global"; + << A->getOption().getName() << GuardValue << "tls global"; return; } if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && - Value == "tls") { + GuardValue == "tls") { if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) { D.Diag(diag::err_drv_ssp_missing_offset_argument) << A->getAsString(Args); @@ -3543,18 +3545,19 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+read-tp-tpidruro"); } - if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") { + if (EffectiveTriple.isAArch64() && GuardValue != "sysreg" && + GuardValue != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) - << A->getOption().getName() << Value << "sysreg global"; + << A->getOption().getName() << GuardValue << "sysreg global"; return; } if (EffectiveTriple.isRISCV() || EffectiveTriple.isPPC()) { - if (Value != "tls" && Value != "global") { + if (GuardValue != "tls" && GuardValue != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) - << A->getOption().getName() << Value << "tls global"; + << A->getOption().getName() << GuardValue << "tls global"; return; } - if (Value == "tls") { + if (GuardValue == "tls") { if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) { D.Diag(diag::err_drv_ssp_missing_offset_argument) << A->getAsString(Args); @@ -3650,6 +3653,18 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, if (Width != 4 && Width != 8) { D.Diag(diag::err_drv_invalid_int_value) << A->getOption().getName() << Value; + } + } + if (Arg *A = Args.getLastArg(options::OPT_mstackprotector_guard_record)) { + if (!EffectiveTriple.isSystemZ()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + return; + } + if (GuardValue != "global") { + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-mstack-protector-guard-record" + << "-mstack-protector-guard=global"; return; } A->render(Args, CmdArgs); diff --git a/clang/test/CodeGen/SystemZ/stack-guard-global-option.c b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c new file mode 100644 index 0000000000000..c81c37b1c89eb --- /dev/null +++ b/clang/test/CodeGen/SystemZ/stack-guard-global-option.c @@ -0,0 +1,10 @@ +// RUN: not %clang_cc1 -S -stack-protector 1 -mstack-protector-guard-record -triple=s390x-ibm-linux < %s -o - 2>&1 | FileCheck -check-prefix=CHECK-OPTS %s +extern char *strcpy (char * D, const char * S); +int main(int argc, char *argv[]) +{ + char Buffer[8] = {0}; + strcpy(Buffer, argv[1]); + return 0; +} + +// CHECK-OPTS: error: option '-mstack-protector-guard-record' cannot be specified without '-mstack-protector-guard=global' diff --git a/clang/test/Driver/stack-protector-guard.c b/clang/test/Driver/stack-protector-guard.c index a31eeefa36ddd..46e09d6581867 100644 --- a/clang/test/Driver/stack-protector-guard.c +++ b/clang/test/Driver/stack-protector-guard.c @@ -160,3 +160,21 @@ // CHECK-TLS-POWERPC32: "-cc1" {{.*}}"-mstack-protector-guard=tls" "-mstack-protector-guard-offset=24" "-mstack-protector-guard-reg=r2" // INVALID-REG-POWERPC32: error: invalid value 'r3' in 'mstack-protector-guard-reg=', expected one of: r2 + +// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=tls %s 2>&1 | \ +// RUN: FileCheck -check-prefix=CHECK_TLS_SYSTEMZ %s +// CHECK_TLS_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=tls" + +// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global %s 2>&1 | \ +// RUN: FileCheck -check-prefix=CHECK_GLOBAL_SYSTEMZ %s +// CHECK_GLOBAL_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global" + +// RUN: %clang -### -target systemz-unknown-elf -mstack-protector-guard=global \ +// RUN: -mstack-protector-guard-record %s 2>&1 | \ +// RUN: FileCheck -check-prefix=CHECK_GLOBAL_RECORD_SYSTEMZ %s +// CHECK_GLOBAL_RECORD_SYSTEMZ: "-cc1" {{.*}}"-mstack-protector-guard=global" "-mstack-protector-guard-record" + +// RUN: not %clang -target systemz-unknown-elf -mstack-protector-guard=tls \ +// RUN: -mstack-protector-guard-record %s 2>&1 | \ +// RUN: FileCheck -check-prefix=INVALID_TLS_RECORD_SYSTEMZ %s +// INVALID_TLS_RECORD_SYSTEMZ: error: invalid argument '-mstack-protector-guard-record' only allowed with '-mstack-protector-guard=global' diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index e71dd36ba5155..1c8c2c2fbd77c 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -1038,6 +1038,10 @@ class LLVM_ABI Module { std::optional<unsigned> getStackProtectorGuardValueWidth() const; void setStackProtectorGuardValueWidth(unsigned Width); + // Get/set flag indicating whether to emit a __stack_protector_loc section. + bool hasStackProtectorGuardRecord() const; + void setStackProtectorGuardRecord(bool Flag); + /// Get/set the stack alignment overridden from the default. unsigned getOverrideStackAlignment() const; void setOverrideStackAlignment(unsigned Align); diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 07edccbaf75d6..faa0fbd3ab81c 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -760,6 +760,17 @@ void Module::setFramePointer(FramePointerKind Kind) { addModuleFlag(ModFlagBehavior::Max, "frame-pointer", static_cast<int>(Kind)); } +bool Module::hasStackProtectorGuardRecord() const { + auto *Val = cast_or_null<ConstantAsMetadata>( + getModuleFlag("stack-protector-guard-record")); + return Val && cast<ConstantInt>(Val->getValue())->isOne(); +} + +void Module::setStackProtectorGuardRecord(bool Flag) { + addModuleFlag(ModFlagBehavior::Max, "stack-protector-guard-record", + Flag ? 1 : 0); +} + StringRef Module::getStackProtectorGuard() const { Metadata *MD = getModuleFlag("stack-protector-guard"); if (auto *MDS = dyn_cast_or_null<MDString>(MD)) diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp index c9c080eb1453a..40bfaa55da17f 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -774,6 +774,13 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) { case SystemZ::EH_SjLj_Setup: return; + case SystemZ::LOAD_TLS_BLOCK_ADDR: + lowerLOAD_TLS_BLOCK_ADDR(*MI, Lower); + return; + case SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR: + lowerLOAD_GLOBAL_STACKGUARD_ADDR(*MI, Lower); + return; + default: Lower.lower(MI, LoweredMI); break; @@ -1023,6 +1030,68 @@ void SystemZAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI, recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2); } +void SystemZAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI, + SystemZMCInstLower &Lower) { + Register AddrReg = MI.getOperand(0).getReg(); + const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + + // EAR can only load the low subregister so use a shift for %a0 to produce + // the GR containing %a0 and %a1. + const Register Reg32 = + MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32); + + // ear <reg>, %a0 + EmitToStreamer(*OutStreamer, + MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0)); + + // sllg <reg>, <reg>, 32 + EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG) + .addReg(AddrReg) + .addReg(AddrReg) + .addReg(0) + .addImm(32)); + + // ear <reg>, %a1 + EmitToStreamer(*OutStreamer, + MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1)); +} + +void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR( + const MachineInstr &MI, SystemZMCInstLower &Lower) { + Register AddrReg = MI.getOperand(0).getReg(); + const MachineFunction &MF = *(MI.getParent()->getParent()); + const Module *M = MF.getFunction().getParent(); + const TargetLowering *TLI = MF.getSubtarget().getTargetLowering(); + + // Obtain the global value (assert if stack guard variable can't be found). + const GlobalVariable *GV = cast<GlobalVariable>( + TLI->getSDagStackGuard(*M, TLI->getLibcallLoweringInfo())); + + // If configured, emit the `__stack_protector_loc` entry + if (M->hasStackProtectorGuardRecord()) { + MCSymbol *Sym = OutContext.createTempSymbol(); + OutStreamer->pushSection(); + OutStreamer->switchSection(OutContext.getELFSection( + "__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC)); + OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize()); + OutStreamer->popSection(); + OutStreamer->emitLabel(Sym); + } + // Emit the address load. + if (M->getPICLevel() == PICLevel::NotPIC) { + EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL) + .addReg(AddrReg) + .addExpr(MCSymbolRefExpr::create( + getSymbol(GV), OutContext))); + } else { + EmitToStreamer(*OutStreamer, + MCInstBuilder(SystemZ::LGRL) + .addReg(AddrReg) + .addExpr(MCSymbolRefExpr::create( + getSymbol(GV), SystemZ::S_GOTENT, OutContext))); + } +} + // The *alignment* of 128-bit vector types is diff erent between the software // and hardware vector ABIs. If the there is an externally visible use of a // vector type in the module it should be annotated with an attribute. diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h index e9d765f81a0cb..f3703b783f7ec 100644 --- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -170,6 +170,10 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public AsmPrinter { void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI, SystemZMCInstLower &Lower); void LowerPATCHABLE_RET(const MachineInstr &MI, SystemZMCInstLower &Lower); + void lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI, + SystemZMCInstLower &Lower); + void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI, + SystemZMCInstLower &Lower); void emitAttributes(Module &M); }; } // end namespace llvm diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index a05fdc74e6366..025969a81f6b7 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -10,10 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "SystemZTargetMachine.h" #include "SystemZISelLowering.h" +#include "SystemZTargetMachine.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/raw_ostream.h" @@ -369,7 +370,11 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { if (F.hasFnAttribute("mrecord-mcount")) report_fatal_error("mrecord-mcount only supported with fentry-call"); } - + if (F.getParent()->getStackProtectorGuard() != "global") { + if (F.getParent()->hasStackProtectorGuardRecord()) + report_fatal_error("mstack-protector-guard-record only supported with " + "mstack-protector-guard=global"); + } Subtarget = &MF.getSubtarget<SystemZSubtarget>(); return SelectionDAGISel::runOnMachineFunction(MF); } diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 26cc921b6b169..b597d6adbd01c 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -14,21 +14,21 @@ #include "SystemZCallingConv.h" #include "SystemZConstantPoolValue.h" #include "SystemZMachineFunctionInfo.h" -#include "SystemZTargetMachine.h" #include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsS390.h" +#include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Target/TargetMachine.h" #include <cctype> #include <optional> @@ -3031,6 +3031,12 @@ static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) { // Return true if it is better to swap the operands of C. static bool shouldSwapCmpOperands(const Comparison &C) { + // If one side of the compare is a load of the stackguard reference value, + // then that load should be Op1. + if (C.Op0.isMachineOpcode() && + (C.Op0.getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) + return true; + // Leave i128 and f128 comparisons alone, since they have no memory forms. if (C.Op0.getValueType() == MVT::i128) return false; @@ -3179,6 +3185,35 @@ static void adjustICmpTruncate(SelectionDAG &DAG, const SDLoc &DL, } } +// Adjust if a given Compare is a check of the stack guard against a stack +// guard instance on the stack. Specifically, this checks if: +// - The operands are a load of the stack guard, and a load from a stack slot +// - The original opcode is ICMP +// - ICMPType is compatible with unsigned comparison. +static void adjustForStackGuardCompare(SelectionDAG &DAG, const SDLoc &DL, + Comparison &C) { + + // Opcode must be ICMP. + if (C.Opcode != SystemZISD::ICMP) + return; + // ICmpType must be Unsigned or Any. + if (C.ICmpType == SystemZICMP::SignedOnly) + return; + // Op0 must be FrameIndex Load. + if (!(ISD::isNormalLoad(C.Op0.getNode()) && + dyn_cast<FrameIndexSDNode>(C.Op0.getOperand(1)))) + return; + // Op1 must be LOAD_STACK_GUARD. + if (!C.Op1.isMachineOpcode() || + C.Op1.getMachineOpcode() != SystemZ::LOAD_STACK_GUARD) + return; + + // At this point we are sure that this is a proper CMP_STACKGUARD + // case, update the opcode to reflect this. + C.Opcode = SystemZISD::CMP_STACKGUARD; + C.Op1 = SDValue(); +} + // Return true if shift operation N has an in-range constant shift value. // Store it in ShiftVal if so. static bool isSimpleShift(SDValue N, unsigned &ShiftVal) { @@ -3600,12 +3635,15 @@ static Comparison getCmp(SelectionDAG &DAG, SDValue CmpOp0, SDValue CmpOp1, adjustForTestUnderMask(DAG, DL, C); adjustICmp128(DAG, DL, C); + adjustForStackGuardCompare(DAG, DL, C); return C; } // Emit the comparison instruction described by C. static SDValue emitCmp(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) { if (!C.Op1.getNode()) { + if (C.Opcode == SystemZISD::CMP_STACKGUARD) + return DAG.getNode(SystemZISD::CMP_STACKGUARD, DL, MVT::i32, C.Op0); SDNode *Node; switch (C.Op0.getOpcode()) { case ISD::INTRINSIC_W_CHAIN: @@ -8119,6 +8157,17 @@ SDValue SystemZTargetLowering::combineSTORE( SN->getMemOperand()); } } + + // combine STORE (LOAD_STACK_GUARD) into MOV_STACKGUARD_DAG + if (Op1->isMachineOpcode() && + (Op1->getMachineOpcode() == SystemZ::LOAD_STACK_GUARD)) { + // Obtain the frame index the store was targeting. + int FI = cast<FrameIndexSDNode>(SN->getOperand(2))->getIndex(); + // Prepare operands of the MOV_STACKGUARD ISD Node - Chain and FrameIndex. + SDValue Ops[] = {SN->getChain(), DAG.getTargetFrameIndex(FI, MVT::i64)}; + return DAG.getNode(SystemZISD::MOV_STACKGUARD, SDLoc(SN), MVT::Other, Ops); + } + // Combine STORE (BSWAP) into STRVH/STRV/STRVG/VSTBR if (!SN->isTruncatingStore() && Op1.getOpcode() == ISD::BSWAP && @@ -11047,6 +11096,22 @@ getBackchainAddress(SDValue SP, SelectionDAG &DAG) const { DAG.getIntPtrConstant(TFL->getBackchainOffset(MF), DL)); } +// Replace a _STACKGUARD_DAG pseudo with a _STACKGUARD pseudo, adding +// a dead early-clobber def reg that will be used as a scratch register +// when the pseudo is expanded. +MachineBasicBlock *SystemZTargetLowering::emitStackGuardPseudo( + MachineInstr &MI, MachineBasicBlock *MBB, unsigned PseudoOp) const { + MachineRegisterInfo *MRI = &MBB->getParent()->getRegInfo(); + const SystemZInstrInfo *TII = Subtarget.getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + Register AddrReg = MRI->createVirtualRegister(&SystemZ::ADDR64BitRegClass); + BuildMI(*MBB, MI, DL, TII->get(PseudoOp), AddrReg) + .addFrameIndex(MI.getOperand(0).getIndex()) + .addImm(MI.getOperand(1).getImm()); + MI.eraseFromParent(); + return MBB; +} + MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter( MachineInstr &MI, MachineBasicBlock *MBB) const { switch (MI.getOpcode()) { @@ -11204,6 +11269,12 @@ MachineBasicBlock *SystemZTargetLowering::EmitInstrWithCustomInserter( case TargetOpcode::PATCHPOINT: return emitPatchPoint(MI, MBB); + case SystemZ::MOV_STACKGUARD_DAG: + return emitStackGuardPseudo(MI, MBB, SystemZ::MOV_STACKGUARD); + + case SystemZ::CMP_STACKGUARD_DAG: + return emitStackGuardPseudo(MI, MBB, SystemZ::CMP_STACKGUARD); + default: llvm_unreachable("Unexpected instr type to insert"); } @@ -11390,3 +11461,15 @@ bool SystemZTargetLowering::verifyNarrowIntegerArgs( return true; } + +void SystemZTargetLowering::insertSSPDeclarations( + Module &M, const LibcallLoweringInfo &Libcalls) const { + StringRef GuardMode = M.getStackProtectorGuard(); + + // In the TLS case, no symbol needs to be inserted. + if (GuardMode == "tls" || GuardMode.empty()) + return; + + // Otherwise (in the global case), insert the appropriate global variable. + TargetLowering::insertSSPDeclarations(M, Libcalls); +} \ No newline at end of file diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index 65197bbf0ee1d..7facd3a27d97c 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -16,6 +16,7 @@ #include "SystemZ.h" #include "SystemZInstrInfo.h" +#include "llvm/CodeGen/LibcallLoweringInfo.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/TargetLowering.h" @@ -227,10 +228,10 @@ class SystemZTargetLowering : public TargetLowering { /// Override to support customized stack guard loading. bool useLoadStackGuardNode(const Module &M) const override { return true; } + /// Insert SSP declaration if global stack protector is used. void insertSSPDeclarations(Module &M, - const LibcallLoweringInfo &Libcalls) const override {} - + const LibcallLoweringInfo &Libcalls) const override; MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const override; @@ -473,7 +474,9 @@ class SystemZTargetLowering : public TargetLowering { unsigned Opcode) const; MachineBasicBlock *emitProbedAlloca(MachineInstr &MI, MachineBasicBlock *MBB) const; - + MachineBasicBlock *emitStackGuardPseudo(MachineInstr &MI, + MachineBasicBlock *MBB, + unsigned PseudoOp) const; SDValue getBackchainAddress(SDValue SP, SelectionDAG &DAG) const; MachineMemOperand::Flags diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp index 3a3190a76cad8..aaf90d5ec29f0 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -33,6 +33,7 @@ #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/VirtRegMap.h" +#include "llvm/IR/Module.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" @@ -229,35 +230,6 @@ void SystemZInstrInfo::expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode, MI.eraseFromParent(); } -void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const { - MachineBasicBlock *MBB = MI->getParent(); - MachineFunction &MF = *MBB->getParent(); - const Register Reg64 = MI->getOperand(0).getReg(); - const Register Reg32 = RI.getSubReg(Reg64, SystemZ::subreg_l32); - - // EAR can only load the low subregister so us a shift for %a0 to produce - // the GR containing %a0 and %a1. - - // ear <reg>, %a0 - BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32) - .addReg(SystemZ::A0) - .addReg(Reg64, RegState::ImplicitDefine); - - // sllg <reg>, <reg>, 32 - BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::SLLG), Reg64) - .addReg(Reg64) - .addReg(0) - .addImm(32); - - // ear <reg>, %a1 - BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32) - .addReg(SystemZ::A1); - - // lg <reg>, 40(<reg>) - MI->setDesc(get(SystemZ::LG)); - MachineInstrBuilder(MF, MI).addReg(Reg64).addImm(40).addReg(0); -} - // Emit a zero-extending move from 32-bit GPR SrcReg to 32-bit GPR // DestReg before MBBI in MBB. Use LowLowOpcode when both DestReg and SrcReg // are low registers, otherwise use RISB[LH]G. Size is the number of bits @@ -1810,8 +1782,12 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { splitAdjDynAlloc(MI); return true; - case TargetOpcode::LOAD_STACK_GUARD: - expandLoadStackGuard(&MI); + case SystemZ::MOV_STACKGUARD: + expandStackGuardPseudo(MI, SystemZ::MVC); + return true; + + case SystemZ::CMP_STACKGUARD: + expandStackGuardPseudo(MI, SystemZ::CLC); return true; default: @@ -1819,6 +1795,51 @@ bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { } } +void SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI, + unsigned Opcode) const { + MachineBasicBlock &MBB = *(MI.getParent()); + const MachineFunction &MF = *(MBB.getParent()); + const auto DL = MI.getDebugLoc(); + const Module *M = MF.getFunction().getParent(); + StringRef GuardType = M->getStackProtectorGuard(); + unsigned int Offset = 0; + + Register AddrReg = MI.getOperand(0).getReg(); + Register OpReg = MI.getOperand(1).getReg(); + + assert( + AddrReg != OpReg && + "Scratch register for stack guard address blocked by operand register."); + + // Emit an appropriate pseudo for the guard type, which loads the address of + // said guard into the scratch register AddrReg. + if (GuardType.empty() || (GuardType == "tls")) { + // Emit a load of the TLS block's address + BuildMI(MBB, MI, DL, get(SystemZ::LOAD_TLS_BLOCK_ADDR), AddrReg); + // Record the appropriate stack guard offset (40 in the tls case). + Offset = 40; + } else if (GuardType == "global") { + // Emit a load of the global stack guard's address + BuildMI(MBB, MI, DL, get(SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR), AddrReg); + } else { + report_fatal_error( + (Twine("unknown stack protector type \"") + GuardType + "\".") + .str() + .c_str()); + } + + // Construct the appropriate move or compare instruction using the + // scratch register. + BuildMI(*(MI.getParent()), MI, MI.getDebugLoc(), get(Opcode)) + .addReg(MI.getOperand(1).getReg()) + .addImm(MI.getOperand(2).getImm()) + .addImm(8) + .addReg(AddrReg) + .addImm(Offset); + + MI.removeFromParent(); +} + unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { if (MI.isInlineAsm()) { const MachineFunction *MF = MI.getParent()->getParent(); @@ -1837,6 +1858,12 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { return 18 + (MI.getOperand(0).getImm() == SystemZ::CondReturn ? 4 : 0); if (MI.getOpcode() == TargetOpcode::BUNDLE) return getInstBundleSize(MI); + if (MI.getOpcode() == SystemZ::LOAD_TLS_BLOCK_ADDR) + // ear (4), sllg (6), ear (4) = 14 bytes + return 14; + if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR) + // Both larl and lgrl are 6 bytes long. + return 6; return MI.getDesc().getSize(); } diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h index fdf349ae41049..0bf20bff52622 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h @@ -193,8 +193,7 @@ class SystemZInstrInfo : public SystemZGenInstrInfo { unsigned HighOpcode) const; void expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode, unsigned Size) const; - void expandLoadStackGuard(MachineInstr *MI) const; - + void expandStackGuardPseudo(MachineInstr &MI, unsigned Opcode) const; MachineInstrBuilder emitGRX32Move(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index 35a923d070e3e..269fa6ffda0b9 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -522,6 +522,44 @@ let SimpleBDXStore = 1, mayStore = 1 in { [(store GR128:$src, bdxaddr20only128:$dst)]>; } } + +let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 1 in { + // Load the TLS block's address for the purpose of loading the stack guard. + def LOAD_TLS_BLOCK_ADDR : Pseudo<(outs ADDR64:$grdaddr), + (ins), []>; + // Load the address of a global variable holding the stack guard. + def LOAD_GLOBAL_STACKGUARD_ADDR : Pseudo<(outs ADDR64:$grdaddr), + (ins), []>; + + let mayStore = 1 in { + // Move the stack guard to the stack. + let usesCustomInserter = 1 in + def MOV_STACKGUARD_DAG : Pseudo<(outs), + (ins bdaddr12only:$grdloc), [ + (z_mov_stackguard + bdaddr12only:$grdloc + ) + ]>; + let Constraints = "@earlyclobber $grdaddr" in + def MOV_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr), + (ins bdaddr12only:$grdloc), []>; + } + let Defs = [CC] in { + // Compare the stack guard against the one on the stack. + let usesCustomInserter = 1 in + def CMP_STACKGUARD_DAG : Pseudo<(outs), + (ins bdaddr12only:$grdloc), + [(set CC, + (z_cmp_stackguard + (load bdaddr12only:$grdloc) + ) + )]>; + let Constraints = "@earlyclobber $grdaddr" in + def CMP_STACKGUARD : Pseudo<(outs ADDR64:$grdaddr), + (ins bdaddr12only:$grdloc), []>; + } +} + def STRL : StoreRILPC<"strl", 0xC4F, aligned_store, GR32>; def STGRL : StoreRILPC<"stgrl", 0xC4B, aligned_store, GR64>; diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td index 758445e2a566d..b69f84d78aaf1 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -21,6 +21,11 @@ def SDT_ZICmp : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32>]>; +def SDT_ZICmpSG : SDTypeProfile<1, 1, + [SDTCisVT<0, i32>, + SDTCisPtrTy<1>]>; +def SDT_ZMovSG : SDTypeProfile<0, 1, + [SDTCisPtrTy<0>]>; def SDT_ZBRCCMask : SDTypeProfile<0, 4, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, @@ -303,6 +308,15 @@ def z_pcrel_offset : SDNode<"SystemZISD::PCREL_OFFSET", // to compare, and an integer of type SystemZICMP. def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp>; +// A special form of icmp dedicated to comparing a stack protector value +// to a stack slot. Kept separate to enable custom lowering. +def z_cmp_stackguard : SDNode<"SystemZISD::CMP_STACKGUARD", SDT_ZICmpSG>; + +// A special ISD node intended to mirror z_cmp_stackguard, but modeling +// the moving of the stackguard to the stack instead of the (later) compare. +def z_mov_stackguard : SDNode<"SystemZISD::MOV_STACKGUARD", SDT_ZMovSG, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; + // Floating-point comparisons. The two operands are the values to compare. def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp>; diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll new file mode 100644 index 0000000000000..5e691c8461153 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-nopic.ll @@ -0,0 +1,158 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s + +define i32 @test_global_stack_guard() #0 { +; CHECK-LABEL: test_global_stack_guard: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp0 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: mvc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp1 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB0_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 1304(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB0_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + +define i32 @test_global_stack_guard_branch(i32 %in) #0 { +; CHECK-LABEL: test_global_stack_guard_branch: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r13, %r15, 104(%r15) +; CHECK-NEXT: .cfi_offset %r13, -56 +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp2 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp2: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: mvc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: lr %r13, %r2 +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: cije %r13, 1, .LBB1_4 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: cijlh %r13, 0, .LBB1_6 +; CHECK-NEXT: # %bb.2: # %foo +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp3 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp3: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.3: # %foo +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_4: # %bar +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp4 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp4: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.5: # %bar +; CHECK-NEXT: lhi %r2, 1 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_6: # %else +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp5 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp5: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.7: # %else +; CHECK-NEXT: lhi %r2, 2 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_8: # %bar +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + switch i32 %in, label %else [ + i32 0, label %foo + i32 1, label %bar + ] +foo: + ret i32 0 +bar: + ret i32 1 +else: + ret i32 2 +} + +define i32 @test_global_stack_guard_large() #0 { +; CHECK-LABEL: test_global_stack_guard_large: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -8376 +; CHECK-NEXT: .cfi_def_cfa_offset 8536 +; CHECK-NEXT: lay %r2, 8192(%r15) +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp6 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp6: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: mvc 176(8,%r2), 0(%r1) +; CHECK-NEXT: la %r2, 176(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: lay %r2, 8192(%r15) +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp7 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp7: +; CHECK-NEXT: larl %r1, __stack_chk_guard +; CHECK-NEXT: clc 176(8,%r2), 0(%r1) +; CHECK-NEXT: jlh .LBB2_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 8488(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB2_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [2048 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + + +declare void @foo3(ptr) + +attributes #0 = { sspstrong } + + +!llvm.module.flags = !{!0, !1} +!0 = !{i32 1, !"stack-protector-guard", !"global"} +!1 = !{i32 7, !"stack-protector-guard-record", i32 1} diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll new file mode 100644 index 0000000000000..d138dfbdb5c67 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/stack-guard-global-pic.ll @@ -0,0 +1,160 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s + +define i32 @test_global_stack_guard() #0 { +; CHECK-LABEL: test_global_stack_guard: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp0 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp0: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: mvc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp1 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp1: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB0_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 1304(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB0_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + +define i32 @test_global_stack_guard_branch(i32 %in) #0 { +; CHECK-LABEL: test_global_stack_guard_branch: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r13, %r15, 104(%r15) +; CHECK-NEXT: .cfi_offset %r13, -56 +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp2 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp2: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: mvc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: lr %r13, %r2 +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: cije %r13, 1, .LBB1_4 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: cijlh %r13, 0, .LBB1_6 +; CHECK-NEXT: # %bb.2: # %foo +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp3 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp3: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.3: # %foo +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_4: # %bar +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp4 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp4: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.5: # %bar +; CHECK-NEXT: lhi %r2, 1 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_6: # %else +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp5 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp5: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: clc 1184(8,%r15), 0(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.7: # %else +; CHECK-NEXT: lhi %r2, 2 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_8: # %bar +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + switch i32 %in, label %else [ + i32 0, label %foo + i32 1, label %bar + ] +foo: + ret i32 0 +bar: + ret i32 1 +else: + ret i32 2 +} + + +define i32 @test_global_stack_guard_large() #0 { +; CHECK-LABEL: test_global_stack_guard_large: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -8376 +; CHECK-NEXT: .cfi_def_cfa_offset 8536 +; CHECK-NEXT: lay %r2, 8192(%r15) +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp6 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp6: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: mvc 176(8,%r2), 0(%r1) +; CHECK-NEXT: la %r2, 176(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: lay %r2, 8192(%r15) +; CHECK-NEXT: .section __stack_protector_loc,"a",@progbits +; CHECK-NEXT: .quad .Ltmp7 +; CHECK-NEXT: .text +; CHECK-NEXT: .Ltmp7: +; CHECK-NEXT: lgrl %r1, __stack_chk_guard@GOTENT +; CHECK-NEXT: clc 176(8,%r2), 0(%r1) +; CHECK-NEXT: jlh .LBB2_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 8488(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB2_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [2048 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + +declare void @foo3(ptr) + +attributes #0 = { sspstrong "mstackprotector-guard-record" } + + +!llvm.module.flags = !{!0, !1, !2, !3} +!0 = !{i32 1, !"stack-protector-guard", !"global"} +!1 = !{i32 7, !"stack-protector-guard-record", i32 1} +!2 = !{i32 8, !"PIC Level", i32 2} +!3 = !{i32 7, !"PIE Level", i32 2} diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll new file mode 100644 index 0000000000000..a3b9b938e097a --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/stack-guard-pseudos.ll @@ -0,0 +1,23 @@ +; RUN: llc -stop-after=systemz-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-DAGCOMBINE %s +; RUN: llc -stop-after=finalize-isel -mtriple=s390x-ibm-linux < %s -o - | FileCheck -check-prefix=CHECK-CUSTOMINSERT %s +; CHECK-DAGCOMBINE: bb.0.entry: +; CHECK-DAGCOMBINE: MOV_STACKGUARD_DAG %stack.0.StackGuardSlot, 0 +; CHECK-DAGCOMBINE: CMP_STACKGUARD_DAG %stack.0.StackGuardSlot, 0, implicit-def $cc +; CHECK-CUSTOMINSERT: bb.0.entry +; CHECK-CUSTOMINSERT: early-clobber %6:addr64bit = MOV_STACKGUARD %stack.0.StackGuardSlot, 0 +; CHECK_CUSTOMINSERT: bb.3.entry +; CHECK-CUSTOMINSERT: early-clobber %10:addr64bit = CMP_STACKGUARD %stack.0.StackGuardSlot, 0, implicit-def $cc + +define dso_local signext i32 @stack_guard_pseudo_check(i32 %argc, ptr %argv) #0 { +entry: + %Buffer = alloca [8 x i8], align 1 + call void @llvm.memset.p0.i64(ptr align 1 %Buffer, i8 0, i64 8, i1 false) + %arraydecay = getelementptr inbounds [8 x i8], ptr %Buffer, i64 0, i64 0 + %call = call ptr @strcpy(ptr noundef %arraydecay, ptr noundef %argv) + ret i32 0 +} + +declare void @llvm.memset.p0.i64(ptr writeonly captures(none), i8, i64, i1 immarg) +declare ptr @strcpy(ptr noundef, ptr noundef) + +attributes #0 = { ssp } diff --git a/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll b/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll new file mode 100644 index 0000000000000..ea5ad0d5429cb --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/stack-guard-tls.ll @@ -0,0 +1,135 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc < %s -mtriple=s390x-linux-gnu -verify-machineinstrs | FileCheck %s + +define i32 @test_tls_stack_guard() #0 { +; CHECK-LABEL: test_tls_stack_guard: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: mvc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: clc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: jlh .LBB0_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 1304(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB0_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + + +define i32 @test_global_stack_guard_branch(i32 %in) #0 { +; CHECK-LABEL: test_global_stack_guard_branch: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r13, %r15, 104(%r15) +; CHECK-NEXT: .cfi_offset %r13, -56 +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: mvc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: lr %r13, %r2 +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: cije %r13, 1, .LBB1_4 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: cijlh %r13, 0, .LBB1_6 +; CHECK-NEXT: # %bb.2: # %foo +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: clc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.3: # %foo +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_4: # %bar +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: clc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.5: # %bar +; CHECK-NEXT: lhi %r2, 1 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_6: # %else +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: clc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: jlh .LBB1_8 +; CHECK-NEXT: # %bb.7: # %else +; CHECK-NEXT: lhi %r2, 2 +; CHECK-NEXT: lmg %r13, %r15, 1296(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB1_8: # %bar +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + switch i32 %in, label %else [ + i32 0, label %foo + i32 1, label %bar + ] +foo: + ret i32 0 +bar: + ret i32 1 +else: + ret i32 2 +} + +define i32 @test_tls_stack_guard_large() #0 { +; CHECK-LABEL: test_tls_stack_guard_large: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: aghi %r15, -1192 +; CHECK-NEXT: .cfi_def_cfa_offset 1352 +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: mvc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: la %r2, 160(%r15) +; CHECK-NEXT: brasl %r14, foo3@PLT +; CHECK-NEXT: ear %r1, %a0 +; CHECK-NEXT: sllg %r1, %r1, 32 +; CHECK-NEXT: ear %r1, %a1 +; CHECK-NEXT: clc 1184(8,%r15), 40(%r1) +; CHECK-NEXT: jlh .LBB2_2 +; CHECK-NEXT: # %bb.1: # %entry +; CHECK-NEXT: lhi %r2, 0 +; CHECK-NEXT: lmg %r14, %r15, 1304(%r15) +; CHECK-NEXT: br %r14 +; CHECK-NEXT: .LBB2_2: # %entry +; CHECK-NEXT: brasl %r14, __stack_chk_fail@PLT +entry: + %a1 = alloca [256 x i32], align 4 + call void @foo3(ptr %a1) + ret i32 0 +} + +declare void @foo3(ptr) + +attributes #0 = { sspstrong } diff --git a/llvm/test/CodeGen/SystemZ/stack-guard.ll b/llvm/test/CodeGen/SystemZ/stack-guard.ll deleted file mode 100644 index 04a87b4632dd2..0000000000000 --- a/llvm/test/CodeGen/SystemZ/stack-guard.ll +++ /dev/null @@ -1,33 +0,0 @@ -; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s - -; CHECK-LABEL: @test_stack_guard -; CHECK: ear [[REG1:%r[1-9][0-9]?]], %a0 -; CHECK: sllg [[REG1]], [[REG1]], 32 -; CHECK: ear [[REG1]], %a1 -; CHECK: lg [[REG1]], 40([[REG1]]) -; CHECK: stg [[REG1]], {{[0-9]*}}(%r15) -; CHECK: brasl %r14, foo3@PLT -; CHECK: ear [[REG2:%r[1-9][0-9]?]], %a0 -; CHECK: sllg [[REG2]], [[REG2]], 32 -; CHECK: ear [[REG2]], %a1 -; CHECK: lg [[REG2]], 40([[REG2]]) -; CHECK: cg [[REG2]], {{[0-9]*}}(%r15) - -define i32 @test_stack_guard() #0 { -entry: - %a1 = alloca [256 x i32], align 4 - call void @llvm.lifetime.start.p0(i64 1024, ptr %a1) - call void @foo3(ptr %a1) - call void @llvm.lifetime.end.p0(i64 1024, ptr %a1) - ret i32 0 -} - -; Function Attrs: nounwind -declare void @llvm.lifetime.start.p0(i64, ptr nocapture) - -declare void @foo3(ptr) - -; Function Attrs: nounwind -declare void @llvm.lifetime.end.p0(i64, ptr nocapture) - -attributes #0 = { sspstrong } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
