From 79807468e747bac056cfea4340065e49a5d97120 Mon Sep 17 00:00:00 2001 From: "taylor.fish" Date: Sat, 21 Jun 2025 21:47:58 -0700 Subject: [PATCH 1/2] Fix illegal behavior from syscalls on powerpc64le On powerpc64le Linux, the registers used for passing syscall parameters (r4-r8, as well as r0 for the syscall number) are volatile, or caller-saved. However, Zig's syscall wrappers for this architecture do not include all such registers in the list of clobbers, leading the compiler to assume these registers will maintain their values after the syscall completes. In practice, this resulted in a segfault when allocating memory with `std.heap.SmpAllocator`, which calls `std.os.linux.sched_getaffinity`. The third parameter to `sched_getaffinity` is a pointer to a `cpu_set_t` and is stored in register r5. After the syscall, the code attempts to access data in the `cpu_set_t`, but because the compiler doesn't realize the value of r5 may have changed, it uses r5 as the memory address, which in practice resulted in a memory access at address 0x8. This commit adds all volatile registers to the list of clobbers. --- lib/std/os/linux/powerpc64.zig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index b0a14ff3cb..1d4205626c 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -22,7 +22,7 @@ pub fn syscall0(number: SYS) usize { \\ 1: : [ret] "={r3}" (-> usize), : [number] "{r0}" (@intFromEnum(number)), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -35,7 +35,7 @@ pub fn syscall1(number: SYS, arg1: usize) usize { : [ret] "={r3}" (-> usize), : [number] "{r0}" (@intFromEnum(number)), [arg1] "{r3}" (arg1), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -49,7 +49,7 @@ pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { : [number] "{r0}" (@intFromEnum(number)), [arg1] "{r3}" (arg1), [arg2] "{r4}" (arg2), - : "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -64,7 +64,7 @@ pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { [arg1] "{r3}" (arg1), [arg2] "{r4}" (arg2), [arg3] "{r5}" (arg3), - : "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -80,7 +80,7 @@ pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) [arg2] "{r4}" (arg2), [arg3] "{r5}" (arg3), [arg4] "{r6}" (arg4), - : "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -97,7 +97,7 @@ pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, [arg3] "{r5}" (arg3), [arg4] "{r6}" (arg4), [arg5] "{r7}" (arg5), - : "memory", "cr0", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -123,7 +123,7 @@ pub fn syscall6( [arg4] "{r6}" (arg4), [arg5] "{r7}" (arg5), [arg6] "{r8}" (arg6), - : "memory", "cr0", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } From 95b638f613406c6bd609c7addd666dbe1758486a Mon Sep 17 00:00:00 2001 From: "taylor.fish" Date: Sun, 22 Jun 2025 16:36:44 -0700 Subject: [PATCH 2/2] Update 32-bit PowerPC syscall functions musl and glibc both specify r0 as an output register because its value may be overwritten by system calls. As with the updates for 64-bit PowerPC in the previous commit, this commit brings Zig's syscall functions for 32-bit PowerPC in line with musl and glibc by adding r0 to the list of clobbers. (Listing r0 as both an input and a clobber is as close as we can get to musl, which declares it as a "+r" read-write output, since Zig doesn't support multiple outputs or the "+" specifier.) --- lib/std/os/linux/powerpc.zig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 450cb27c7e..9ca6119219 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -22,7 +22,7 @@ pub fn syscall0(number: SYS) usize { \\ 1: : [ret] "={r3}" (-> usize), : [number] "{r0}" (@intFromEnum(number)), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -35,7 +35,7 @@ pub fn syscall1(number: SYS, arg1: usize) usize { : [ret] "={r3}" (-> usize), : [number] "{r0}" (@intFromEnum(number)), [arg1] "{r3}" (arg1), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -49,7 +49,7 @@ pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { : [number] "{r0}" (@intFromEnum(number)), [arg1] "{r3}" (arg1), [arg2] "{r4}" (arg2), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -64,7 +64,7 @@ pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { [arg1] "{r3}" (arg1), [arg2] "{r4}" (arg2), [arg3] "{r5}" (arg3), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -80,7 +80,7 @@ pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) [arg2] "{r4}" (arg2), [arg3] "{r5}" (arg3), [arg4] "{r6}" (arg4), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -97,7 +97,7 @@ pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, [arg3] "{r5}" (arg3), [arg4] "{r6}" (arg4), [arg5] "{r7}" (arg5), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); } @@ -123,7 +123,7 @@ pub fn syscall6( [arg4] "{r6}" (arg4), [arg5] "{r7}" (arg5), [arg6] "{r8}" (arg6), - : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + : "memory", "cr0", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" ); }