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(...@@ -75,12 +75,15 @@ pub fn syscall4(
75 arg3: syscall_arg_t,75 arg3: syscall_arg_t,
76 arg4: syscall_arg_t,76 arg4: syscall_arg_t,
77) u32 {77) u32 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
78 return asm volatile (80 return asm volatile (
79 \\ syscall81 \\ syscall
80 \\ beq $a3, $zero, 1f82 \\ beq $a3, $zero, 1f
81 \\ subu $v0, $zero, $v083 \\ subu $v0, $zero, $v0
82 \\1:84 \\1:
83 : [ret] "={$2}" (-> u32),85 : [ret] "={$2}" (-> u32),
86 [r7_out] "={$7}" (r7_out),
84 : [number] "{$2}" (@backingInt(number)),87 : [number] "{$2}" (@backingInt(number)),
85 [arg1] "{$4}" (arg1),88 [arg1] "{$4}" (arg1),
86 [arg2] "{$5}" (arg2),89 [arg2] "{$5}" (arg2),
...@@ -100,6 +103,8 @@ pub fn syscall5(...@@ -100,6 +103,8 @@ pub fn syscall5(
100 arg4: syscall_arg_t,103 arg4: syscall_arg_t,
101 arg5: syscall_arg_t,104 arg5: syscall_arg_t,
102) u32 {105) u32 {
106 // $7 is both an input and a clobber.
107 var r7_out: syscall_arg_t = undefined;
103 return asm volatile (108 return asm volatile (
104 \\ subu $sp, $sp, 24109 \\ subu $sp, $sp, 24
105 \\ sw %[arg5], 16($sp)110 \\ sw %[arg5], 16($sp)
...@@ -109,6 +114,7 @@ pub fn syscall5(...@@ -109,6 +114,7 @@ pub fn syscall5(
109 \\ subu $v0, $zero, $v0114 \\ subu $v0, $zero, $v0
110 \\1:115 \\1:
111 : [ret] "={$2}" (-> u32),116 : [ret] "={$2}" (-> u32),
117 [r7_out] "={$7}" (r7_out),
112 : [number] "{$2}" (@backingInt(number)),118 : [number] "{$2}" (@backingInt(number)),
113 [arg1] "{$4}" (arg1),119 [arg1] "{$4}" (arg1),
114 [arg2] "{$5}" (arg2),120 [arg2] "{$5}" (arg2),
...@@ -127,6 +133,8 @@ pub fn syscall6(...@@ -127,6 +133,8 @@ pub fn syscall6(
127 arg5: syscall_arg_t,133 arg5: syscall_arg_t,
128 arg6: syscall_arg_t,134 arg6: syscall_arg_t,
129) u32 {135) u32 {
136 // $7 is both an input and a clobber.
137 var r7_out: syscall_arg_t = undefined;
130 return asm volatile (138 return asm volatile (
131 \\ subu $sp, $sp, 24139 \\ subu $sp, $sp, 24
132 \\ sw %[arg5], 16($sp)140 \\ sw %[arg5], 16($sp)
...@@ -137,6 +145,7 @@ pub fn syscall6(...@@ -137,6 +145,7 @@ pub fn syscall6(
137 \\ subu $v0, $zero, $v0145 \\ subu $v0, $zero, $v0
138 \\1:146 \\1:
139 : [ret] "={$2}" (-> u32),147 : [ret] "={$2}" (-> u32),
148 [r7_out] "={$7}" (r7_out),
140 : [number] "{$2}" (@backingInt(number)),149 : [number] "{$2}" (@backingInt(number)),
141 [arg1] "{$4}" (arg1),150 [arg1] "{$4}" (arg1),
142 [arg2] "{$5}" (arg2),151 [arg2] "{$5}" (arg2),
...@@ -157,6 +166,8 @@ pub fn syscall7(...@@ -157,6 +166,8 @@ pub fn syscall7(
157 arg6: syscall_arg_t,166 arg6: syscall_arg_t,
158 arg7: syscall_arg_t,167 arg7: syscall_arg_t,
159) u32 {168) u32 {
169 // $7 is both an input and a clobber.
170 var r7_out: syscall_arg_t = undefined;
160 return asm volatile (171 return asm volatile (
161 \\ subu $sp, $sp, 32172 \\ subu $sp, $sp, 32
162 \\ sw %[arg5], 16($sp)173 \\ sw %[arg5], 16($sp)
...@@ -168,6 +179,7 @@ pub fn syscall7(...@@ -168,6 +179,7 @@ pub fn syscall7(
168 \\ subu $v0, $zero, $v0179 \\ subu $v0, $zero, $v0
169 \\1:180 \\1:
170 : [ret] "={$2}" (-> u32),181 : [ret] "={$2}" (-> u32),
182 [r7_out] "={$7}" (r7_out),
171 : [number] "{$2}" (@backingInt(number)),183 : [number] "{$2}" (@backingInt(number)),
172 [arg1] "{$4}" (arg1),184 [arg1] "{$4}" (arg1),
173 [arg2] "{$5}" (arg2),185 [arg2] "{$5}" (arg2),
lib/std/os/linux/mips64.zig+9
...@@ -75,12 +75,15 @@ pub fn syscall4(...@@ -75,12 +75,15 @@ pub fn syscall4(
75 arg3: syscall_arg_t,75 arg3: syscall_arg_t,
76 arg4: syscall_arg_t,76 arg4: syscall_arg_t,
77) u64 {77) u64 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
78 return asm volatile (80 return asm volatile (
79 \\ syscall81 \\ syscall
80 \\ beq $a3, $zero, 1f82 \\ beq $a3, $zero, 1f
81 \\ dsubu $v0, $zero, $v083 \\ dsubu $v0, $zero, $v0
82 \\1:84 \\1:
83 : [ret] "={$2}" (-> u64),85 : [ret] "={$2}" (-> u64),
86 [r7_out] "={$7}" (r7_out),
84 : [number] "{$2}" (@backingInt(number)),87 : [number] "{$2}" (@backingInt(number)),
85 [arg1] "{$4}" (arg1),88 [arg1] "{$4}" (arg1),
86 [arg2] "{$5}" (arg2),89 [arg2] "{$5}" (arg2),
...@@ -97,12 +100,15 @@ pub fn syscall5(...@@ -97,12 +100,15 @@ pub fn syscall5(
97 arg4: syscall_arg_t,100 arg4: syscall_arg_t,
98 arg5: syscall_arg_t,101 arg5: syscall_arg_t,
99) u64 {102) u64 {
103 // $7 is both an input and a clobber.
104 var r7_out: syscall_arg_t = undefined;
100 return asm volatile (105 return asm volatile (
101 \\ syscall106 \\ syscall
102 \\ beq $a3, $zero, 1f107 \\ beq $a3, $zero, 1f
103 \\ dsubu $v0, $zero, $v0108 \\ dsubu $v0, $zero, $v0
104 \\1:109 \\1:
105 : [ret] "={$2}" (-> u64),110 : [ret] "={$2}" (-> u64),
111 [r7_out] "={$7}" (r7_out),
106 : [number] "{$2}" (@backingInt(number)),112 : [number] "{$2}" (@backingInt(number)),
107 [arg1] "{$4}" (arg1),113 [arg1] "{$4}" (arg1),
108 [arg2] "{$5}" (arg2),114 [arg2] "{$5}" (arg2),
...@@ -121,12 +127,15 @@ pub fn syscall6(...@@ -121,12 +127,15 @@ pub fn syscall6(
121 arg5: syscall_arg_t,127 arg5: syscall_arg_t,
122 arg6: syscall_arg_t,128 arg6: syscall_arg_t,
123) u64 {129) u64 {
130 // $7 is both an input and a clobber.
131 var r7_out: syscall_arg_t = undefined;
124 return asm volatile (132 return asm volatile (
125 \\ syscall133 \\ syscall
126 \\ beq $a3, $zero, 1f134 \\ beq $a3, $zero, 1f
127 \\ dsubu $v0, $zero, $v0135 \\ dsubu $v0, $zero, $v0
128 \\1:136 \\1:
129 : [ret] "={$2}" (-> u64),137 : [ret] "={$2}" (-> u64),
138 [r7_out] "={$7}" (r7_out),
130 : [number] "{$2}" (@backingInt(number)),139 : [number] "{$2}" (@backingInt(number)),
131 [arg1] "{$4}" (arg1),140 [arg1] "{$4}" (arg1),
132 [arg2] "{$5}" (arg2),141 [arg2] "{$5}" (arg2),
lib/std/os/linux/mipsn32.zig+9
...@@ -75,12 +75,15 @@ pub fn syscall4(...@@ -75,12 +75,15 @@ pub fn syscall4(
75 arg3: syscall_arg_t,75 arg3: syscall_arg_t,
76 arg4: syscall_arg_t,76 arg4: syscall_arg_t,
77) u32 {77) u32 {
78 // $7 is both an input and a clobber.
79 var r7_out: syscall_arg_t = undefined;
78 return asm volatile (80 return asm volatile (
79 \\ syscall81 \\ syscall
80 \\ beq $a3, $zero, 1f82 \\ beq $a3, $zero, 1f
81 \\ subu $v0, $zero, $v083 \\ subu $v0, $zero, $v0
82 \\1:84 \\1:
83 : [ret] "={$2}" (-> u32),85 : [ret] "={$2}" (-> u32),
86 [r7_out] "={$7}" (r7_out),
84 : [number] "{$2}" (@backingInt(number)),87 : [number] "{$2}" (@backingInt(number)),
85 [arg1] "{$4}" (arg1),88 [arg1] "{$4}" (arg1),
86 [arg2] "{$5}" (arg2),89 [arg2] "{$5}" (arg2),
...@@ -97,12 +100,15 @@ pub fn syscall5(...@@ -97,12 +100,15 @@ pub fn syscall5(
97 arg4: syscall_arg_t,100 arg4: syscall_arg_t,
98 arg5: syscall_arg_t,101 arg5: syscall_arg_t,
99) u32 {102) u32 {
103 // $7 is both an input and a clobber.
104 var r7_out: syscall_arg_t = undefined;
100 return asm volatile (105 return asm volatile (
101 \\ syscall106 \\ syscall
102 \\ beq $a3, $zero, 1f107 \\ beq $a3, $zero, 1f
103 \\ subu $v0, $zero, $v0108 \\ subu $v0, $zero, $v0
104 \\1:109 \\1:
105 : [ret] "={$2}" (-> u32),110 : [ret] "={$2}" (-> u32),
111 [r7_out] "={$7}" (r7_out),
106 : [number] "{$2}" (@backingInt(number)),112 : [number] "{$2}" (@backingInt(number)),
107 [arg1] "{$4}" (arg1),113 [arg1] "{$4}" (arg1),
108 [arg2] "{$5}" (arg2),114 [arg2] "{$5}" (arg2),
...@@ -121,12 +127,15 @@ pub fn syscall6(...@@ -121,12 +127,15 @@ pub fn syscall6(
121 arg5: syscall_arg_t,127 arg5: syscall_arg_t,
122 arg6: syscall_arg_t,128 arg6: syscall_arg_t,
123) u32 {129) u32 {
130 // $7 is both an input and a clobber.
131 var r7_out: syscall_arg_t = undefined;
124 return asm volatile (132 return asm volatile (
125 \\ syscall133 \\ syscall
126 \\ beq $a3, $zero, 1f134 \\ beq $a3, $zero, 1f
127 \\ subu $v0, $zero, $v0135 \\ subu $v0, $zero, $v0
128 \\1:136 \\1:
129 : [ret] "={$2}" (-> u32),137 : [ret] "={$2}" (-> u32),
138 [r7_out] "={$7}" (r7_out),
130 : [number] "{$2}" (@backingInt(number)),139 : [number] "{$2}" (@backingInt(number)),
131 [arg1] "{$4}" (arg1),140 [arg1] "{$4}" (arg1),
132 [arg2] "{$5}" (arg2),141 [arg2] "{$5}" (arg2),