Implement context save/restore asm for x86_64

This commit is contained in:
Gary Guo 2021-08-25 05:59:24 +01:00
parent c9385a3f21
commit 5ecb44d1e3
3 changed files with 131 additions and 0 deletions

3
src/arch/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod x86_64;
pub use x86_64::*;

127
src/arch/x86_64.rs Normal file
View File

@ -0,0 +1,127 @@
use core::fmt;
use core::ops;
use gimli::{Register, X86_64};
#[repr(C)]
#[derive(Clone, Default)]
pub struct Context {
pub registers: [usize; 16],
pub ra: usize,
pub mcxsr: usize,
pub fcw: usize,
}
impl fmt::Debug for Context {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut fmt = fmt.debug_struct("Context");
for i in 0..=15 {
fmt.field(
X86_64::register_name(Register(i as _)).unwrap(),
&self.registers[i],
);
}
fmt.field("ra", &self.ra)
.field("mcxsr", &self.mcxsr)
.field("fcw", &self.fcw)
.finish()
}
}
impl ops::Index<Register> for Context {
type Output = usize;
fn index(&self, reg: Register) -> &usize {
match reg {
Register(0..=15) => &self.registers[reg.0 as usize],
X86_64::RA => &self.ra,
X86_64::MXCSR => &self.mcxsr,
X86_64::FCW => &self.fcw,
_ => unimplemented!(),
}
}
}
impl ops::IndexMut<gimli::Register> for Context {
fn index_mut(&mut self, reg: Register) -> &mut usize {
match reg {
Register(0..=15) => &mut self.registers[reg.0 as usize],
X86_64::RA => &mut self.ra,
X86_64::MXCSR => &mut self.mcxsr,
X86_64::FCW => &mut self.fcw,
_ => unimplemented!(),
}
}
}
#[naked]
pub extern "C-unwind" fn save_context() -> Context {
// No need to save caller-saved registers here.
unsafe {
asm!(
"
mov rax, rdi
mov [rax + 0x18], rbx
mov [rax + 0x30], rbp
/* Adjust the stack to account for the return address */
lea rdi, [rsp + 8]
mov [rax + 0x38], rdi
mov [rax + 0x60], r12
mov [rax + 0x68], r13
mov [rax + 0x70], r14
mov [rax + 0x78], r15
mov rdx, [rsp]
mov [rax + 0x80], rdx
stmxcsr [rax + 0x88]
fnstcw [rax + 0x90]
ret
",
options(noreturn)
);
}
}
#[naked]
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
// No need to save caller-saved registers here.
asm!(
"
/* Restore stack */
mov rsp, [rdi + 0x38]
/* Restore callee-saved control registers */
ldmxcsr [rdi + 0x88]
fldcw [rdi + 0x90]
/* Restore return address */
mov rax, [rdi + 0x80]
push rax
/*
* Restore general-purpose registers. Non-callee-saved registers are
* also restored because sometimes it's used to pass unwind arguments.
*/
mov rax, [rdi + 0x00]
mov rdx, [rdi + 0x08]
mov rcx, [rdi + 0x10]
mov rbx, [rdi + 0x18]
mov rsi, [rdi + 0x20]
mov rbp, [rdi + 0x30]
mov r8 , [rdi + 0x40]
mov r9 , [rdi + 0x48]
mov r10, [rdi + 0x50]
mov r11, [rdi + 0x58]
mov r12, [rdi + 0x60]
mov r13, [rdi + 0x68]
mov r14, [rdi + 0x70]
mov r15, [rdi + 0x78]
/* RDI resotred last */
mov rdi, [rdi + 0x28]
ret
",
options(noreturn)
);
}

View File

@ -1,2 +1,3 @@
mod arch;
mod find_fde;
mod util;