Commit a12ce28224

mlugg <mlugg@mlugg.co.uk>
2025-09-11 17:50:48
std: fix os.linux.x86.syscall6
It was possible for `arg6` to be passed as an operand relative to esp. In that case, the `push` at the top clobbered esp and hence made the reference to arg6 invalid. This was manifesting in this branch as broken stack traces on x86-linux due to an `mmap2` syscall accidentally passing the page offset as non-zero! This commit fixes a bug introduced in cb0e6d8aa.
1 parent 9901b93
Changed files (1)
lib
std
os
linux
lib/std/os/linux/x86.zig
@@ -80,28 +80,32 @@ pub fn syscall6(
     arg5: usize,
     arg6: usize,
 ) usize {
-    // arg5/arg6 are passed via memory as we're out of registers if ebp is used as frame pointer, or
-    // if we're compiling with PIC. We push arg5/arg6 on the stack before changing ebp/esp as the
-    // compiler may reference arg5/arg6 as an offset relative to ebp/esp.
+    // arg6 can't be passed to asm in a register because ebp might be reserved as the frame pointer
+    // and there are no more GPRs available; so we'll need a memory operand for it. Adding that
+    // memory operand means that on PIC we might need a reference to the GOT, which in turn needs
+    // *its* own GPR, so we need to pass another arg in memory too! This is surprisingly hard to get
+    // right, because we can't touch esp or ebp until we're done with the memory input (as that
+    // input could be relative to esp or ebp).
+    const args56: [2]usize = .{ arg5, arg6 };
     return asm volatile (
-        \\ push %[arg5]
-        \\ push %[arg6]
-        \\ push %%edi
+        \\ push %[args56]
         \\ push %%ebp
-        \\ mov  12(%%esp), %%edi
-        \\ mov  8(%%esp), %%ebp
+        \\ mov 4(%%esp), %%ebp
+        \\ mov %%edi, 4(%%esp)
+        \\ // The saved %edi and %ebp are on the stack, and %ebp points to `args56`.
+        \\ // Prepare the last two args, syscall, then pop the saved %ebp and %edi.
+        \\ mov (%%ebp), %%edi
+        \\ mov 4(%%ebp), %%ebp
         \\ int  $0x80
         \\ pop  %%ebp
         \\ pop  %%edi
-        \\ add  $8, %%esp
         : [ret] "={eax}" (-> usize),
         : [number] "{eax}" (@intFromEnum(number)),
           [arg1] "{ebx}" (arg1),
           [arg2] "{ecx}" (arg2),
           [arg3] "{edx}" (arg3),
           [arg4] "{esi}" (arg4),
-          [arg5] "rm" (arg5),
-          [arg6] "rm" (arg6),
+          [args56] "rm" (&args56),
         : .{ .memory = true });
 }