diff --git a/crates/jit/src/link.rs b/crates/jit/src/link.rs index c8313b5d86..8ffe729526 100644 --- a/crates/jit/src/link.rs +++ b/crates/jit/src/link.rs @@ -2,7 +2,7 @@ use crate::Compilation; use cranelift_codegen::binemit::Reloc; -use std::ptr::write_unaligned; +use std::ptr::{read_unaligned, write_unaligned}; use wasmtime_environ::{Module, Relocation, RelocationTarget}; use wasmtime_runtime::libcalls; use wasmtime_runtime::VMFunctionBody; @@ -101,6 +101,23 @@ fn apply_reloc( Reloc::X86PCRelRodata4 => { // ignore } + Reloc::Arm64Call => unsafe { + let reloc_address = body.add(r.offset as usize) as usize; + let reloc_addend = r.addend as isize; + let reloc_delta = (target_func_address as u64).wrapping_sub(reloc_address as u64); + // TODO: come up with a PLT-like solution for longer calls. We can't extend the + // code segment at this point, but we could conservatively allocate space at the + // end of the function during codegen, a fixed amount per call, to allow for + // potential branch islands. + assert!((reloc_delta as i64) < (1 << 27)); + assert!((reloc_delta as i64) >= -(1 << 27)); + let reloc_delta = reloc_delta as u32; + let reloc_delta = reloc_delta.wrapping_add(reloc_addend as u32); + let delta_bits = reloc_delta >> 2; + let insn = read_unaligned(reloc_address as *const u32); + let new_insn = (insn & 0xfc00_0000) | (delta_bits & 0x03ff_ffff); + write_unaligned(reloc_address as *mut u32, new_insn); + }, _ => panic!("unsupported reloc kind"), } } @@ -108,14 +125,11 @@ fn apply_reloc( // A declaration for the stack probe function in Rust's standard library, for // catching callstack overflow. cfg_if::cfg_if! { - if #[cfg(any( - target_arch="aarch64", - all( + if #[cfg(all( target_os = "windows", target_env = "msvc", target_pointer_width = "64" - ) - ))] { + ))] { extern "C" { pub fn __chkstk(); } @@ -132,6 +146,8 @@ cfg_if::cfg_if! { extern "C" { pub fn __rust_probestack(); } - static PROBESTACK: unsafe extern "C" fn() = __rust_probestack; + static PROBESTACK: unsafe extern "C" fn() = empty_probestack; } } + +extern "C" fn empty_probestack() {} diff --git a/crates/runtime/src/helpers.c b/crates/runtime/src/helpers.c index 213f34e593..6436922243 100644 --- a/crates/runtime/src/helpers.c +++ b/crates/runtime/src/helpers.c @@ -26,3 +26,12 @@ void* GetPcFromUContext(ucontext_t *cx) { return (void*) cx->uc_mcontext->__ss.__rip; } #endif + +#if defined(__linux__) && defined(__aarch64__) +#include + +void* GetPcFromUContext(ucontext_t *cx) { + return (void*) cx->uc_mcontext.pc; +} + +#endif // __linux__ && __aarch64__ diff --git a/crates/runtime/src/traphandlers.rs b/crates/runtime/src/traphandlers.rs index 657abb6221..571f823b3f 100644 --- a/crates/runtime/src/traphandlers.rs +++ b/crates/runtime/src/traphandlers.rs @@ -31,6 +31,7 @@ cfg_if::cfg_if! { static mut PREV_SIGBUS: MaybeUninit = MaybeUninit::uninit(); static mut PREV_SIGILL: MaybeUninit = MaybeUninit::uninit(); static mut PREV_SIGFPE: MaybeUninit = MaybeUninit::uninit(); + static mut PREV_SIGTRAP: MaybeUninit = MaybeUninit::uninit(); unsafe fn platform_init() { let register = |slot: &mut MaybeUninit, signal: i32| { @@ -70,6 +71,9 @@ cfg_if::cfg_if! { register(&mut PREV_SIGFPE, libc::SIGFPE); } + // on ARM64, we use `brk` to report traps, which generates SIGTRAP. + register(&mut PREV_SIGTRAP, libc::SIGTRAP); + // On ARM, handle Unaligned Accesses. // On Darwin, guard page accesses are raised as SIGBUS. if cfg!(target_arch = "arm") || cfg!(target_os = "macos") { @@ -87,6 +91,7 @@ cfg_if::cfg_if! { libc::SIGBUS => &PREV_SIGBUS, libc::SIGFPE => &PREV_SIGFPE, libc::SIGILL => &PREV_SIGILL, + libc::SIGTRAP => &PREV_SIGTRAP, _ => panic!("unknown signal: {}", signum), }; let handled = tls::with(|info| { @@ -158,6 +163,12 @@ cfg_if::cfg_if! { if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] { let cx = &*(cx as *const libc::ucontext_t); cx.uc_mcontext.gregs[libc::REG_RIP as usize] as *const u8 + } else if #[cfg(all(target_os = "linux", target_arch = "aarch64"))] { + // libc doesn't seem to support Linux/aarch64 at the moment? + extern "C" { + fn GetPcFromUContext(cx: *mut libc::c_void) -> *const u8; + } + GetPcFromUContext(cx) } else if #[cfg(target_os = "macos")] { // FIXME(rust-lang/libc#1702) - once that lands and is // released we should inline the definition here diff --git a/tests/custom_signal_handler.rs b/tests/custom_signal_handler.rs index 27d14fc910..8b3c8cd478 100644 --- a/tests/custom_signal_handler.rs +++ b/tests/custom_signal_handler.rs @@ -122,7 +122,7 @@ mod tests { .downcast::()?; assert!( trap.message() - .starts_with("wasm trap: out of bounds memory access"), + .starts_with("wasm trap: out of bounds"), "bad trap message: {:?}", trap.message() ); @@ -149,7 +149,7 @@ mod tests { .downcast::()?; assert!(trap .message() - .starts_with("wasm trap: out of bounds memory access")); + .starts_with("wasm trap: out of bounds")); } Ok(()) }