* Switch macOS to using mach ports for trap handling This commit moves macOS to using mach ports instead of signals for handling traps. The motivation for this is listed in #2456, namely that once mach ports are used in a process that means traditional UNIX signal handlers won't get used. This means that if Wasmtime is integrated with Breakpad, for example, then Wasmtime's trap handler never fires and traps don't work. The `traphandlers` module is refactored as part of this commit to split the platform-specific bits into their own files (it was growing quite a lot for one inline `cfg_if!`). The `unix.rs` and `windows.rs` files remain the same as they were before with a few minor tweaks for some refactored interfaces. The `macos.rs` file is brand new and lifts almost its entire implementation from SpiderMonkey, adapted for Wasmtime though. The main gotcha with mach ports is that a separate thread is what services the exception. Some unsafe magic allows this separate thread to read non-`Send` and temporary state from other threads, but is hoped to be safe in this context. The unfortunate downside is that calling wasm on macOS now involves taking a global lock and modifying a global hash map twice-per-call. I'm not entirely sure how to get out of this cost for now, but hopefully for any embeddings on macOS it's not the end of the world. Closes #2456 * Add a sketch of arm64 apple support * store: maintain CallThreadState mapping when switching fibers * cranelift/aarch64: generate unwind directives to disable pointer auth Aarch64 post ARMv8.3 has a feature called pointer authentication, designed to fight ROP/JOP attacks: some pointers may be signed using new instructions, adding payloads to the high (previously unused) bits of the pointers. More on this here: https://lwn.net/Articles/718888/ Unwinders on aarch64 need to know if some pointers contained on the call frame contain an authentication code or not, to be able to properly authenticate them or use them directly. Since native code may have enabled it by default (as is the case on the Mac M1), and the default is that this configuration value is inherited, we need to explicitly disable it, for the only kind of supported pointers (return addresses). To do so, we set the value of a non-existing dwarf pseudo register (34) to 0, as documented in https://github.com/ARM-software/abi-aa/blob/master/aadwarf64/aadwarf64.rst#note-8. This is done at the function granularity, in the spirit of Cranelift compilation model. Alternatively, a single directive could be generated in the CIE, generating less information per module. * Make exception handling work on Mac aarch64 too * fibers: use a breakpoint instruction after the final call in wasmtime_fiber_start Co-authored-by: Alex Crichton <alex@alexcrichton.com>
123 lines
4.0 KiB
ArmAsm
123 lines
4.0 KiB
ArmAsm
// 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.
|
|
|
|
#include "header.h"
|
|
|
|
// fn(top_of_stack(%x0): *mut u8)
|
|
HIDDEN(wasmtime_fiber_switch)
|
|
GLOBL(wasmtime_fiber_switch)
|
|
.p2align 2
|
|
TYPE(wasmtime_fiber_switch)
|
|
FUNCTION(wasmtime_fiber_switch):
|
|
// Save all callee-saved registers on the stack since we're assuming
|
|
// they're clobbered as a result of the stack switch.
|
|
stp lr, fp, [sp, -16]!
|
|
stp x20, x19, [sp, -16]!
|
|
stp x22, x21, [sp, -16]!
|
|
stp x24, x23, [sp, -16]!
|
|
stp x26, x25, [sp, -16]!
|
|
stp x28, x27, [sp, -16]!
|
|
stp d9, d8, [sp, -16]!
|
|
stp d11, d10, [sp, -16]!
|
|
stp d13, d12, [sp, -16]!
|
|
stp d15, d14, [sp, -16]!
|
|
|
|
// Load our previously saved stack pointer to resume to, and save off our
|
|
// current stack pointer on where to come back to eventually.
|
|
ldr x8, [x0, -0x10]
|
|
mov x9, sp
|
|
str x9, [x0, -0x10]
|
|
|
|
// Switch to the new stack and restore all our callee-saved registers after
|
|
// the switch and return to our new stack.
|
|
mov sp, x8
|
|
ldp d15, d14, [sp], 16
|
|
ldp d13, d12, [sp], 16
|
|
ldp d11, d10, [sp], 16
|
|
ldp d9, d8, [sp], 16
|
|
ldp x28, x27, [sp], 16
|
|
ldp x26, x25, [sp], 16
|
|
ldp x24, x23, [sp], 16
|
|
ldp x22, x21, [sp], 16
|
|
ldp x20, x19, [sp], 16
|
|
ldp lr, fp, [sp], 16
|
|
ret
|
|
SIZE(wasmtime_fiber_switch)
|
|
|
|
// fn(
|
|
// top_of_stack(%x0): *mut u8,
|
|
// entry_point(%x1): extern fn(*mut u8, *mut u8),
|
|
// entry_arg0(%x2): *mut u8,
|
|
// )
|
|
HIDDEN(wasmtime_fiber_init)
|
|
GLOBL(wasmtime_fiber_init)
|
|
.p2align 2
|
|
TYPE(wasmtime_fiber_init)
|
|
FUNCTION(wasmtime_fiber_init):
|
|
adr x8, FUNCTION(wasmtime_fiber_start)
|
|
stp x0, x8, [x0, -0x28] // x0 => x19, x8 => lr
|
|
stp x2, x1, [x0, -0x38] // x1 => x20, x2 => x21
|
|
|
|
// `wasmtime_fiber_switch` has an 0xa0 byte stack, and we add 0x10 more for
|
|
// the original reserved 16 bytes.
|
|
add x8, x0, -0xb0
|
|
str x8, [x0, -0x10]
|
|
ret
|
|
SIZE(wasmtime_fiber_init)
|
|
|
|
.p2align 2
|
|
TYPE(wasmtime_fiber_start)
|
|
FUNCTION(wasmtime_fiber_start):
|
|
.cfi_startproc simple
|
|
|
|
// 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`.
|
|
.cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \
|
|
5, /* the byte length of this expression */ \
|
|
0x6f, /* DW_OP_reg31(%sp) */ \
|
|
0x06, /* DW_OP_deref */ \
|
|
0x23, 0xa0, 0x1 /* DW_OP_plus_uconst 0xa0 */
|
|
|
|
.cfi_rel_offset lr, -0x10
|
|
.cfi_rel_offset x19, -0x18
|
|
.cfi_rel_offset x20, -0x20
|
|
.cfi_rel_offset x21, -0x28
|
|
.cfi_rel_offset x22, -0x30
|
|
.cfi_rel_offset x23, -0x38
|
|
.cfi_rel_offset x24, -0x40
|
|
.cfi_rel_offset x25, -0x48
|
|
.cfi_rel_offset x26, -0x50
|
|
.cfi_rel_offset x27, -0x58
|
|
.cfi_rel_offset x29, -0x60
|
|
|
|
// Load our two arguments from the stack, where x1 is our start procedure
|
|
// and x0 is its first argument. This also blows away the stack space used
|
|
// by those two arguments.
|
|
mov x0, x21
|
|
mov x1, x19
|
|
|
|
// ... and then we call the function! Note that this is a function call so
|
|
// our frame stays on the stack to backtrace through.
|
|
blr x20
|
|
// Unreachable, here for safety. This should help catch unexpected behaviors.
|
|
// Use a noticeable payload so one can grep for it in the codebase.
|
|
brk 0xf1b3
|
|
.cfi_endproc
|
|
SIZE(wasmtime_fiber_start)
|
|
|
|
// This omits the `.subsections_via_symbols` directive on macOS which means we
|
|
// can't GC specific intrinsics from this file, but it enables usage of the
|
|
// `adr` instruction above in lieu of figuring out a slightly more complicated
|
|
// way of implementing that.
|
|
#ifndef CFG_TARGET_OS_macos
|
|
FOOTER
|
|
#endif
|