diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -382,6 +382,7 @@ /// The TLS base register when StackProtectorGuard is "tls". /// On x86 this can be "fs" or "gs". + /// On AArch64 this can be any value of llvm::AArch64SysReg::SysReg. std::string StackProtectorGuardReg; /// Path to blocklist file specifying which objects diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -555,10 +555,11 @@ Options.UniqueBasicBlockSectionNames = CodeGenOpts.UniqueBasicBlockSectionNames; Options.StackProtectorGuard = - llvm::StringSwitch(CodeGenOpts - .StackProtectorGuard) + llvm::StringSwitch( + CodeGenOpts.StackProtectorGuard) .Case("tls", llvm::StackProtectorGuards::TLS) .Case("global", llvm::StackProtectorGuards::Global) + .Case("sysreg", llvm::StackProtectorGuards::SysReg) .Default(llvm::StackProtectorGuards::None); Options.StackProtectorGuardOffset = CodeGenOpts.StackProtectorGuardOffset; Options.StackProtectorGuardReg = CodeGenOpts.StackProtectorGuardReg; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3095,18 +3095,17 @@ } } - // First support "tls" and "global" for X86 target. - // TODO: Support "sysreg" for AArch64. const std::string &TripleStr = EffectiveTriple.getTriple(); if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) { StringRef Value = A->getValue(); if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; - if (Value != "tls" && Value != "global") { + if (Value != "tls" && Value != "global" && Value != "sysreg") { D.Diag(diag::err_drv_invalid_value_with_suggestion) - << A->getOption().getName() << Value - << "valid arguments to '-mstack-protector-guard=' are:tls global"; + << A->getOption().getName() << Value + << "valid arguments to '-mstack-protector-guard=' are:tls global " + "sysreg"; return; } A->render(Args, CmdArgs); @@ -3114,7 +3113,7 @@ if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_offset_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; unsigned Offset; @@ -3127,7 +3126,7 @@ if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_reg_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; if (EffectiveTriple.isX86() && (Value != "fs" && Value != "gs")) { @@ -3136,6 +3135,11 @@ << "for X86, valid arguments to '-mstack-protector-guard-reg=' are:fs gs"; return; } + if (EffectiveTriple.isAArch64() && Value != "sp_el0") { + D.Diag(diag::err_drv_invalid_value_with_suggestion) + << A->getOption().getName() << Value; + return; + } A->render(Args, CmdArgs); } } diff --git a/clang/test/Driver/stack-protector-guard.c b/clang/test/Driver/stack-protector-guard.c --- a/clang/test/Driver/stack-protector-guard.c +++ b/clang/test/Driver/stack-protector-guard.c @@ -7,7 +7,7 @@ // CHECK-TLS: "-cc1" {{.*}}"-mstack-protector-guard=tls" // CHECK-GLOBAL: "-cc1" {{.*}}"-mstack-protector-guard=global" -// INVALID-VALUE: error: invalid value 'local' in 'mstack-protector-guard=','valid arguments to '-mstack-protector-guard=' are:tls global' +// INVALID-VALUE: error: invalid value 'local' in 'mstack-protector-guard=','valid arguments to '-mstack-protector-guard=' are:tls global sysreg' // RUN: %clang -### -target x86_64-unknown-unknown -mstack-protector-guard-reg=fs %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-FS %s @@ -23,7 +23,7 @@ // RUN: FileCheck -check-prefix=INVALID-ARCH2 %s // INVALID-ARCH2: unsupported option '-mstack-protector-guard-reg=fs' for target -// RUN: not %clang -target aarch64-linux-gnu -mstack-protector-guard-offset=10 %s 2>&1 | \ +// RUN: not %clang -target arm-linux-gnuebi -mstack-protector-guard-offset=10 %s 2>&1 | \ // RUN: FileCheck -check-prefix=INVALID-ARCH3 %s // INVALID-ARCH3: unsupported option '-mstack-protector-guard-offset=10' for target @@ -41,3 +41,11 @@ // RUN: FileCheck -check-prefix=CHECK-OFFSET %s // CHECK-OFFSET: "-cc1" {{.*}}"-mstack-protector-guard-offset=30" + +// RUN: %clang -### -target aarch64-linux-gnu -mstack-protector-guard=sysreg \ +// RUN: -mstack-protector-guard-reg=sp_el0 \ +// RUN: -mstack-protector-guard-offset=0 %s 2>&1 | FileCheck \ +// RUN: -check-prefix=CHECK-AARCH64 %s + +// CHECK-AARCH64: "-cc1" {{.*}}"-mstack-protector-guard=sysreg" "-mstack-protector-guard-offset=0" "-mstack-protector-guard-reg=sp_el0" +// TODO: check invalid reg diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -73,11 +73,7 @@ None // Do not use Basic Block Sections. }; - enum class StackProtectorGuards { - None, - TLS, - Global - }; + enum class StackProtectorGuards { None, TLS, Global, SysReg }; enum class EABI { Unknown, @@ -334,7 +330,7 @@ /// Stack protector guard offset to use. unsigned StackProtectorGuardOffset = -1U; - /// Stack protector guard mode to use, e.g. tls, global. + /// Stack protector guard mode to use, e.g. tls, global, sysreg. StackProtectorGuards StackProtectorGuard = StackProtectorGuards::None; diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -502,6 +502,8 @@ return StackProtectorGuards::TLS; if (getStackProtectorGuard() == "global") return StackProtectorGuards::Global; + if (getStackProtectorGuard() == "sysreg") + return StackProtectorGuards::SysReg; if (getStackProtectorGuard() != "none") { ErrorOr> MBOrErr = MemoryBuffer::getFile(getStackProtectorGuard()); diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1752,6 +1752,21 @@ } Register Reg = MI.getOperand(0).getReg(); + if (MI.getOpcode() == AArch64::LOAD_STACK_GUARD) { + TargetOptions Options = MI.getParent()->getParent()->getTarget().Options; + if (Options.StackProtectorGuard == StackProtectorGuards::SysReg) { + const AArch64SysReg::SysReg *SrcReg = + AArch64SysReg::lookupSysRegByName(Options.StackProtectorGuardReg); + // TODO: if we're given a non-sense StackProtectorGuardReg, so + // SrcReg is nullptr, what should we do? + BuildMI(MBB, MI, DL, get(AArch64::MRS)) + .addReg(Reg, getKillRegState(false)) + .addImm(SrcReg->Encoding); + MBB.erase(MI); + return true; + } + } + const GlobalValue *GV = cast((*MI.memoperands_begin())->getValue()); const TargetMachine &TM = MBB.getParent()->getTarget(); diff --git a/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll b/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc %s --stack-protector-guard=sysreg \ +; RUN: --stack-protector-guard-reg=sp_el0 \ +; RUN: --stack-protector-guard-offset=0 -o - | FileCheck %s + +target triple = "aarch64-unknown-linux-gnu" + +; Verify that we `mrs` from `SP_EL0` twice, rather than load from +; __stack_chk_guard. +define dso_local void @foo(i64 %t) local_unnamed_addr #0 { +; CHECK-LABEL: foo: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill +; CHECK-NEXT: mov x29, sp +; CHECK-NEXT: sub sp, sp, #16 // =16 +; CHECK-NEXT: .cfi_def_cfa w29, 16 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w29, -16 +; CHECK-NEXT: lsl x9, x0, #2 +; CHECK-NEXT: add x9, x9, #15 // =15 +; CHECK-NEXT: mrs x8, SP_EL0 +; CHECK-NEXT: stur x8, [x29, #-8] +; CHECK-NEXT: mov x8, sp +; CHECK-NEXT: and x9, x9, #0xfffffffffffffff0 +; CHECK-NEXT: sub x0, x8, x9 +; CHECK-NEXT: mov sp, x0 +; CHECK-NEXT: bl baz +; CHECK-NEXT: ldur x8, [x29, #-8] +; CHECK-NEXT: mrs x9, SP_EL0 +; CHECK-NEXT: cmp x9, x8 +; CHECK-NEXT: b.ne .LBB0_2 +; CHECK-NEXT: // %bb.1: // %entry +; CHECK-NEXT: mov sp, x29 +; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB0_2: // %entry +; CHECK-NEXT: bl __stack_chk_fail +; CHECK-NOT: __stack_chk_guard +entry: + %vla = alloca i32, i64 %t, align 4 + call void @baz(i32* nonnull %vla) + ret void +} + +declare dso_local void @baz(i32*) local_unnamed_addr + +attributes #0 = { sspstrong }