[PATCH] aarch64: simplify __libc_arm_za_disable failure path

Muhammad Kamran muhammad.kamran@arm.com
Tue Apr 21 13:08:04 GMT 2026


The failure tail of __libc_arm_za_disable only leads to
__libc_fatal, so it does not need to preserve call frame state.

Remove the PAC prologue, frame setup, saved cntd value, stack
stores, and associated CFI directives from the fatal path, leaving
only the required SME state shutdown and fatal call.

Add tst-sme-za-disable-fail to exercise the abort path by providing
a TPIDR2 block with non-zero reserved bytes and checking that the
process terminates with SIGABRT and the expected fatal message.
---
 sysdeps/aarch64/Makefile                  |  2 +
 sysdeps/aarch64/__arm_za_disable.S        | 10 ----
 sysdeps/aarch64/tst-sme-helper.h          | 12 ++--
 sysdeps/aarch64/tst-sme-za-disable-fail.c | 67 +++++++++++++++++++++++
 4 files changed, 75 insertions(+), 16 deletions(-)
 create mode 100644 sysdeps/aarch64/tst-sme-za-disable-fail.c

diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile
index d6c5cc96ca..57132179fd 100644
--- a/sysdeps/aarch64/Makefile
+++ b/sysdeps/aarch64/Makefile
@@ -82,9 +82,11 @@ tests-internal += \
   tst-sme-clone3 \
   tst-sme-fork \
   tst-sme-vfork \
+  tst-sme-za-disable-fail \
   # tests-internal
 
 $(objpfx)tst-sme-clone3: $(objpfx)clone3.o $(objpfx)__arm_za_disable.o
+$(objpfx)tst-sme-za-disable-fail: $(objpfx)__arm_za_disable.o
 endif
 
 ifeq ($(subdir),malloc)
diff --git a/sysdeps/aarch64/__arm_za_disable.S b/sysdeps/aarch64/__arm_za_disable.S
index c9663e3bcb..f360c8c77b 100644
--- a/sysdeps/aarch64/__arm_za_disable.S
+++ b/sysdeps/aarch64/__arm_za_disable.S
@@ -88,16 +88,6 @@ L(save_loop):
 L(end):
 	ret
 L(fail):
-	paciasp
-	cfi_negate_ra_state
-	stp	x29, x30, [sp, -32]!
-	cfi_adjust_cfa_offset (32)
-	cfi_rel_offset (x29, 0)
-	cfi_rel_offset (x30, 8)
-	mov	x29, sp
-	.inst	0x04e0e3f0  /* cntd	x16  */
-	str	x16, [sp, 16]
-	cfi_rel_offset (46, 16)
 	.inst	0xd503467f  /* smstop  */
 	adrp	x0, L(msg)
 	add	x0, x0, :lo12:L(msg)
diff --git a/sysdeps/aarch64/tst-sme-helper.h b/sysdeps/aarch64/tst-sme-helper.h
index 2ae2cc2f47..66e016f0b8 100644
--- a/sysdeps/aarch64/tst-sme-helper.h
+++ b/sysdeps/aarch64/tst-sme-helper.h
@@ -23,7 +23,7 @@ struct blk {
 };
 
 /* Read SVCR to get SM (bit0) and ZA (bit1) state.  */
-static unsigned long
+static unsigned long __attribute__ ((unused))
 get_svcr (void)
 {
   register unsigned long x0 asm ("x0");
@@ -34,7 +34,7 @@ get_svcr (void)
 }
 
 /* Returns tpidr2.  */
-static void *
+static __attribute__ ((unused)) void *
 get_tpidr2 (void)
 {
   register unsigned long x0 asm ("x0");
@@ -45,7 +45,7 @@ get_tpidr2 (void)
 }
 
 /* Obtains current streaming SVE vector register size.  */
-static unsigned long
+static unsigned long __attribute__ ((unused))
 get_svl (void)
 {
   register unsigned long x0 asm ("x0");
@@ -56,7 +56,7 @@ get_svl (void)
 }
 
 /* PSTATE.ZA = 1, set ZA state to active.  */
-static void
+static void __attribute__ ((unused))
 start_za (void)
 {
   asm volatile (
@@ -64,7 +64,7 @@ start_za (void)
 }
 
 /* Load data into ZA byte by byte from p.  */
-static void __attribute__ ((noinline))
+static void __attribute__ ((noinline, unused))
 load_za (const void *buf, unsigned long svl)
 {
   register unsigned long x15 asm ("x15") = 0;
@@ -84,7 +84,7 @@ load_za (const void *buf, unsigned long svl)
 }
 
 /* Set tpidr2 to BLK.  */
-static void
+static void __attribute__ ((unused))
 set_tpidr2 (struct blk *blk)
 {
   register unsigned long x0 asm ("x0") = (unsigned long)blk;
diff --git a/sysdeps/aarch64/tst-sme-za-disable-fail.c b/sysdeps/aarch64/tst-sme-za-disable-fail.c
new file mode 100644
index 0000000000..d3a6bebaf9
--- /dev/null
+++ b/sysdeps/aarch64/tst-sme-za-disable-fail.c
@@ -0,0 +1,67 @@
+/* Test that __libc_arm_za_disable aborts on unknown TPIDR2 extensions.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/auxv.h>
+
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+#include "tst-sme-helper.h"
+
+extern void __libc_arm_za_disable (void);
+
+/* Required by __arm_za_disable.o and provided by the startup code
+   as a hidden symbol.  */
+uint64_t _dl_hwcap2;
+
+static struct blk blk = {
+  .za_save_buffer = NULL,
+  .num_za_save_slices = 0,
+  .__reserved = { 1, 0, 0, 0, 0, 0 },
+};
+
+static void
+do_abort (void *closure)
+{
+  start_za ();
+  set_tpidr2 (closure);
+  __libc_arm_za_disable ();
+}
+
+static int
+do_test (void)
+{
+  _dl_hwcap2 = getauxval (AT_HWCAP2);
+  if ((_dl_hwcap2 & HWCAP2_SME) == 0)
+    FAIL_UNSUPPORTED ("kernel or CPU does not support SME");
+
+  struct support_capture_subprocess result
+      = support_capture_subprocess (do_abort, &blk);
+  support_capture_subprocess_check (&result, "tst-sme-za-disable-fail",
+				    -SIGABRT, sc_allow_stderr);
+  TEST_COMPARE_STRING (result.err.buffer,
+		       "FATAL: __libc_arm_za_disable failed.\n");
+  support_capture_subprocess_free (&result);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.43.0



More information about the Libc-alpha mailing list