>From 0493ed31c748f9b3725c62048a164419a11517c7 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Sun, 4 Oct 2026 15:04:29 +0000 Subject: [PATCH v2] aarch64: workaround for syscalls with sve SVE registers z0..z31 overlap with the base isa registers d0..d31 (bottom 64bits) and q0..q31 (bottom 128bits). SVE also has an ffr and p0..p15 predicate registers. arm64 linux syscalls preserve q0..q31 but not the top bits of z0..z31 (if they are >128bits) nor ffr nor p0..p15. the c call abi requires preserving d8..d15. so the syscall inline asm requires sve z0..z31, p0..p15 and ffr clobbers, but then d8..d15 is spilled at every syscall call site defeating the purpose of inlining. unfortunately there is no inline asm syntax for specifying clobbers for z0..z31 top bits only. the lack of sve clobbers affect clang, it uses p regs around syscalls. so use extern syscalls as a workaround. adding noinline is not enough due to inter-procedural optimizations and gives bigger code. using c code for the syscalls is not lto safe within libc.so. (for lto libc.a the workaround would be required even if musl is built without sve as user might use it). building musl with sve is not recommended for now (it does extra reg shuffling at syscalls). auto disabling sve is hard to do portably. with gcc-16.1.0 -march=armv8-a+sve, libc.so .text increases by 3469 and there are 486 new refs to __syscall[0-6] across *.lo https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128010 https://www.kernel.org/doc/html/latest/arch/arm64/sve.html#system-call-behaviour https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#simd-and-floating-point-registers --- --- v2: - use extern __syscall*.S - reword commit msg - gcc upstream bug - tested with libc-test + qemu-user arch/aarch64/syscall_arch.h | 11 +++++++++++ src/internal/__syscall0.c | 0 src/internal/__syscall1.c | 0 src/internal/__syscall2.c | 0 src/internal/__syscall3.c | 0 src/internal/__syscall4.c | 0 src/internal/__syscall5.c | 0 src/internal/__syscall6.c | 0 src/internal/aarch64/__syscall0.S | 8 ++++++++ src/internal/aarch64/__syscall1.S | 9 +++++++++ src/internal/aarch64/__syscall2.S | 10 ++++++++++ src/internal/aarch64/__syscall3.S | 11 +++++++++++ src/internal/aarch64/__syscall4.S | 12 ++++++++++++ src/internal/aarch64/__syscall5.S | 13 +++++++++++++ src/internal/aarch64/__syscall6.S | 14 ++++++++++++++ 15 files changed, 88 insertions(+) create mode 100644 src/internal/__syscall0.c create mode 100644 src/internal/__syscall1.c create mode 100644 src/internal/__syscall2.c create mode 100644 src/internal/__syscall3.c create mode 100644 src/internal/__syscall4.c create mode 100644 src/internal/__syscall5.c create mode 100644 src/internal/__syscall6.c create mode 100644 src/internal/aarch64/__syscall0.S create mode 100644 src/internal/aarch64/__syscall1.S create mode 100644 src/internal/aarch64/__syscall2.S create mode 100644 src/internal/aarch64/__syscall3.S create mode 100644 src/internal/aarch64/__syscall4.S create mode 100644 src/internal/aarch64/__syscall5.S create mode 100644 src/internal/aarch64/__syscall6.S diff --git a/arch/aarch64/syscall_arch.h b/arch/aarch64/syscall_arch.h index 504983aa..33508456 100644 --- a/arch/aarch64/syscall_arch.h +++ b/arch/aarch64/syscall_arch.h @@ -1,6 +1,16 @@ #define __SYSCALL_LL_E(x) (x) #define __SYSCALL_LL_O(x) (x) +#if __ARM_FEATURE_SVE +/* workaround for no clobber syntax for z reg top bits */ +long __syscall0(long n); +long __syscall1(long n, long a); +long __syscall2(long n, long a, long b); +long __syscall3(long n, long a, long b, long c); +long __syscall4(long n, long a, long b, long c, long d); +long __syscall5(long n, long a, long b, long c, long d, long e); +long __syscall6(long n, long a, long b, long c, long d, long e, long f); +#else #define __asm_syscall(...) do { \ __asm__ __volatile__ ( "svc 0" \ : "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \ @@ -70,6 +80,7 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo register long x5 __asm__("x5") = f; __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)); } +#endif #define VDSO_USEFUL #define VDSO_CGT_SYM "__kernel_clock_gettime" diff --git a/src/internal/__syscall0.c b/src/internal/__syscall0.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall1.c b/src/internal/__syscall1.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall2.c b/src/internal/__syscall2.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall3.c b/src/internal/__syscall3.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall4.c b/src/internal/__syscall4.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall5.c b/src/internal/__syscall5.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/__syscall6.c b/src/internal/__syscall6.c new file mode 100644 index 00000000..e69de29b diff --git a/src/internal/aarch64/__syscall0.S b/src/internal/aarch64/__syscall0.S new file mode 100644 index 00000000..38e24baf --- /dev/null +++ b/src/internal/aarch64/__syscall0.S @@ -0,0 +1,8 @@ +#if __ARM_FEATURE_SVE +.global __syscall0 +.type __syscall0,%function +__syscall0: + mov x8, x0 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall1.S b/src/internal/aarch64/__syscall1.S new file mode 100644 index 00000000..a754c3a5 --- /dev/null +++ b/src/internal/aarch64/__syscall1.S @@ -0,0 +1,9 @@ +#if __ARM_FEATURE_SVE +.global __syscall1 +.type __syscall1,%function +__syscall1: + mov x8, x0 + mov x0, x1 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall2.S b/src/internal/aarch64/__syscall2.S new file mode 100644 index 00000000..f9c2fcac --- /dev/null +++ b/src/internal/aarch64/__syscall2.S @@ -0,0 +1,10 @@ +#if __ARM_FEATURE_SVE +.global __syscall2 +.type __syscall2,%function +__syscall2: + mov x8, x0 + mov x0, x1 + mov x1, x2 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall3.S b/src/internal/aarch64/__syscall3.S new file mode 100644 index 00000000..dc8d325c --- /dev/null +++ b/src/internal/aarch64/__syscall3.S @@ -0,0 +1,11 @@ +#if __ARM_FEATURE_SVE +.global __syscall3 +.type __syscall3,%function +__syscall3: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall4.S b/src/internal/aarch64/__syscall4.S new file mode 100644 index 00000000..5cda5944 --- /dev/null +++ b/src/internal/aarch64/__syscall4.S @@ -0,0 +1,12 @@ +#if __ARM_FEATURE_SVE +.global __syscall4 +.type __syscall4,%function +__syscall4: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall5.S b/src/internal/aarch64/__syscall5.S new file mode 100644 index 00000000..40f11e63 --- /dev/null +++ b/src/internal/aarch64/__syscall5.S @@ -0,0 +1,13 @@ +#if __ARM_FEATURE_SVE +.global __syscall5 +.type __syscall5,%function +__syscall5: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + svc 0 + ret +#endif diff --git a/src/internal/aarch64/__syscall6.S b/src/internal/aarch64/__syscall6.S new file mode 100644 index 00000000..7d5801a0 --- /dev/null +++ b/src/internal/aarch64/__syscall6.S @@ -0,0 +1,14 @@ +#if __ARM_FEATURE_SVE +.global __syscall6 +.type __syscall6,%function +__syscall6: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + svc 0 + ret +#endif -- 2.52.0