Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fiber/src/stackswitch/x86.rs
3067 views
1
// A WORD OF CAUTION
2
//
3
// This entire file basically needs to be kept in sync with itself. It's not
4
// really possible to modify just one bit of this file without understanding
5
// all the other bits. Documentation tries to reference various bits here and
6
// there but try to make sure to read over everything before tweaking things!
7
//
8
// This file is modeled after x86_64.rs and comments are not copied over. For
9
// reference be sure to review the other file. Note that the pointer size is
10
// different so the reserved space at the top of the stack is 8 bytes, not 16
11
// bytes. Still two pointers though.
12
13
use core::arch::naked_asm;
14
15
#[inline(never)] // FIXME(rust-lang/rust#148307)
16
pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) {
17
unsafe { wasmtime_fiber_switch_(top_of_stack) }
18
}
19
20
#[unsafe(naked)]
21
unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8) {
22
naked_asm!(
23
"
24
// Load our stack-to-use
25
mov eax, 0x4[esp]
26
mov ecx, -0x8[eax]
27
28
// Save callee-saved registers
29
push ebp
30
push ebx
31
push esi
32
push edi
33
34
// Save our current stack and jump to the stack-to-use
35
mov -0x8[eax], esp
36
mov esp, ecx
37
38
// Restore callee-saved registers
39
pop edi
40
pop esi
41
pop ebx
42
pop ebp
43
ret
44
",
45
)
46
}
47
48
pub(crate) unsafe fn wasmtime_fiber_init(
49
top_of_stack: *mut u8,
50
entry_point: extern "C" fn(*mut u8, *mut u8),
51
entry_arg0: *mut u8,
52
) {
53
// Our stack from top-to-bottom looks like:
54
//
55
// * 8 bytes of reserved space per unix.rs (two-pointers space)
56
// * 8 bytes of arguments (two arguments wasmtime_fiber_start forwards)
57
// * 4 bytes of return address
58
// * 16 bytes of saved registers
59
//
60
// Note that after the return address the stack is conveniently 16-byte
61
// aligned as required, so we just leave the arguments on the stack in
62
// `wasmtime_fiber_start` and immediately do the call.
63
#[repr(C)]
64
#[derive(Default)]
65
struct InitialStack {
66
// state that will get resumed into from a `wasmtime_fiber_switch`
67
// starting up this fiber.
68
edi: *mut u8,
69
esi: *mut u8,
70
ebx: *mut u8,
71
ebp: *mut u8,
72
return_address: *mut u8,
73
74
// two arguments to `entry_point`
75
arg1: *mut u8,
76
arg2: *mut u8,
77
78
// unix.rs reserved space
79
last_sp: *mut u8,
80
run_result: *mut u8,
81
}
82
83
unsafe {
84
let initial_stack = top_of_stack.cast::<InitialStack>().sub(1);
85
initial_stack.write(InitialStack {
86
ebp: entry_point as *mut u8,
87
return_address: wasmtime_fiber_start as *mut u8,
88
arg1: entry_arg0,
89
arg2: top_of_stack,
90
last_sp: initial_stack.cast(),
91
..InitialStack::default()
92
});
93
}
94
}
95
96
#[unsafe(naked)]
97
unsafe extern "C" fn wasmtime_fiber_start() -> ! {
98
naked_asm!(
99
"
100
.cfi_startproc simple
101
.cfi_def_cfa_offset 0
102
.cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \
103
5, /* the byte length of this expression */ \
104
0x74, 0x08, /* DW_OP_breg4 (%esp) + 8 */ \
105
0x06, /* DW_OP_deref */ \
106
0x23, 0x14 /* DW_OP_plus_uconst 0x14 */
107
108
.cfi_rel_offset eip, -4
109
.cfi_rel_offset ebp, -8
110
.cfi_rel_offset ebx, -12
111
.cfi_rel_offset esi, -16
112
.cfi_rel_offset edi, -20
113
114
// Our arguments and stack alignment are all prepped by
115
// `wasmtime_fiber_init`.
116
call ebp
117
ud2
118
.cfi_endproc
119
",
120
);
121
}
122
123