aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os/linux/x86.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/os/linux/x86.zig')
-rw-r--r--lib/std/os/linux/x86.zig148
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 });
-}