imping_hook/context.rs
1//! The CPU register context passed to register-context injections.
2
3/// The x86-64 registers at an injection site: general-purpose registers,
4/// flags, instruction pointer and SSE registers.
5///
6/// [`inspect`](crate::InjectionBuilder::inspect) callbacks read it;
7/// [`modify`](crate::InjectionBuilder::modify) callbacks can also change it
8/// before the original code resumes, and redirect with [`rip`](Self::rip).
9// The stub reads and writes this layout on the stack; don't reorder fields.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[repr(C)]
12pub struct Context {
13 /// The `rflags` register.
14 pub rflags: u64,
15 /// The `rax` register.
16 pub rax: u64,
17 /// The `rbx` register.
18 pub rbx: u64,
19 /// The `rcx` register.
20 pub rcx: u64,
21 /// The `rdx` register.
22 pub rdx: u64,
23 /// The `rsi` register.
24 pub rsi: u64,
25 /// The `rdi` register.
26 pub rdi: u64,
27 /// The `rbp` register.
28 pub rbp: u64,
29 /// The stack pointer at the injection site.
30 ///
31 /// In `modify`, a changed `rsp` only takes effect along with a changed
32 /// [`rip`](Self::rip); otherwise the original code resumes on its own stack.
33 pub rsp: u64,
34 /// The `r8` register.
35 pub r8: u64,
36 /// The `r9` register.
37 pub r9: u64,
38 /// The `r10` register.
39 pub r10: u64,
40 /// The `r11` register.
41 pub r11: u64,
42 /// The `r12` register.
43 pub r12: u64,
44 /// The `r13` register.
45 pub r13: u64,
46 /// The `r14` register.
47 pub r14: u64,
48 /// The `r15` register.
49 pub r15: u64,
50 /// The address of the injection site, the patched instruction.
51 ///
52 /// In `modify`, setting it to another address jumps there with the (maybe
53 /// changed) [`rsp`](Self::rsp), and the displaced instructions don't run.
54 pub rip: u64,
55 /// The SSE registers `xmm0`–`xmm15`.
56 pub xmm: [Xmm; 16],
57}
58
59/// The 128 bits of one SSE (`xmm`) register.
60///
61/// Stored as raw little-endian bytes; the helpers read and build them as
62/// scalars or packed lanes.
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64#[repr(C)]
65pub struct Xmm(pub [u8; 16]);
66
67impl Xmm {
68 /// An all-zero register.
69 pub const ZERO: Xmm = Xmm([0; 16]);
70
71 /// Returns the raw little-endian bytes.
72 pub fn to_bytes(self) -> [u8; 16] {
73 self.0
74 }
75
76 /// Builds a register from raw little-endian bytes.
77 pub fn from_bytes(bytes: [u8; 16]) -> Xmm {
78 Xmm(bytes)
79 }
80
81 /// Returns all 128 bits as an unsigned integer.
82 pub fn u128(self) -> u128 {
83 u128::from_le_bytes(self.0)
84 }
85
86 /// Builds a register from a 128-bit unsigned integer.
87 pub fn from_u128(value: u128) -> Xmm {
88 Xmm(value.to_le_bytes())
89 }
90
91 /// Returns the low lane as an `f32`, a scalar single as after `movss`.
92 pub fn f32(self) -> f32 {
93 f32::from_le_bytes([self.0[0], self.0[1], self.0[2], self.0[3]])
94 }
95
96 /// Returns the low lane as an `f64`, a scalar double as after `movsd`.
97 pub fn f64(self) -> f64 {
98 f64::from_le_bytes([
99 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
100 ])
101 }
102
103 /// Returns the four packed `f32` lanes.
104 pub fn f32x4(self) -> [f32; 4] {
105 let mut out = [0.0f32; 4];
106 for (lane, value) in out.iter_mut().enumerate() {
107 let base = lane * 4;
108 *value = f32::from_le_bytes([
109 self.0[base],
110 self.0[base + 1],
111 self.0[base + 2],
112 self.0[base + 3],
113 ]);
114 }
115 out
116 }
117
118 /// Returns the two packed `f64` lanes.
119 pub fn f64x2(self) -> [f64; 2] {
120 let mut out = [0.0f64; 2];
121 for (lane, value) in out.iter_mut().enumerate() {
122 let base = lane * 8;
123 let mut bytes = [0u8; 8];
124 bytes.copy_from_slice(&self.0[base..base + 8]);
125 *value = f64::from_le_bytes(bytes);
126 }
127 out
128 }
129
130 /// Returns the four packed `i32` lanes.
131 pub fn i32x4(self) -> [i32; 4] {
132 let mut out = [0i32; 4];
133 for (lane, value) in out.iter_mut().enumerate() {
134 let base = lane * 4;
135 *value = i32::from_le_bytes([
136 self.0[base],
137 self.0[base + 1],
138 self.0[base + 2],
139 self.0[base + 3],
140 ]);
141 }
142 out
143 }
144
145 /// Returns the two packed `u64` lanes.
146 pub fn u64x2(self) -> [u64; 2] {
147 let mut out = [0u64; 2];
148 for (lane, value) in out.iter_mut().enumerate() {
149 let base = lane * 8;
150 let mut bytes = [0u8; 8];
151 bytes.copy_from_slice(&self.0[base..base + 8]);
152 *value = u64::from_le_bytes(bytes);
153 }
154 out
155 }
156
157 /// Sets the low `f32` lane, leaving the rest unchanged.
158 pub fn set_f32(&mut self, value: f32) {
159 self.0[0..4].copy_from_slice(&value.to_le_bytes());
160 }
161
162 /// Sets the low `f64` lane, leaving the rest unchanged.
163 pub fn set_f64(&mut self, value: f64) {
164 self.0[0..8].copy_from_slice(&value.to_le_bytes());
165 }
166
167 /// Builds a register with `value` in the low `f32` lane and zeros elsewhere.
168 pub fn from_f32(value: f32) -> Xmm {
169 let mut xmm = Xmm::ZERO;
170 xmm.set_f32(value);
171 xmm
172 }
173
174 /// Builds a register with `value` in the low `f64` lane and zeros elsewhere.
175 pub fn from_f64(value: f64) -> Xmm {
176 let mut xmm = Xmm::ZERO;
177 xmm.set_f64(value);
178 xmm
179 }
180
181 /// Builds a register from four packed `f32` lanes.
182 pub fn from_f32x4(lanes: [f32; 4]) -> Xmm {
183 let mut bytes = [0u8; 16];
184 for (lane, value) in lanes.iter().enumerate() {
185 bytes[lane * 4..lane * 4 + 4].copy_from_slice(&value.to_le_bytes());
186 }
187 Xmm(bytes)
188 }
189
190 /// Builds a register from two packed `f64` lanes.
191 pub fn from_f64x2(lanes: [f64; 2]) -> Xmm {
192 let mut bytes = [0u8; 16];
193 for (lane, value) in lanes.iter().enumerate() {
194 bytes[lane * 8..lane * 8 + 8].copy_from_slice(&value.to_le_bytes());
195 }
196 Xmm(bytes)
197 }
198}
199
200impl Default for Xmm {
201 fn default() -> Self {
202 Xmm::ZERO
203 }
204}