diff --git a/build.rs b/build.rs index 3c55c1350458583de01019561956fbd75b4e0861..b93858d862aff7ecdc0ccdb28b6f9c44c19360d6 100644 --- a/build.rs +++ b/build.rs @@ -5,7 +5,7 @@ extern crate gcc; fn main() { gcc::compile_library("libruntime.a", &["src/runtime/runtime_x64_sysv.c"]); - gcc::Config::new().flag("-O3") + gcc::Config::new().flag("-O3").flag("-c") .file("src/runtime/swap_stack_x64_sysv.S") .compile("libswap_stack.a"); } @@ -15,7 +15,7 @@ fn main() { fn main() { gcc::compile_library("libruntime.a", &["src/runtime/runtime_x64_sysv.c"]); - gcc::Config::new().flag("-O3") + gcc::Config::new().flag("-O3").flag("-c") .file("src/runtime/swap_stack_x64_sysv.S") .compile("libswap_stack.a"); } diff --git a/src/runtime/exception_x64.rs b/src/runtime/exception_x64.rs index ad2713dde82d467cc3b61393a0fa4a095a94ee8f..53e6b6d0e42c205e26e1b3f5bfa4e73d43f2e6f3 100644 --- a/src/runtime/exception_x64.rs +++ b/src/runtime/exception_x64.rs @@ -11,22 +11,48 @@ use std::sync::RwLockReadGuard; use std::collections::HashMap; use std::fmt; +// muentry_throw_exception in swap_stack_x64_sysV.S +// is like a special calling convention to throw_exception_internal +// in order to save all the callee saved registers at a known location + +// normal calling convention: +// ---code--- ---stack--- +// push caller saved caller saved +// call return addr +// -> (in callee) push rbp old rbp +// mov rsp -> rbp callee saved +// push callee saved + +// this function's calling convention +// ---code--- ---stack--- +// push caller saved caller saved +// call return addr +// -> (in asm) push callee saved all callee saved <- 2nd arg +// (in rust) push rbp (by rust) old rbp +// mov rsp -> rbp (by rust) callee saved +// push callee saved + +// we do not want to make any assumptionon where rust saves rbp or callee saved +// so we save them by ourselves in assembly, and pass a pointer as 2nd argument + #[no_mangle] #[allow(unreachable_code)] -pub extern fn muentry_throw_exception(exception_obj: Address) { +// last_frame_callee_saved: a pointer passed from assembly, values of 6 callee_saved +// registers are layed out as rbx, rbp, r12-r15 (from low address to high address) +// and return address is put after 6 callee saved regsiters +pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee_saved: Address) { trace!("throwing exception: {}", exception_obj); + + trace!("callee saved registers of last frame is saved at {}", last_frame_callee_saved); + inspect_nearby_address(last_frame_callee_saved, 8); let mut cur_thread = thread::MuThread::current_mut(); // set exception object cur_thread.exception_obj = exception_obj; let cf_lock = cur_thread.vm.compiled_funcs().read().unwrap(); - - // rbp of current frame (mu_throw_exception(), Rust frame) - let rust_frame_rbp = unsafe {thread::get_current_frame_rbp()}; - trace!("current frame RBP: 0x{:x}", rust_frame_rbp); - inspect_nearby_address(rust_frame_rbp, 5); - let rust_frame_return_addr = unsafe {rust_frame_rbp.plus(POINTER_SIZE).load::
()}; + + let rust_frame_return_addr = unsafe {last_frame_callee_saved.plus(POINTER_SIZE * x86_64::CALLEE_SAVED_GPRs.len()).load::
()}; trace!("return address : 0x{:x} - throw instruction", rust_frame_return_addr); // the return address is within throwing frame @@ -36,7 +62,9 @@ pub extern fn muentry_throw_exception(exception_obj: Address) { // skip to previous frame // this is the frame that throws the exception - let rbp = unsafe {rust_frame_rbp.load::
()}; + let previous_frame_rbp_loc = last_frame_callee_saved.plus(POINTER_SIZE); + let rbp = unsafe {previous_frame_rbp_loc.load::
()}; + trace!("rbp of previous frame is {} (last_frame_callee_saved {} + 8)", rbp, last_frame_callee_saved); // set cursor to throwing frame let mut cursor = FrameCursor { @@ -44,7 +72,14 @@ pub extern fn muentry_throw_exception(exception_obj: Address) { return_addr: unsafe {rbp.plus(POINTER_SIZE).load::
()}, func_id: throw_func, func_ver_id: throw_fv, - callee_saved_locs: HashMap::new() + callee_saved_locs: hashmap!{ + x86_64::RBX.id() => last_frame_callee_saved, + x86_64::RBP.id() => previous_frame_rbp_loc, + x86_64::R12.id() => last_frame_callee_saved.plus(POINTER_SIZE * 2), + x86_64::R13.id() => last_frame_callee_saved.plus(POINTER_SIZE * 3), + x86_64::R14.id() => last_frame_callee_saved.plus(POINTER_SIZE * 4), + x86_64::R15.id() => last_frame_callee_saved.plus(POINTER_SIZE * 5), + } }; trace!("cursor at first Mu frame: {}", cursor); diff --git a/src/runtime/swap_stack_x64_sysv.S b/src/runtime/swap_stack_x64_sysv.S index de5968cdaf8a4bf76b62dcc57ef2f58648752595..075c385a45f8e3193b1b70b40190bbaf9d2be52f 100644 --- a/src/runtime/swap_stack_x64_sysv.S +++ b/src/runtime/swap_stack_x64_sysv.S @@ -70,8 +70,25 @@ begin_func get_current_frame_rbp ret end_func get_current_frame_rbp +# muentry_throw_exception(obj: Address) +# %rdi +begin_func muentry_throw_exception + # save all callee-saved + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbp + pushq %rbx + + # %rsp points to %rbx, pass this as 2nd argument + movq %rsp, %rsi + + jmp CNAME(throw_exception_internal) + # won't return + # _exception_restore(dest: Address, callee_saved: *const Word, rsp: Address) -> ! -# %rdi %rsi %rdx +# %rdi %rsi %rdx # callee_saved: [rbx, rbp, r12, r13, r14, r15] begin_func exception_restore movq 0(%rsi), %rbx diff --git a/src/runtime/thread.rs b/src/runtime/thread.rs index 04bfbe6380156cfa45ffdc549dfd4e4ae75c8eee..40ccb7e2d1c3b176f0a86cd69ac9793e48196758 100644 --- a/src/runtime/thread.rs +++ b/src/runtime/thread.rs @@ -300,6 +300,7 @@ impl MuThread { if ! unsafe{muentry_get_thread_local()}.is_zero() { warn!("current thread has a thread local (has a muthread to it)"); + panic!("should not have muthread here"); return false; }