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