x86_64.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. use core::fmt;
  2. use core::ops;
  3. use gimli::{Register, X86_64};
  4. #[repr(C)]
  5. #[derive(Clone, Default)]
  6. pub struct Context {
  7. pub registers: [usize; 16],
  8. pub ra: usize,
  9. pub mcxsr: usize,
  10. pub fcw: usize,
  11. }
  12. impl fmt::Debug for Context {
  13. fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
  14. let mut fmt = fmt.debug_struct("Context");
  15. for i in 0..=15 {
  16. fmt.field(
  17. X86_64::register_name(Register(i as _)).unwrap(),
  18. &self.registers[i],
  19. );
  20. }
  21. fmt.field("ra", &self.ra)
  22. .field("mcxsr", &self.mcxsr)
  23. .field("fcw", &self.fcw)
  24. .finish()
  25. }
  26. }
  27. impl ops::Index<Register> for Context {
  28. type Output = usize;
  29. fn index(&self, reg: Register) -> &usize {
  30. match reg {
  31. Register(0..=15) => &self.registers[reg.0 as usize],
  32. X86_64::RA => &self.ra,
  33. X86_64::MXCSR => &self.mcxsr,
  34. X86_64::FCW => &self.fcw,
  35. _ => unimplemented!(),
  36. }
  37. }
  38. }
  39. impl ops::IndexMut<gimli::Register> for Context {
  40. fn index_mut(&mut self, reg: Register) -> &mut usize {
  41. match reg {
  42. Register(0..=15) => &mut self.registers[reg.0 as usize],
  43. X86_64::RA => &mut self.ra,
  44. X86_64::MXCSR => &mut self.mcxsr,
  45. X86_64::FCW => &mut self.fcw,
  46. _ => unimplemented!(),
  47. }
  48. }
  49. }
  50. #[naked]
  51. pub extern "C-unwind" fn save_context() -> Context {
  52. // No need to save caller-saved registers here.
  53. unsafe {
  54. asm!(
  55. "
  56. mov rax, rdi
  57. mov [rax + 0x18], rbx
  58. mov [rax + 0x30], rbp
  59. /* Adjust the stack to account for the return address */
  60. lea rdi, [rsp + 8]
  61. mov [rax + 0x38], rdi
  62. mov [rax + 0x60], r12
  63. mov [rax + 0x68], r13
  64. mov [rax + 0x70], r14
  65. mov [rax + 0x78], r15
  66. mov rdx, [rsp]
  67. mov [rax + 0x80], rdx
  68. stmxcsr [rax + 0x88]
  69. fnstcw [rax + 0x90]
  70. ret
  71. ",
  72. options(noreturn)
  73. );
  74. }
  75. }
  76. #[naked]
  77. pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
  78. unsafe {
  79. asm!(
  80. "
  81. /* Restore stack */
  82. mov rsp, [rdi + 0x38]
  83. /* Restore callee-saved control registers */
  84. ldmxcsr [rdi + 0x88]
  85. fldcw [rdi + 0x90]
  86. /* Restore return address */
  87. mov rax, [rdi + 0x80]
  88. push rax
  89. /*
  90. * Restore general-purpose registers. Non-callee-saved registers are
  91. * also restored because sometimes it's used to pass unwind arguments.
  92. */
  93. mov rax, [rdi + 0x00]
  94. mov rdx, [rdi + 0x08]
  95. mov rcx, [rdi + 0x10]
  96. mov rbx, [rdi + 0x18]
  97. mov rsi, [rdi + 0x20]
  98. mov rbp, [rdi + 0x30]
  99. mov r8 , [rdi + 0x40]
  100. mov r9 , [rdi + 0x48]
  101. mov r10, [rdi + 0x50]
  102. mov r11, [rdi + 0x58]
  103. mov r12, [rdi + 0x60]
  104. mov r13, [rdi + 0x68]
  105. mov r14, [rdi + 0x70]
  106. mov r15, [rdi + 0x78]
  107. /* RDI resotred last */
  108. mov rdi, [rdi + 0x28]
  109. ret
  110. ",
  111. options(noreturn)
  112. );
  113. }
  114. }