authorgravatar for gg@condado.devGeyslan Gregório <gg@condado.dev> 2026-10-14 20:53:01-03:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-15 20:13:17+02:00
logd3b1f18b06e81d1ddf163820c1d0de21a1c46521
tree0291f152cbafc1d0b430b9bc32fe41bcdc9ee74d
parentb3e2902e1d892204f727083d02937320fbb04e39
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

std.os.linux: declare $a3 as an output of mips syscall4 and up

On MIPS, $a3 ($7) carries the fourth argument [1] and returns the kernel's error flag [2]. The kernel writes the flag on every return, success included [3]. syscall4 and up declared $7 an input only, so the compiler assumed it still held the argument after the syscall. In release builds, a pointer passed as the fourth argument then reads back as the flag, 0 on success, and using it faults at address 0. Commit 5b29b4ffa6 ("Fix MIPS inline assembly clobbers") took $7 out of the clobbers, since an input cannot be one, but never made it an output. Add that output, as alpha.zig does for its argument registers [4] and musl does with "+r" [5]. $7 stays out of the clobbers, because a register that is input, output and clobber at once can miscompile (#35724). [1] - https://refspecs.linuxfoundation.org/elf/mipsabi.pdf#page=24 [2] - https://man7.org/linux/man-pages/man2/syscall.2.html [3] - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/kernel/scall32-o32.S?h=v7.1#n112 [4] - https://codeberg.org/ziglang/zig/src/commit/d8938120130dbe48ee8764b502b18c6224ab9340/lib/std/os/linux/alpha.zig#L38-L46 [5] - https://git.musl-libc.org/cgit/musl/tree/arch/mips/syscall_arch.h?h=v1.2.6#n81 closes #37247

3 files changed, 30 insertions(+), 0 deletions(-)

lib/std/os/linux/mips.zig+12
......@@ -75,12 +75,15 @@ pub fn syscall4(
7575 arg3: syscall_arg_t,
7676 arg4: syscall_arg_t,
7777) u32 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
7880 return asm volatile (
7981 \\ syscall
8082 \\ beq $a3, $zero, 1f
8183 \\ subu $v0, $zero, $v0
8284 \\1:
8385 : [ret] "={$2}" (-> u32),
86 [r7_out] "={$7}" (r7_out),
8487 : [number] "{$2}" (@backingInt(number)),
8588 [arg1] "{$4}" (arg1),
8689 [arg2] "{$5}" (arg2),
......@@ -100,6 +103,8 @@ pub fn syscall5(
100103 arg4: syscall_arg_t,
101104 arg5: syscall_arg_t,
102105) u32 {
106 // $7 is both an input and a clobber.
107 var r7_out: syscall_arg_t = undefined;
103108 return asm volatile (
104109 \\ subu $sp, $sp, 24
105110 \\ sw %[arg5], 16($sp)
......@@ -109,6 +114,7 @@ pub fn syscall5(
109114 \\ subu $v0, $zero, $v0
110115 \\1:
111116 : [ret] "={$2}" (-> u32),
117 [r7_out] "={$7}" (r7_out),
112118 : [number] "{$2}" (@backingInt(number)),
113119 [arg1] "{$4}" (arg1),
114120 [arg2] "{$5}" (arg2),
......@@ -127,6 +133,8 @@ pub fn syscall6(
127133 arg5: syscall_arg_t,
128134 arg6: syscall_arg_t,
129135) u32 {
136 // $7 is both an input and a clobber.
137 var r7_out: syscall_arg_t = undefined;
130138 return asm volatile (
131139 \\ subu $sp, $sp, 24
132140 \\ sw %[arg5], 16($sp)
......@@ -137,6 +145,7 @@ pub fn syscall6(
137145 \\ subu $v0, $zero, $v0
138146 \\1:
139147 : [ret] "={$2}" (-> u32),
148 [r7_out] "={$7}" (r7_out),
140149 : [number] "{$2}" (@backingInt(number)),
141150 [arg1] "{$4}" (arg1),
142151 [arg2] "{$5}" (arg2),
......@@ -157,6 +166,8 @@ pub fn syscall7(
157166 arg6: syscall_arg_t,
158167 arg7: syscall_arg_t,
159168) u32 {
169 // $7 is both an input and a clobber.
170 var r7_out: syscall_arg_t = undefined;
160171 return asm volatile (
161172 \\ subu $sp, $sp, 32
162173 \\ sw %[arg5], 16($sp)
......@@ -168,6 +179,7 @@ pub fn syscall7(
168179 \\ subu $v0, $zero, $v0
169180 \\1:
170181 : [ret] "={$2}" (-> u32),
182 [r7_out] "={$7}" (r7_out),
171183 : [number] "{$2}" (@backingInt(number)),
172184 [arg1] "{$4}" (arg1),
173185 [arg2] "{$5}" (arg2),
lib/std/os/linux/mips64.zig+9
......@@ -75,12 +75,15 @@ pub fn syscall4(
7575 arg3: syscall_arg_t,
7676 arg4: syscall_arg_t,
7777) u64 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
7880 return asm volatile (
7981 \\ syscall
8082 \\ beq $a3, $zero, 1f
8183 \\ dsubu $v0, $zero, $v0
8284 \\1:
8385 : [ret] "={$2}" (-> u64),
86 [r7_out] "={$7}" (r7_out),
8487 : [number] "{$2}" (@backingInt(number)),
8588 [arg1] "{$4}" (arg1),
8689 [arg2] "{$5}" (arg2),
......@@ -97,12 +100,15 @@ pub fn syscall5(
97100 arg4: syscall_arg_t,
98101 arg5: syscall_arg_t,
99102) u64 {
103 // $7 is both an input and a clobber.
104 var r7_out: syscall_arg_t = undefined;
100105 return asm volatile (
101106 \\ syscall
102107 \\ beq $a3, $zero, 1f
103108 \\ dsubu $v0, $zero, $v0
104109 \\1:
105110 : [ret] "={$2}" (-> u64),
111 [r7_out] "={$7}" (r7_out),
106112 : [number] "{$2}" (@backingInt(number)),
107113 [arg1] "{$4}" (arg1),
108114 [arg2] "{$5}" (arg2),
......@@ -121,12 +127,15 @@ pub fn syscall6(
121127 arg5: syscall_arg_t,
122128 arg6: syscall_arg_t,
123129) u64 {
130 // $7 is both an input and a clobber.
131 var r7_out: syscall_arg_t = undefined;
124132 return asm volatile (
125133 \\ syscall
126134 \\ beq $a3, $zero, 1f
127135 \\ dsubu $v0, $zero, $v0
128136 \\1:
129137 : [ret] "={$2}" (-> u64),
138 [r7_out] "={$7}" (r7_out),
130139 : [number] "{$2}" (@backingInt(number)),
131140 [arg1] "{$4}" (arg1),
132141 [arg2] "{$5}" (arg2),
lib/std/os/linux/mipsn32.zig+9
......@@ -75,12 +75,15 @@ pub fn syscall4(
7575 arg3: syscall_arg_t,
7676 arg4: syscall_arg_t,
7777) u32 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
7880 return asm volatile (
7981 \\ syscall
8082 \\ beq $a3, $zero, 1f
8183 \\ subu $v0, $zero, $v0
8284 \\1:
8385 : [ret] "={$2}" (-> u32),
86 [r7_out] "={$7}" (r7_out),
8487 : [number] "{$2}" (@backingInt(number)),
8588 [arg1] "{$4}" (arg1),
8689 [arg2] "{$5}" (arg2),
......@@ -97,12 +100,15 @@ pub fn syscall5(
97100 arg4: syscall_arg_t,
98101 arg5: syscall_arg_t,
99102) u32 {
103 // $7 is both an input and a clobber.
104 var r7_out: syscall_arg_t = undefined;
100105 return asm volatile (
101106 \\ syscall
102107 \\ beq $a3, $zero, 1f
103108 \\ subu $v0, $zero, $v0
104109 \\1:
105110 : [ret] "={$2}" (-> u32),
111 [r7_out] "={$7}" (r7_out),
106112 : [number] "{$2}" (@backingInt(number)),
107113 [arg1] "{$4}" (arg1),
108114 [arg2] "{$5}" (arg2),
......@@ -121,12 +127,15 @@ pub fn syscall6(
121127 arg5: syscall_arg_t,
122128 arg6: syscall_arg_t,
123129) u32 {
130 // $7 is both an input and a clobber.
131 var r7_out: syscall_arg_t = undefined;
124132 return asm volatile (
125133 \\ syscall
126134 \\ beq $a3, $zero, 1f
127135 \\ subu $v0, $zero, $v0
128136 \\1:
129137 : [ret] "={$2}" (-> u32),
138 [r7_out] "={$7}" (r7_out),
130139 : [number] "{$2}" (@backingInt(number)),
131140 [arg1] "{$4}" (arg1),
132141 [arg2] "{$5}" (arg2),