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 wasmtime_asm_macros::asm_func;
14 
15 // fn(top_of_stack: *mut u8)
16 asm_func!(
17     wasmtime_versioned_export_macros::versioned_stringify_ident!(wasmtime_fiber_switch),
18     "
19         // Load our stack-to-use
20         mov eax, 0x4[esp]
21         mov ecx, -0x8[eax]
22 
23         // Save callee-saved registers
24         push ebp
25         push ebx
26         push esi
27         push edi
28 
29         // Save our current stack and jump to the stack-to-use
30         mov -0x8[eax], esp
31         mov esp, ecx
32 
33         // Restore callee-saved registers
34         pop edi
35         pop esi
36         pop ebx
37         pop ebp
38         ret
39     ",
40 );
41 
42 // fn(
43 //    top_of_stack: *mut u8,
44 //    entry_point: extern fn(*mut u8, *mut u8),
45 //    entry_arg0: *mut u8,
46 // )
47 asm_func!(
48     wasmtime_versioned_export_macros::versioned_stringify_ident!(wasmtime_fiber_init),
49     "
50         mov eax, 4[esp]
51 
52         // move top_of_stack to the 2nd argument
53         mov -0x0c[eax], eax
54 
55         // move entry_arg0 to the 1st argument
56         mov ecx, 12[esp]
57         mov -0x10[eax], ecx
58 
59         // Move our start function to the return address which the `ret` in
60         // `wasmtime_fiber_start` will return to.
61         lea ecx, {start}
62         mov -0x14[eax], ecx
63 
64         // And move `entry_point` to get loaded into `%ebp` through the context
65         // switch. This'll get jumped to in `wasmtime_fiber_start`.
66         mov ecx, 8[esp]
67         mov -0x18[eax], ecx
68 
69         // Our stack from top-to-bottom looks like:
70         //
71         //	  * 8 bytes of reserved space per unix.rs (two-pointers space)
72         //	  * 8 bytes of arguments (two arguments wasmtime_fiber_start forwards)
73         //	  * 4 bytes of return address
74         //	  * 16 bytes of saved registers
75         //
76         // Note that after the return address the stack is conveniently 16-byte
77         // aligned as required, so we just leave the arguments on the stack in
78         // `wasmtime_fiber_start` and immediately do the call.
79         lea ecx, -0x24[eax]
80         mov -0x08[eax], ecx
81         ret
82     ",
83     start = sym super::wasmtime_fiber_start,
84 );
85 
86 asm_func!(
87     wasmtime_versioned_export_macros::versioned_stringify_ident!(wasmtime_fiber_start),
88     "
89         .cfi_startproc simple
90         .cfi_def_cfa_offset 0
91         .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \
92             5,            /* the byte length of this expression */ \
93             0x74, 0x08,   /* DW_OP_breg4 (%esp) + 8 */ \
94             0x06,         /* DW_OP_deref */ \
95             0x23, 0x14    /* DW_OP_plus_uconst 0x14 */
96 
97         .cfi_rel_offset eip, -4
98         .cfi_rel_offset ebp, -8
99         .cfi_rel_offset ebx, -12
100         .cfi_rel_offset esi, -16
101         .cfi_rel_offset edi, -20
102 
103         // Our arguments and stack alignment are all prepped by
104         // `wasmtime_fiber_init`.
105         call ebp
106         ud2
107         .cfi_endproc
108     ",
109 );
110