/// other styles we may implement in the future.
std::string StackProtectorGuard;
- /// The TLS base register when StackProtectorGuard is "tls".
+ /// The TLS base register when StackProtectorGuard is "tls", or register used
+ /// to store the stack canary for "sysreg".
/// On x86 this can be "fs" or "gs".
+ /// On AArch64 this can only be "sp_el0".
std::string StackProtectorGuardReg;
/// Path to ignorelist file specifying which objects
MarshallingInfoString<CodeGenOpts<"StackProtectorGuard">>;
def mstack_protector_guard_offset_EQ : Joined<["-"], "mstack-protector-guard-offset=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use the given offset for addressing the stack-protector guard">,
- MarshallingInfoInt<CodeGenOpts<"StackProtectorGuardOffset">, "INT_MAX">;
+ MarshallingInfoInt<CodeGenOpts<"StackProtectorGuardOffset">, "INT_MAX", "int">;
def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Use the given reg for addressing the stack-protector guard">,
MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">, [{"none"}]>;
Options.UniqueBasicBlockSectionNames =
CodeGenOpts.UniqueBasicBlockSectionNames;
Options.StackProtectorGuard =
- llvm::StringSwitch<llvm::StackProtectorGuards>(CodeGenOpts
- .StackProtectorGuard)
+ llvm::StringSwitch<llvm::StackProtectorGuards>(
+ 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;
}
}
- // 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 (EffectiveTriple.isX86() && Value != "tls" && Value != "global") {
D.Diag(diag::err_drv_invalid_value_with_suggestion)
<< A->getOption().getName() << Value << "tls global";
return;
}
+ if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") {
+ D.Diag(diag::err_drv_invalid_value_with_suggestion)
+ << A->getOption().getName() << Value << "sysreg global";
+ return;
+ }
A->render(Args, CmdArgs);
}
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;
int Offset;
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")) {
<< A->getOption().getName() << Value << "fs gs";
return;
}
+ if (EffectiveTriple.isAArch64() && Value != "sp_el0") {
+ D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value;
+ return;
+ }
A->render(Args, CmdArgs);
}
}
// 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-gnueabi -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
// 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 | \
+// RUN: FileCheck -check-prefix=CHECK-AARCH64 %s
+// RUN: %clang -### -target aarch64-linux-gnu \
+// RUN: -mstack-protector-guard=tls %s 2>&1 | \
+// RUN: FileCheck -check-prefix=INVALID-VALUE-AARCH64 %s
+// RUN: %clang -### -target aarch64-linux-gnu -mstack-protector-guard=sysreg \
+// RUN: -mstack-protector-guard-reg=foo \
+// RUN: -mstack-protector-guard-offset=0 %s 2>&1 | \
+// RUN: FileCheck -check-prefix=INVALID-REG-AARCH64 %s
+
+// CHECK-AARCH64: "-cc1" {{.*}}"-mstack-protector-guard=sysreg" "-mstack-protector-guard-offset=0" "-mstack-protector-guard-reg=sp_el0"
+// INVALID-VALUE-AARCH64: error: invalid value 'tls' in 'mstack-protector-guard=', expected one of: sysreg global
+// INVALID-REG-AARCH64: error: invalid value 'foo' in 'mstack-protector-guard-reg='
None // Do not use Basic Block Sections.
};
- enum class StackProtectorGuards {
- None,
- TLS,
- Global
- };
+ enum class StackProtectorGuards { None, TLS, Global, SysReg };
enum class EABI {
Unknown,
/// Stack protector guard offset to use.
int StackProtectorGuardOffset = INT_MAX;
- /// 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;
return StackProtectorGuards::TLS;
if (getStackProtectorGuard() == "global")
return StackProtectorGuards::Global;
+ if (getStackProtectorGuard() == "sysreg")
+ return StackProtectorGuards::SysReg;
if (getStackProtectorGuard() != "none") {
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
MemoryBuffer::getFile(getStackProtectorGuard());
}
Register Reg = MI.getOperand(0).getReg();
+ TargetOptions Options = MI.getParent()->getParent()->getTarget().Options;
+ if (Options.StackProtectorGuard == StackProtectorGuards::SysReg) {
+ const AArch64SysReg::SysReg *SrcReg =
+ AArch64SysReg::lookupSysRegByName(Options.StackProtectorGuardReg);
+ if (!SrcReg)
+ report_fatal_error("Unknown SysReg for Stack Protector Guard Register");
+
+ // mrs xN, sysreg
+ BuildMI(MBB, MI, DL, get(AArch64::MRS))
+ .addDef(Reg, RegState::Renamable)
+ .addImm(SrcReg->Encoding);
+ int Offset = Options.StackProtectorGuardOffset;
+ if (Offset >= 0 && Offset <= 32760 && Offset % 8 == 0) {
+ // ldr xN, [xN, #offset]
+ BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
+ .addDef(Reg)
+ .addUse(Reg, RegState::Kill)
+ .addImm(Offset / 8);
+ } else if (Offset >= -256 && Offset <= 255) {
+ // ldur xN, [xN, #offset]
+ BuildMI(MBB, MI, DL, get(AArch64::LDURXi))
+ .addDef(Reg)
+ .addUse(Reg, RegState::Kill)
+ .addImm(Offset);
+ } else if (Offset >= -4095 && Offset <= 4095) {
+ if (Offset > 0) {
+ // add xN, xN, #offset
+ BuildMI(MBB, MI, DL, get(AArch64::ADDXri))
+ .addDef(Reg)
+ .addUse(Reg, RegState::Kill)
+ .addImm(Offset)
+ .addImm(0);
+ } else {
+ // sub xN, xN, #offset
+ BuildMI(MBB, MI, DL, get(AArch64::SUBXri))
+ .addDef(Reg)
+ .addUse(Reg, RegState::Kill)
+ .addImm(-Offset)
+ .addImm(0);
+ }
+ // ldr xN, [xN]
+ BuildMI(MBB, MI, DL, get(AArch64::LDRXui))
+ .addDef(Reg)
+ .addUse(Reg, RegState::Kill)
+ .addImm(0);
+ } else {
+ // Cases that are larger than +/- 4095 and not a multiple of 8, or larger
+ // than 23760.
+ // It might be nice to use AArch64::MOVi32imm here, which would get
+ // expanded in PreSched2 after PostRA, but our lone scratch Reg already
+ // contains the MRS result. findScratchNonCalleeSaveRegister() in
+ // AArch64FrameLowering might help us find such a scratch register
+ // though. If we failed to find a scratch register, we could emit a
+ // stream of add instructions to build up the immediate. Or, we could try
+ // to insert a AArch64::MOVi32imm before register allocation so that we
+ // didn't need to scavenge for a scratch register.
+ report_fatal_error("Unable to encode Stack Protector Guard Offset");
+ }
+ MBB.erase(MI);
+ return true;
+ }
+
const GlobalValue *GV =
cast<GlobalValue>((*MI.memoperands_begin())->getValue());
const TargetMachine &TM = MBB.getParent()->getTarget();
--- /dev/null
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=0 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NO-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=8 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-POSITIVE-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=-8 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NEGATIVE-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=1 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NPOT-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=-1 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NPOT-NEG-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=257 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-257-OFFSET %s
+; RUN: llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=-257 -verify-machineinstrs -o - | \
+; RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-MINUS-257-OFFSET %s
+
+; XFAIL
+; RUN: not --crash llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=32761 -o - 2>&1 | \
+; RUN: FileCheck --check-prefix=CHECK-BAD-OFFSET %s
+; RUN: not --crash llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=-4096 -o - 2>&1 | \
+; RUN: FileCheck --check-prefix=CHECK-BAD-OFFSET %s
+; RUN: not --crash llc %s --stack-protector-guard=sysreg \
+; RUN: --stack-protector-guard-reg=sp_el0 \
+; RUN: --stack-protector-guard-offset=4097 -o - 2>&1 | \
+; RUN: FileCheck --check-prefix=CHECK-BAD-OFFSET %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: mrs x8, SP_EL0
+; CHECK-NO-OFFSET: ldr x8, [x8]
+; CHECK-POSITIVE-OFFSET: ldr x8, [x8, #8]
+; CHECK-NEGATIVE-OFFSET: ldur x8, [x8, #-8]
+; CHECK-NPOT-OFFSET: ldur x8, [x8, #1]
+; CHECK-NPOT-NEG-OFFSET: ldur x8, [x8, #-1]
+; CHECK-257-OFFSET: add x8, x8, #257
+; CHECK-257-OFFSET-NEXT: ldr x8, [x8]
+; CHECK-MINUS-257-OFFSET: sub x8, x8, #257
+; CHECK-MINUS-257-OFFSET-NEXT: ldr x8, [x8]
+; CHECK-NEXT: lsl x9, x0, #2
+; CHECK-NEXT: add x9, x9, #15 // =15
+; CHECK-NEXT: and x9, x9, #0xfffffffffffffff0
+; CHECK-NEXT: stur x8, [x29, #-8]
+; CHECK-NEXT: mov x8, sp
+; 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-NO-OFFSET: ldr x9, [x9]
+; CHECK-POSITIVE-OFFSET: ldr x9, [x9, #8]
+; CHECK-NEGATIVE-OFFSET: ldur x9, [x9, #-8]
+; CHECK-NPOT-OFFSET: ldur x9, [x9, #1]
+; CHECK-NPOT-NEG-OFFSET: ldur x9, [x9, #-1]
+; CHECK-257-OFFSET: add x9, x9, #257
+; CHECK-257-OFFSET-NEXT: ldr x9, [x9]
+; CHECK-MINUS-257-OFFSET: sub x9, x9, #257
+; CHECK-MINUS-257-OFFSET-NEXT: ldr x9, [x9]
+; 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 void @baz(i32*)
+
+attributes #0 = { sspstrong }
+
+; CHECK-BAD-OFFSET: LLVM ERROR: Unable to encode Stack Protector Guard Offset