Skip to main content

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