diff options
Diffstat (limited to 'lib/std/os/linux/x86.zig')
| -rw-r--r-- | lib/std/os/linux/x86.zig | 148 |
1 files changed, 15 insertions, 133 deletions
diff --git a/lib/std/os/linux/x86.zig b/lib/std/os/linux/x86.zig index 0ffe9c2956..c24ffcae6a 100644 --- a/lib/std/os/linux/x86.zig +++ b/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 }); } @@ -284,44 +288,6 @@ pub const timezone = extern struct { dsttime: i32, }; -pub const mcontext_t = extern struct { - gregs: [19]usize, - fpregs: [*]u8, - oldmask: usize, - cr2: usize, -}; - -pub const REG = struct { - pub const GS = 0; - pub const FS = 1; - pub const ES = 2; - pub const DS = 3; - pub const EDI = 4; - pub const ESI = 5; - pub const EBP = 6; - pub const ESP = 7; - pub const EBX = 8; - pub const EDX = 9; - pub const ECX = 10; - pub const EAX = 11; - pub const TRAPNO = 12; - pub const ERR = 13; - pub const EIP = 14; - pub const CS = 15; - pub const EFL = 16; - pub const UESP = 17; - pub const SS = 18; -}; - -pub const ucontext_t = extern struct { - flags: usize, - link: ?*ucontext_t, - stack: stack_t, - mcontext: mcontext_t, - sigmask: [1024 / @bitSizeOf(c_ulong)]c_ulong, // Currently a libc-compatible (1024-bit) sigmask - regspace: [64]u64, -}; - pub const Elf_Symndx = u32; pub const user_desc = extern struct { @@ -362,87 +328,3 @@ pub const SC = struct { pub const recvmmsg = 19; pub const sendmmsg = 20; }; - -fn gpRegisterOffset(comptime reg_index: comptime_int) usize { - return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index; -} - -noinline fn getContextReturnAddress() usize { - return @returnAddress(); -} - -pub fn getContextInternal() callconv(.naked) usize { - asm volatile ( - \\ movl $0, %[flags_offset:c](%%edx) - \\ movl $0, %[link_offset:c](%%edx) - \\ movl %%edi, %[edi_offset:c](%%edx) - \\ movl %%esi, %[esi_offset:c](%%edx) - \\ movl %%ebp, %[ebp_offset:c](%%edx) - \\ movl %%ebx, %[ebx_offset:c](%%edx) - \\ movl %%edx, %[edx_offset:c](%%edx) - \\ movl %%ecx, %[ecx_offset:c](%%edx) - \\ movl %%eax, %[eax_offset:c](%%edx) - \\ movl (%%esp), %%ecx - \\ movl %%ecx, %[eip_offset:c](%%edx) - \\ leal 4(%%esp), %%ecx - \\ movl %%ecx, %[esp_offset:c](%%edx) - \\ xorl %%ecx, %%ecx - \\ movw %%fs, %%cx - \\ movl %%ecx, %[fs_offset:c](%%edx) - \\ leal %[regspace_offset:c](%%edx), %%ecx - \\ movl %%ecx, %[fpregs_offset:c](%%edx) - \\ fnstenv (%%ecx) - \\ fldenv (%%ecx) - \\ pushl %%ebx - \\ pushl %%esi - \\ xorl %%ebx, %%ebx - \\ movl %[sigaltstack], %%eax - \\ leal %[stack_offset:c](%%edx), %%ecx - \\ int $0x80 - \\ testl %%eax, %%eax - \\ jnz 0f - \\ movl %[sigprocmask], %%eax - \\ xorl %%ecx, %%ecx - \\ leal %[sigmask_offset:c](%%edx), %%edx - \\ movl %[sigset_size], %%esi - \\ int $0x80 - \\0: - \\ popl %%esi - \\ popl %%ebx - \\ retl - : - : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")), - [link_offset] "i" (@offsetOf(ucontext_t, "link")), - [edi_offset] "i" (comptime gpRegisterOffset(REG.EDI)), - [esi_offset] "i" (comptime gpRegisterOffset(REG.ESI)), - [ebp_offset] "i" (comptime gpRegisterOffset(REG.EBP)), - [esp_offset] "i" (comptime gpRegisterOffset(REG.ESP)), - [ebx_offset] "i" (comptime gpRegisterOffset(REG.EBX)), - [edx_offset] "i" (comptime gpRegisterOffset(REG.EDX)), - [ecx_offset] "i" (comptime gpRegisterOffset(REG.ECX)), - [eax_offset] "i" (comptime gpRegisterOffset(REG.EAX)), - [eip_offset] "i" (comptime gpRegisterOffset(REG.EIP)), - [fs_offset] "i" (comptime gpRegisterOffset(REG.FS)), - [fpregs_offset] "i" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), - [regspace_offset] "i" (@offsetOf(ucontext_t, "regspace")), - [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)), - [stack_offset] "i" (@offsetOf(ucontext_t, "stack")), - [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)), - [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")), - [sigset_size] "i" (linux.NSIG / 8), - : .{ .cc = true, .memory = true, .eax = true, .ecx = true, .edx = true }); -} - -pub inline fn getcontext(context: *ucontext_t) usize { - // This method is used so that getContextInternal can control - // its prologue in order to read ESP from a constant offset. - // An aligned stack is not needed for getContextInternal. - var clobber_edx: usize = undefined; - return asm volatile ( - \\ calll %[getContextInternal:P] - : [_] "={eax}" (-> usize), - [_] "={edx}" (clobber_edx), - : [_] "{edx}" (context), - [getContextInternal] "X" (&getContextInternal), - : .{ .cc = true, .memory = true, .ecx = true }); -} |
