authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-11 16:50:48+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-30 13:44:53+01:00
loga12ce28224f475bd97dc92bc8314ffff60fd6dd2
treeb135e02c66ba8f7276817701f7d6468fe6eb0d8c
parent9901b9389ed963ff262d1ce4973029a570035f19
signaturelock-open Commit is signed but in an unrecognized format.

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 files changed, 15 insertions(+), 11 deletions(-)

lib/std/os/linux/x86.zig+15-11
......@@ -80,28 +80,32 @@ pub fn syscall6(
8080 arg5: usize,
8181 arg6: usize,
8282) usize {
83 // arg5/arg6 are passed via memory as we're out of registers if ebp is used as frame pointer, or
84 // if we're compiling with PIC. We push arg5/arg6 on the stack before changing ebp/esp as the
85 // compiler may reference arg5/arg6 as an offset relative to ebp/esp.
83 // arg6 can't be passed to asm in a register because ebp might be reserved as the frame pointer
84 // and there are no more GPRs available; so we'll need a memory operand for it. Adding that
85 // memory operand means that on PIC we might need a reference to the GOT, which in turn needs
86 // *its* own GPR, so we need to pass another arg in memory too! This is surprisingly hard to get
87 // right, because we can't touch esp or ebp until we're done with the memory input (as that
88 // input could be relative to esp or ebp).
89 const args56: [2]usize = .{ arg5, arg6 };
8690 return asm volatile (
87 \\ push %[arg5]
88 \\ push %[arg6]
89 \\ push %%edi
91 \\ push %[args56]
9092 \\ push %%ebp
91 \\ mov 12(%%esp), %%edi
92 \\ mov 8(%%esp), %%ebp
93 \\ mov 4(%%esp), %%ebp
94 \\ mov %%edi, 4(%%esp)
95 \\ // The saved %edi and %ebp are on the stack, and %ebp points to `args56`.
96 \\ // Prepare the last two args, syscall, then pop the saved %ebp and %edi.
97 \\ mov (%%ebp), %%edi
98 \\ mov 4(%%ebp), %%ebp
9399 \\ int $0x80
94100 \\ pop %%ebp
95101 \\ pop %%edi
96 \\ add $8, %%esp
97102 : [ret] "={eax}" (-> usize),
98103 : [number] "{eax}" (@intFromEnum(number)),
99104 [arg1] "{ebx}" (arg1),
100105 [arg2] "{ecx}" (arg2),
101106 [arg3] "{edx}" (arg3),
102107 [arg4] "{esi}" (arg4),
103 [arg5] "rm" (arg5),
104 [arg6] "rm" (arg6),
108 [args56] "rm" (&args56),
105109 : .{ .memory = true });
106110}
107111