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 // Also at this time this file is heavily based off the x86_64 file, so you'll 9 // probably want to read that one as well. 10 11 use core::arch::naked_asm; 12 13 #[inline(never)] // FIXME(rust-lang/rust#148307) 14 pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) { 15 unsafe { wasmtime_fiber_switch_(top_of_stack) } 16 } 17 18 #[unsafe(naked)] 19 unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8 /* r0 */) { 20 naked_asm!( 21 " 22 // Save callee-saved registers 23 push {{r4-r11,lr}} 24 25 // Swap stacks, recording our current stack pointer 26 ldr r4, [r0, #-0x08] 27 str sp, [r0, #-0x08] 28 mov sp, r4 29 30 // Restore and return 31 pop {{r4-r11,lr}} 32 bx lr 33 ", 34 ); 35 } 36 37 pub(crate) unsafe fn wasmtime_fiber_init( 38 top_of_stack: *mut u8, 39 entry_point: extern "C" fn(*mut u8, *mut u8) -> *mut u8, 40 entry_arg0: *mut u8, 41 ) { 42 #[repr(C)] 43 #[derive(Default)] 44 struct InitialStack { 45 r4: *mut u8, 46 r5: *mut u8, 47 r6: *mut u8, 48 r7: *mut u8, 49 r8: *mut u8, 50 r9: *mut u8, 51 r10: *mut u8, 52 r11: *mut u8, 53 lr: *mut u8, 54 55 // unix.rs reserved space 56 last_sp: *mut u8, 57 run_result: *mut u8, 58 } 59 60 unsafe { 61 let initial_stack = top_of_stack.cast::<InitialStack>().sub(1); 62 initial_stack.write(InitialStack { 63 r8: wasmtime_fiber_switch_ as *mut u8, 64 r9: entry_arg0, 65 r10: entry_point as *mut u8, 66 r11: top_of_stack, 67 lr: wasmtime_fiber_start as *mut u8, 68 last_sp: initial_stack.cast(), 69 ..InitialStack::default() 70 }); 71 } 72 } 73 74 #[unsafe(naked)] 75 unsafe extern "C" fn wasmtime_fiber_start() -> ! { 76 naked_asm!( 77 " 78 .cfi_startproc simple 79 .cfi_def_cfa_offset 0 80 // See the x86_64 file for more commentary on what these CFI directives 81 // are doing. Like over there note that the relative offsets to 82 // registers here match the frame layout in `wasmtime_fiber_switch`. 83 // 84 // TODO: this is only lightly tested. This gets backtraces in gdb but 85 // not at runtime. Perhaps the libgcc at runtime was too old? Doesn't 86 // support something here? Unclear. Will need investigation if someone 87 // ends up needing this and it still doesn't work. 88 .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ 89 5, /* the byte length of this expression */ \ 90 0x7d, 0x00, /* DW_OP_breg14(%sp) + 0 */ \ 91 0x06, /* DW_OP_deref */ \ 92 0x23, 0x24 /* DW_OP_plus_uconst 0x24 */ 93 94 .cfi_rel_offset lr, -0x04 95 .cfi_rel_offset r11, -0x08 96 .cfi_rel_offset r10, -0x0c 97 .cfi_rel_offset r9, -0x10 98 .cfi_rel_offset r8, -0x14 99 .cfi_rel_offset r7, -0x18 100 .cfi_rel_offset r6, -0x1c 101 .cfi_rel_offset r5, -0x20 102 .cfi_rel_offset r4, -0x24 103 104 mov r1, r11 105 mov r0, r9 106 blx r10 107 blx r8 108 .cfi_endproc 109 ", 110 ); 111 } 112