This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0f417789192e: [AArch64] Support customizing stack protector 
guard (authored by nickdesaulniers).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100919/new/

https://reviews.llvm.org/D100919

Files:
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/test/Driver/stack-protector-guard.c
  llvm/include/llvm/Target/TargetOptions.h
  llvm/lib/CodeGen/CommandFlags.cpp
  llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
  llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll

Index: llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/AArch64/stack-guard-sysreg.ll
@@ -0,0 +1,105 @@
+; 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
Index: llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -1904,6 +1904,68 @@
   }
 
   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();
Index: llvm/lib/CodeGen/CommandFlags.cpp
===================================================================
--- llvm/lib/CodeGen/CommandFlags.cpp
+++ llvm/lib/CodeGen/CommandFlags.cpp
@@ -508,6 +508,8 @@
     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());
Index: llvm/include/llvm/Target/TargetOptions.h
===================================================================
--- llvm/include/llvm/Target/TargetOptions.h
+++ 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,
@@ -335,7 +331,7 @@
     /// 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;
 
Index: clang/test/Driver/stack-protector-guard.c
===================================================================
--- clang/test/Driver/stack-protector-guard.c
+++ clang/test/Driver/stack-protector-guard.c
@@ -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-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
 
@@ -41,3 +41,19 @@
 // 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='
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -3102,25 +3102,28 @@
     }
   }
 
-  // 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;
@@ -3133,7 +3136,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")) {
@@ -3141,6 +3144,10 @@
           << 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);
   }
 }
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -559,10 +559,11 @@
   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;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -3410,7 +3410,7 @@
   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"}]>;
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -364,8 +364,10 @@
   /// 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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to