https://github.com/sujianIBM updated 
https://github.com/llvm/llvm-project/pull/206045

>From a4732561e975ffa1e82081fe593f7c3f6adfbbe5 Mon Sep 17 00:00:00 2001
From: Jian Su <[email protected]>
Date: Thu, 25 Jun 2026 19:34:58 +0000
Subject: [PATCH 1/3] Add support for stack guard on z/OS.

---
 llvm/include/llvm/IR/RuntimeLibcalls.td       |   3 +-
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp |  19 ++
 llvm/lib/Target/SystemZ/SystemZAsmPrinter.h   |   2 +
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp  |  17 +-
 llvm/lib/Target/SystemZ/SystemZInstrInfo.td   |   3 +
 .../CodeGen/SystemZ/zos-stack-protector.ll    | 190 ++++++++++++++++++
 6 files changed, 229 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/SystemZ/zos-stack-protector.ll

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td 
b/llvm/include/llvm/IR/RuntimeLibcalls.td
index 37bad559f49e7..ff23a813ca737 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -3541,7 +3541,8 @@ def isZOS : RuntimeLibcallPredicate<"TT.isOSzOS()">;
 def SystemZZOSSystemLibrary
     : SystemRuntimeLibrary<
           isSystemZZOS, (add DefaultLibcallImpls64,
-                            LibcallImpls<(add ZOSRuntimeLibcalls), isZOS>)>;
+                            LibcallImpls<(add ZOSRuntimeLibcalls), isZOS>,
+                            DefaultStackProtector)>;
 
 
//===----------------------------------------------------------------------===//
 // WebAssembly Runtime Libcalls
diff --git a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp 
b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
index 5c755db5f7f5f..c181e2048becd 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp
@@ -780,6 +780,9 @@ void SystemZAsmPrinter::emitInstruction(const MachineInstr 
*MI) {
   case SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR:
     lowerLOAD_GLOBAL_STACKGUARD_ADDR(*MI, Lower);
     return;
+  case SystemZ::LOAD_LIBRARY_ANCHOR_AREA_ADDR:
+    lowerLOAD_LIBRARY_ANCHOR_AREA_ADDR(*MI, Lower);
+    return;
 
   default:
     Lower.lower(MI, LoweredMI);
@@ -1092,6 +1095,22 @@ void SystemZAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
   }
 }
 
+void SystemZAsmPrinter::lowerLOAD_LIBRARY_ANCHOR_AREA_ADDR(
+    const MachineInstr &MI, SystemZMCInstLower &Lower) {
+  Register AddrReg = MI.getOperand(0).getReg();
+  const SystemZSubtarget &STI = MF->getSubtarget<SystemZSubtarget>();
+
+  assert(STI.isTargetzOS() &&
+         "LOAD_LIBRARY_ANCHOR_AREA_ADDR is only for XPLINK64 on z/OS");
+
+  enum { OFFSET_PSALAA = 0x4B8 };
+  EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLGT)
+                                   .addReg(AddrReg)
+                                   .addReg(0)
+                                   .addImm(OFFSET_PSALAA)
+                                   .addReg(0));
+}
+
 // The *alignment* of 128-bit vector types is different 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 f3703b783f7ec..e383b29b199e5 100644
--- a/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
+++ b/llvm/lib/Target/SystemZ/SystemZAsmPrinter.h
@@ -174,6 +174,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZAsmPrinter : public 
AsmPrinter {
                                 SystemZMCInstLower &Lower);
   void lowerLOAD_GLOBAL_STACKGUARD_ADDR(const MachineInstr &MI,
                                         SystemZMCInstLower &Lower);
+  void lowerLOAD_LIBRARY_ANCHOR_AREA_ADDR(const MachineInstr &MI,
+                                          SystemZMCInstLower &Lower);
   void emitAttributes(Module &M);
 };
 } // end namespace llvm
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp 
b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index d5bdb8ef3b595..2662bb905d96d 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1813,10 +1813,16 @@ void 
SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   // 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;
+    if (STI.isTargetzOS()) {
+      enum { OFFSET_CEELAA_STACK_GUARD = 0x98 };
+      BuildMI(MBB, MI, DL, get(SystemZ::LOAD_LIBRARY_ANCHOR_AREA_ADDR), 
AddrReg);
+      Offset = OFFSET_CEELAA_STACK_GUARD;
+    } else {
+      // 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);
@@ -1861,6 +1867,9 @@ unsigned SystemZInstrInfo::getInstSizeInBytes(const 
MachineInstr &MI) const {
   if (MI.getOpcode() == SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR)
     // Both larl and lgrl are 6 bytes long.
     return 6;
+  if (MI.getOpcode() == SystemZ::LOAD_LIBRARY_ANCHOR_AREA_ADDR)
+    // llgt(6)
+    return 6;
 
   return MI.getDesc().getSize();
 }
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td 
b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 269fa6ffda0b9..8cd135aaa8b1c 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -530,6 +530,9 @@ let hasNoSchedulingInfo = 1, hasSideEffects = 1, mayLoad = 
1 in {
   // Load the address of a global variable holding the stack guard.
   def LOAD_GLOBAL_STACKGUARD_ADDR : Pseudo<(outs ADDR64:$grdaddr),
                                                (ins), []>;
+  // Load the address of Library Anchor Area (LAA) on z/OS
+  def LOAD_LIBRARY_ANCHOR_AREA_ADDR : Pseudo<(outs ADDR64:$grdaddr),
+                                             (ins), []>;
 
   let mayStore = 1 in {
     // Move the stack guard to the stack.
diff --git a/llvm/test/CodeGen/SystemZ/zos-stack-protector.ll 
b/llvm/test/CodeGen/SystemZ/zos-stack-protector.ll
new file mode 100644
index 0000000000000..c56360bbfa4f9
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/zos-stack-protector.ll
@@ -0,0 +1,190 @@
+; Test the stack protector under XPLINK on z/OS
+;
+; RUN: llc < %s -mtriple=s390x-ibm-zos -mcpu=z13 | FileCheck 
--check-prefixes=CHECK %s
+
+; Test stack protector for non-XPLEAF.
+
+; Small stack frame.
+; CHECK-LABEL: func0
+; CHECK:                    * DSA Size [[#%#x,DSA_SIZE:]]
+; CHECK:                    aghi  4,-[[#%u,mul(div(DSA_SIZE,32),32)]]
+; CHECK:                    llgt  [[REG1:[0-9]+]],1208
+; CHECK:                    mvc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)]](8,4),152([[REG1]])
+; ...
+; CHECK:                    llgt  [[REG3:[0-9]+]],1208
+; CHECK:                    clc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)]](8,4),152([[REG3]])
+; CHECK:                    jlh   [[FAIL_LABEL:L#BB[0-9_]+]]
+; success block
+; CHECK:                    aghi  4,[[#%u,mul(div(DSA_SIZE,32),32)]]
+; CHECK:                    b     2(7)
+; failure block
+; CHECK:                    [[FAIL_LABEL]] DS 0H
+; invoke __stack_chk_fail
+; CHECK:                    lg    6,[[#CHK_FAIL_OFF:]]({{[0-9]+}})
+; CHECK:                    lg    5,[[#CHK_FAIL_OFF-8]]({{[0-9]+}})
+; CHECK:                    basr  7,6
+; CHECK-NEXT:               bcr   0,0
+
+define void @func0() sspreq {
+  call i64 (i64) @fun(i64 10)
+  ret void
+}
+
+; Large stack frame.
+; Larger than 1M in XPLINK64.
+; CHECK-LABEL: func1
+; CHECK:                    * DSA Size [[#%#x,DSA_SIZE:]]
+; CHECK:                    stmg  6,{{[0-9]+}},2064(4)
+; CHECK:                    llilh 
[[REG_CANARY_OFF_HIGH:[0-9]+]],[[#%u,CANARY_OFF_HIGH:div(DSA_SIZE,65536)]]
+; CHECK:                    la    
[[REG_CANARY_OFF_HIGH]],0([[REG_CANARY_OFF_HIGH]],4)
+; CHECK:                    llgt  [[REG1:[0-9]+]],1208
+; CHECK:                    mvc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)-mul(CANARY_OFF_HIGH,65536)]](8,[[REG_CANARY_OFF_HIGH]]),152([[REG1]])
+; ...
+; CHECK:                    llilh 
[[REG_CANARY_OFF_HIGH_2:[0-9]+]],[[#%u,CANARY_OFF_HIGH_2:div(DSA_SIZE,65536)]]
+; CHECK:                    la    
[[REG_CANARY_OFF_HIGH_2]],0([[REG_CANARY_OFF_HIGH_2]],4)
+; CHECK:                    llgt  [[REG3:[0-9]+]],1208
+; CHECK:                    clc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)-mul(CANARY_OFF_HIGH_2,65536)]](8,[[REG_CANARY_OFF_HIGH_2]]),152([[REG3]])
+; CHECK:                    jlh   [[FAIL_LABEL:L#BB[0-9_]+]]
+; success block
+; CHECK:                    agfi  4,[[#%u,mul(div(DSA_SIZE,32),32)]]
+; CHECK:                    b     2(7)
+; failure block
+; CHECK:                    [[FAIL_LABEL]] DS 0H
+; invoke __stack_chk_fail
+; CHECK:                    lg    6,[[#CHK_FAIL_OFF:]]({{[0-9]+}})
+; CHECK:                    lg    5,[[#CHK_FAIL_OFF-8]]({{[0-9]+}})
+; CHECK:                    basr  7,6
+; CHECK-NEXT:               bcr   0,0
+
+define void @func1() sspreq {
+  %arr = alloca [131072 x i64], align 8
+  call i64 (ptr) @fun1(ptr %arr)
+  ret void
+}
+
+; Test converting XPLeaf functions to non-leaf functions if they need stack 
protection
+
+; TODO: Currently any function that needs to store data on the stack is
+; converted to a non-leaf function, so XPLeaf functions never write to the
+; stack, and thus there is no way for them to cause stack corruption.
+;
+; Eventually we'll start taking advantage of the 2048 bytes of space between R4
+; and the caller's stack frame to eliminate the need to convert some functions
+; that would have been XPLeaf functions. At which point, it will be possible 
for
+; an XPLeaf function to corrupt the stack.
+;
+; Since stack protection protects against corruption of the caller's stack
+; frame and not corruption of the callee's stack frame, it doesn't matter that
+; XPLeaf functions don't have a stack frame of their own - that's not what we'd
+; be protecting anyways.
+;
+; Thus, we'll have to choose what to do with functions that need stack 
protection
+; but could remain as XPLeaf functions by using those 2048 bytes of space.
+; We have 3 options:
+; 1. Convert them to non-leaf functions and continue protecting them as before.
+; 2. Keep them as XPLeaf functions, but give up on stack protecting them
+; 3. Keep them as XPLeaf functions, and try to stack protect them without 
making
+;    any function calls in the failure case. This would probably involve
+;    delaying the invocation of __stack_chk_fail/__CEL4SFCR until we return to
+;    the caller.
+;
+; If we choose option 1, leave this test as is and remove this TODO.
+; If we choose option 2, make sure we don't try to stack protect these 
functions.
+; If we choose option 3, this test needs to be replaced, but what we replace it
+; with will depend on how we implement the failure case.
+
+; Based on func3_64 in call-zos-03.ll
+; CHECK-LABEL: func2_64
+; CHECK:                    * Entry Flags
+; CHECK-NEXT:               *   Bit 1: 0 = Non-leaf function
+define i64 @func2_64(i64 %arg0) sspreq {
+  %out = add i64 %arg0, 55
+  ret i64 %out
+}
+
+; Based on func6 in zos-prologue-epilog.ll. R15 is callee-saved, so needs to be
+; spilled to the stack before we use it. As a result this currently gets
+; converted to a non-leaf function (even without sspreq).
+; CHECK-LABEL: func3
+; CHECK:                    * Entry Flags
+; CHECK-NEXT:               *   Bit 1: 0 = Non-leaf function
+define void @func3() local_unnamed_addr sspreq #0 {
+entry:
+  tail call void asm sideeffect " lhi 15,1\0A", "~{r15}"()
+  ret void
+}
+
+; Test stack protector for function that uses alloca()
+
+; CHECK-LABEL: func4
+; CHECK:                    * DSA Size [[#%#x,DSA_SIZE:]]
+; CHECK:                    * Entry Flags
+; CHECK-NEXT:               *   Bit 1: 0 = Non-leaf function
+; CHECK-NEXT:               *   Bit 2: 1 = Uses alloca
+; CHECK:                    stmg  
4,[[SPILLHI:[0-9]+]],[[#%u,2048-mul(div(DSA_SIZE,32),32)]](4)
+; CHECK:                    aghi  4,-[[#%u,mul(div(DSA_SIZE,32),32)]]
+; CHECK:                    lgr   [[ALLOCAREG:[0-9]+]],4
+; CHECK:                    llgt  [[REG1:[0-9]+]],1208
+; CHECK:                    mvc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)]](8,[[ALLOCAREG]]),152([[REG1]])
+; ...
+; CHECK:                    llgt  [[REG3:[0-9]+]],1208
+; CHECK:                    clc   
[[#%u,2040+mul(div(DSA_SIZE,32),32)]](8,[[ALLOCAREG]]),152([[REG3]])
+; CHECK:                    jlh   [[FAIL_LABEL:L#BB[0-9_]+]]
+; success block
+; CHECK:                    lmg   4,[[SPILLHI]],2048(4)
+; CHECK:                    b     2(7)
+; failure block
+; CHECK:                    [[FAIL_LABEL]] DS 0H
+; invoke __stack_chk_fail
+; CHECK:                    lg    6,[[#CHK_FAIL_OFF:]]({{[0-9]+}})
+; CHECK:                    lg    5,[[#CHK_FAIL_OFF-8]]({{[0-9]+}})
+; CHECK:                    basr  7,6
+; CHECK-NEXT:               bcr   0,0
+
+define i64 @func4(i64 %n) sspreq {
+  %vla = alloca i64, i64 %n, align 8
+  %call = call i64 @fun2(i64 %n, ptr nonnull %vla, ptr nonnull %vla)
+  ret i64 %call
+}
+
+; Test stack protector off.
+
+; CHECK-LABEL: func5
+define void @func5() {
+  call i64 (i64) @fun(i64 10)
+  ret void
+}
+
+declare i64 @fun(i64 %arg0)
+declare i64 @fun1(ptr %ptr)
+declare i64 @fun2(i64 %n, ptr %arr0, ptr %arr1)
+
+; CHECK-LABEL: L#PPA1_func0_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 1 = STACKPROTECT is enabled
+
+; CHECK-LABEL: L#PPA1_func1_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 1 = STACKPROTECT is enabled
+
+; CHECK-LABEL: L#PPA1_func2_64_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 1 = STACKPROTECT is enabled
+
+; CHECK-LABEL: L#PPA1_func3_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 1 = STACKPROTECT is enabled
+
+; CHECK-LABEL: L#PPA1_func4_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 1 = STACKPROTECT is enabled
+
+; CHECK-LABEL: L#PPA1_func5_0 DS 0H
+; CHECK:                    * PPA1 Flags 2
+; CHECK-NOT:                * PPA1 Flags 3
+; CHECK:                    *   Bit 3: 0 = STACKPROTECT is not enabled

>From 03eca124e2b7b0c899f4ca01a8d662b9ef8b585a Mon Sep 17 00:00:00 2001
From: Jian Su <[email protected]>
Date: Thu, 25 Jun 2026 20:06:52 +0000
Subject: [PATCH 2/3] Disable value global for option -mstack-protector-guard=
 on z/OS.

---
 clang/lib/Driver/ToolChains/Clang.cpp     | 6 ++++++
 clang/test/Driver/stack-protector-guard.c | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 418d540895681..b3bd5ca3463c2 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3524,6 +3524,12 @@ static void RenderSSPOptions(const Driver &D, const 
ToolChain &TC,
         !EffectiveTriple.isSystemZ())
       D.Diag(diag::err_drv_unsupported_opt_for_target)
           << A->getAsString(Args) << TripleStr;
+    // z/OS only supports the tls mode.
+    if (EffectiveTriple.isOSzOS() && GuardValue != "tls") {
+      D.Diag(diag::err_drv_invalid_value_with_suggestion)
+          << A->getOption().getName() << GuardValue << "tls";
+      return;
+    }
     if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() ||
          EffectiveTriple.isThumb() || EffectiveTriple.isSystemZ()) &&
         GuardValue != "tls" && GuardValue != "global") {
diff --git a/clang/test/Driver/stack-protector-guard.c 
b/clang/test/Driver/stack-protector-guard.c
index 46e09d6581867..971b042dd4f2e 100644
--- a/clang/test/Driver/stack-protector-guard.c
+++ b/clang/test/Driver/stack-protector-guard.c
@@ -178,3 +178,11 @@
 // 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'
+
+// RUN: %clang -### -target s390x-ibm-zos -mstack-protector-guard=tls %s 2>&1 
| \
+// RUN:  FileCheck -check-prefix=CHECK_TLS_ZOS %s
+// CHECK_TLS_ZOS: "-cc1" {{.*}}"-mstack-protector-guard=tls"
+
+// RUN: not %clang -### -target s390x-ibm-zos -mstack-protector-guard=global 
%s 2>&1 | \
+// RUN:  FileCheck -check-prefix=INVALID_GLOBAL_ZOS %s
+// INVALID_GLOBAL_ZOS: invalid value 'global' in 'mstack-protector-guard=', 
expected one of: tls

>From 6a9c1e604f9ddc22248c69ab45304d1eeece4345 Mon Sep 17 00:00:00 2001
From: Jian Su <[email protected]>
Date: Fri, 26 Jun 2026 12:44:30 +0000
Subject: [PATCH 3/3] Fix format.

---
 llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp 
b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 2662bb905d96d..4883171435549 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -1815,7 +1815,8 @@ void 
SystemZInstrInfo::expandStackGuardPseudo(MachineInstr &MI,
   if (GuardType.empty() || (GuardType == "tls")) {
     if (STI.isTargetzOS()) {
       enum { OFFSET_CEELAA_STACK_GUARD = 0x98 };
-      BuildMI(MBB, MI, DL, get(SystemZ::LOAD_LIBRARY_ANCHOR_AREA_ADDR), 
AddrReg);
+      BuildMI(MBB, MI, DL, get(SystemZ::LOAD_LIBRARY_ANCHOR_AREA_ADDR),
+              AddrReg);
       Offset = OFFSET_CEELAA_STACK_GUARD;
     } else {
       // Emit a load of the TLS block's address

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to