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}