juicebox_asm/reg.rs
1// SPDX-License-Identifier: MIT
2//
3// Copyright (c) 2023, Johannes Stoelp <dev@memzero.de>
4
5//! Definition of registers which are used as input operands for various instructions.
6
7/// Trait to interact with register operands.
8pub(crate) trait Reg {
9 /// Get the raw x64 register code.
10 fn idx(&self) -> u8;
11
12 /// Check if the registers needs the `REX.W` bit.
13 fn rexw(&self) -> bool;
14
15 /// Check if the register is an extended registers.
16 fn is_ext(&self) -> bool {
17 self.idx() > 7
18 }
19
20 /// Check if the register requires a `REX` byte.
21 fn need_rex(&self) -> bool {
22 self.is_ext() || self.rexw()
23 }
24
25 /// Check if the register requires a `SIB` byte if used as addressing operand.
26 ///
27 /// See [64 bit
28 /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
29 /// further details.
30 fn need_sib(&self) -> bool {
31 self.idx() == 4 || self.idx() == 12
32 }
33
34 /// Check if the register is interpreted as `PC` relative if used as addressing operand.
35 ///
36 /// See [64 bit
37 /// addressing](https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing) for
38 /// further details.
39 fn is_pc_rel(&self) -> bool {
40 self.idx() == 5 || self.idx() == 13
41 }
42}
43
44macro_rules! enum_reg {
45 (#[$doc:meta] $name:ident, { $($reg:ident),+ $(,)? }) => {
46 #[$doc]
47 #[allow(non_camel_case_types)]
48 #[derive(Copy, Clone)]
49 #[repr(u8)]
50 pub enum $name {
51 $( $reg, )+
52 }
53
54 #[cfg(test)]
55 impl $name {
56 fn iter() -> impl Iterator<Item = &'static $name> {
57 use $name::*;
58 [$( $reg, )+].iter()
59 }
60 }
61 };
62}
63
64macro_rules! impl_reg {
65 (#[$doc:meta] $name:ident, $rexw:expr, { $($reg:ident),+ $(,)? }) => {
66 enum_reg!(#[$doc] $name, { $( $reg, )+ });
67
68 impl Reg for $name {
69 /// Get the raw x64 register code.
70 fn idx(&self) -> u8 {
71 *self as u8
72 }
73
74 /// Check if the registers needs the `REX.W` bit.
75 fn rexw(&self) -> bool {
76 $rexw
77 }
78 }
79 }
80}
81
82impl_reg!(
83 /// Definition of 64 bit registers.
84 Reg64, true, { rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15 });
85impl_reg!(
86 /// Definition of 32 bit registers.
87 Reg32, false, { eax, ecx, edx, ebx, esp, ebp, esi, edi, r8d, r9d, r10d, r11d, r12d, r13d, r14d, r15d });
88impl_reg!(
89 /// Definition of 16 bit registers.
90 Reg16, false, { ax, cx, dx, bx, sp, bp, si, di, r8w, r9w, r10w, r11w, r12w, r13w, r14w, r15w });
91enum_reg!(
92 /// Definition of 8 bit registers.
93 Reg8, { al, cl, dl, bl, spl, bpl, sil, dil, r8l, r9l, r10l, r11l, r12l, r13l, r14l, r15l,
94 ah, ch, dh, bh });
95
96impl Reg for Reg8 {
97 /// Get the raw x64 register code.
98 fn idx(&self) -> u8 {
99 match self {
100 Reg8::ah => 4,
101 Reg8::ch => 5,
102 Reg8::dh => 6,
103 Reg8::bh => 7,
104 _ => *self as u8,
105 }
106 }
107
108 /// Check if the registers needs the `REX.W` bit.
109 fn rexw(&self) -> bool {
110 false
111 }
112
113 /// Check whether the gp register needs a `REX` prefix
114 /// Check if the register requires a `REX` byte.
115 ///
116 /// For 1 byte addressing, register indexes `[4:7]` require a `REX` prefix, or else they will
117 /// be decoded as `{AH, CH, DH, BH}` accordingly.
118 ///
119 /// See [Registers](https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers) for
120 /// further details or conduct `Table 3-1. Register Codes` in the *Intel Software Developers
121 /// Manual - Volume 2*.
122 fn need_rex(&self) -> bool {
123 self.idx() > 7 || matches!(self, Reg8::spl | Reg8::bpl | Reg8::sil | Reg8::dil)
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_reg8() {
133 use Reg8::*;
134
135 for r in Reg8::iter() {
136 // Check register index.
137 let idx = match r {
138 al => 0,
139 cl => 1,
140 dl => 2,
141 bl => 3,
142 spl => 4,
143 bpl => 5,
144 sil => 6,
145 dil => 7,
146 r8l => 8,
147 r9l => 9,
148 r10l => 10,
149 r11l => 11,
150 r12l => 12,
151 r13l => 13,
152 r14l => 14,
153 r15l => 15,
154 ah => 4,
155 ch => 5,
156 dh => 6,
157 bh => 7,
158 };
159 assert_eq!(r.idx(), idx);
160
161 // Check REX.W bit.
162 assert!(!r.rexw());
163
164 // Check need REX byte.
165 let rex = matches!(
166 r,
167 r8l | r9l | r10l | r11l | r12l | r13l | r14l | r15l | spl | bpl | sil | dil
168 );
169 assert_eq!(r.need_rex(), rex);
170
171 // Check need SIB byte.
172 let sib = matches!(r, spl | r12l | ah);
173 assert_eq!(r.need_sib(), sib);
174
175 // Check if is PC relative addressing.
176 let rel = matches!(r, bpl | r13l | ch);
177 assert_eq!(r.is_pc_rel(), rel);
178 }
179 }
180
181 #[test]
182 fn test_reg16() {
183 use Reg16::*;
184
185 for r in Reg16::iter() {
186 // Check register index.
187 let idx = match r {
188 ax => 0,
189 cx => 1,
190 dx => 2,
191 bx => 3,
192 sp => 4,
193 bp => 5,
194 si => 6,
195 di => 7,
196 r8w => 8,
197 r9w => 9,
198 r10w => 10,
199 r11w => 11,
200 r12w => 12,
201 r13w => 13,
202 r14w => 14,
203 r15w => 15,
204 };
205 assert_eq!(r.idx(), idx);
206
207 // Check REX.W bit.
208 assert!(!r.rexw());
209
210 // Check need REX byte.
211 let rex = matches!(r, r8w | r9w | r10w | r11w | r12w | r13w | r14w | r15w);
212 assert_eq!(r.need_rex(), rex);
213
214 // Check need SIB byte.
215 let sib = matches!(r, sp | r12w);
216 assert_eq!(r.need_sib(), sib);
217
218 // Check if is PC relative addressing.
219 let rel = matches!(r, bp | r13w);
220 assert_eq!(r.is_pc_rel(), rel);
221 }
222 }
223
224 #[test]
225 fn test_reg32() {
226 use Reg32::*;
227
228 for r in Reg32::iter() {
229 // Check register index.
230 let idx = match r {
231 eax => 0,
232 ecx => 1,
233 edx => 2,
234 ebx => 3,
235 esp => 4,
236 ebp => 5,
237 esi => 6,
238 edi => 7,
239 r8d => 8,
240 r9d => 9,
241 r10d => 10,
242 r11d => 11,
243 r12d => 12,
244 r13d => 13,
245 r14d => 14,
246 r15d => 15,
247 };
248 assert_eq!(r.idx(), idx);
249
250 // Check REX.W bit.
251 assert!(!r.rexw());
252
253 // Check need REX byte.
254 let rex = matches!(r, r8d | r9d | r10d | r11d | r12d | r13d | r14d | r15d);
255 assert_eq!(r.need_rex(), rex);
256
257 // Check need SIB byte.
258 let sib = matches!(r, esp | r12d);
259 assert_eq!(r.need_sib(), sib);
260
261 // Check if is PC relative addressing.
262 let rel = matches!(r, ebp | r13d);
263 assert_eq!(r.is_pc_rel(), rel);
264 }
265 }
266
267 #[test]
268 fn test_reg64() {
269 use Reg64::*;
270
271 for r in Reg64::iter() {
272 // Check register index.
273 let idx = match r {
274 rax => 0,
275 rcx => 1,
276 rdx => 2,
277 rbx => 3,
278 rsp => 4,
279 rbp => 5,
280 rsi => 6,
281 rdi => 7,
282 r8 => 8,
283 r9 => 9,
284 r10 => 10,
285 r11 => 11,
286 r12 => 12,
287 r13 => 13,
288 r14 => 14,
289 r15 => 15,
290 };
291 assert_eq!(r.idx(), idx);
292
293 // Check REX.W bit.
294 assert!(r.rexw());
295
296 // Check need REX byte.
297 assert!(r.need_rex());
298
299 // Check need SIB byte.
300 let sib = matches!(r, rsp | r12);
301 assert_eq!(r.need_sib(), sib);
302
303 // Check if is PC relative addressing.
304 let rel = matches!(r, rbp | r13);
305 assert_eq!(r.is_pc_rel(), rel);
306 }
307 }
308}