// A WORD OF CAUTION // // This entire file basically needs to be kept in sync with itself. It's not // really possible to modify just one bit of this file without understanding // all the other bits. Documentation tries to reference various bits here and // there but try to make sure to read over everything before tweaking things! // // Also at this time this file is heavily based off the x86_64 file, so you'll // probably want to read that one as well. use core::arch::naked_asm; #[inline(never)] // FIXME(rust-lang/rust#148307) pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) { unsafe { wasmtime_fiber_switch_(top_of_stack) } } #[unsafe(naked)] unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8 /* r0 */) { naked_asm!( " // Save callee-saved registers push {{r4-r11,lr}} // Swap stacks, recording our current stack pointer ldr r4, [r0, #-0x08] str sp, [r0, #-0x08] mov sp, r4 // Restore and return pop {{r4-r11,lr}} bx lr ", ); } pub(crate) unsafe fn wasmtime_fiber_init( top_of_stack: *mut u8, entry_point: extern "C" fn(*mut u8, *mut u8) -> *mut u8, entry_arg0: *mut u8, ) { #[repr(C)] #[derive(Default)] struct InitialStack { r4: *mut u8, r5: *mut u8, r6: *mut u8, r7: *mut u8, r8: *mut u8, r9: *mut u8, r10: *mut u8, r11: *mut u8, lr: *mut u8, // unix.rs reserved space last_sp: *mut u8, run_result: *mut u8, } unsafe { let initial_stack = top_of_stack.cast::().sub(1); initial_stack.write(InitialStack { r8: wasmtime_fiber_switch_ as *mut u8, r9: entry_arg0, r10: entry_point as *mut u8, r11: top_of_stack, lr: wasmtime_fiber_start as *mut u8, last_sp: initial_stack.cast(), ..InitialStack::default() }); } } #[unsafe(naked)] unsafe extern "C" fn wasmtime_fiber_start() -> ! { naked_asm!( " .cfi_startproc simple .cfi_def_cfa_offset 0 // See the x86_64 file for more commentary on what these CFI directives // are doing. Like over there note that the relative offsets to // registers here match the frame layout in `wasmtime_fiber_switch`. // // TODO: this is only lightly tested. This gets backtraces in gdb but // not at runtime. Perhaps the libgcc at runtime was too old? Doesn't // support something here? Unclear. Will need investigation if someone // ends up needing this and it still doesn't work. .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ 5, /* the byte length of this expression */ \ 0x7d, 0x00, /* DW_OP_breg14(%sp) + 0 */ \ 0x06, /* DW_OP_deref */ \ 0x23, 0x24 /* DW_OP_plus_uconst 0x24 */ .cfi_rel_offset lr, -0x04 .cfi_rel_offset r11, -0x08 .cfi_rel_offset r10, -0x0c .cfi_rel_offset r9, -0x10 .cfi_rel_offset r8, -0x14 .cfi_rel_offset r7, -0x18 .cfi_rel_offset r6, -0x1c .cfi_rel_offset r5, -0x20 .cfi_rel_offset r4, -0x24 mov r1, r11 mov r0, r9 blx r10 blx r8 .cfi_endproc ", ); }