dynasm\arch\x64/
ast.rs

1use proc_macro2::Span;
2
3use crate::common::{Size, Jump};
4
5use std::cmp::PartialEq;
6
7
8/**
9 * Reused AST parts
10 */
11
12/**
13 * Registers
14 */
15
16#[derive(Debug, Clone)]
17pub struct Register {
18    pub size: Size,
19    pub kind: RegKind
20}
21
22#[derive(Debug, Clone)]
23pub enum RegKind {
24    Static(RegId),
25    Dynamic(RegFamily, syn::Expr)
26}
27
28// this map identifies the different registers that exist. some of these can be referred to as different sizes
29// but they share the same ID here (think AL/AX/EAX/RAX, XMM/YMM)
30#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
31pub enum RegId {
32    // size: 1, 2, 4 or 8 bytes
33    RAX = 0x00, RCX = 0x01, RDX = 0x02, RBX = 0x03,
34    RSP = 0x04, RBP = 0x05, RSI = 0x06, RDI = 0x07,
35    R8  = 0x08, R9  = 0x09, R10 = 0x0A, R11 = 0x0B,
36    R12 = 0x0C, R13 = 0x0D, R14 = 0x0E, R15 = 0x0F,
37
38    // size: 4 or 8 bytes
39    RIP = 0x15,
40
41    // size: 1 byte
42    AH = 0x24, CH = 0x25, DH = 0x26, BH = 0x27,
43
44    // size: 10 bytes
45    ST0 = 0x30, ST1 = 0x31, ST2 = 0x32, ST3 = 0x33,
46    ST4 = 0x34, ST5 = 0x35, ST6 = 0x36, ST7 = 0x37,
47
48    // size: 8 bytes. alternative encoding exists
49    MMX0 = 0x40, MMX1 = 0x41, MMX2 = 0x42, MMX3 = 0x43,
50    MMX4 = 0x44, MMX5 = 0x45, MMX6 = 0x46, MMX7 = 0x47,
51
52    // size: 16 bytes or 32 bytes
53    XMM0  = 0x50, XMM1  = 0x51, XMM2  = 0x52, XMM3  = 0x53,
54    XMM4  = 0x54, XMM5  = 0x55, XMM6  = 0x56, XMM7  = 0x57,
55    XMM8  = 0x58, XMM9  = 0x59, XMM10 = 0x5A, XMM11 = 0x5B,
56    XMM12 = 0x5C, XMM13 = 0x5D, XMM14 = 0x5E, XMM15 = 0x5F,
57
58    // size: 2 bytes. alternative encoding exists
59    ES = 0x60, CS = 0x61, SS = 0x62, DS = 0x63,
60    FS = 0x64, GS = 0x65,
61
62    // size: 4 bytes
63    CR0  = 0x70, CR1  = 0x71, CR2  = 0x72, CR3  = 0x73,
64    CR4  = 0x74, CR5  = 0x75, CR6  = 0x76, CR7  = 0x77,
65    CR8  = 0x78, CR9  = 0x79, CR10 = 0x7A, CR11 = 0x7B,
66    CR12 = 0x7C, CR13 = 0x7D, CR14 = 0x7E, CR15 = 0x7F,
67
68    // size: 4 bytes
69    DR0  = 0x80, DR1  = 0x81, DR2  = 0x82, DR3  = 0x83,
70    DR4  = 0x84, DR5  = 0x85, DR6  = 0x86, DR7  = 0x87,
71    DR8  = 0x88, DR9  = 0x89, DR10 = 0x8A, DR11 = 0x8B,
72    DR12 = 0x8C, DR13 = 0x8D, DR14 = 0x8E, DR15 = 0x8F,
73
74    // size: 16 bytes
75    BND0 = 0x90, BND1 = 0x91, BND2 = 0x92, BND3 = 0x93
76}
77
78#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone, Copy)]
79pub enum RegFamily {
80    LEGACY = 0,
81    RIP = 1,
82    HIGHBYTE = 2,
83    FP = 3,
84    MMX = 4,
85    XMM = 5,
86    SEGMENT = 6,
87    CONTROL = 7,
88    DEBUG = 8,
89    BOUND = 9
90}
91
92impl Register {
93    pub fn new_static(size: Size, id: RegId) -> Register {
94        Register {size, kind: RegKind::Static(id) }
95    }
96
97    pub fn new_dynamic(size: Size, family: RegFamily, id: syn::Expr) -> Register {
98        Register {size, kind: RegKind::Dynamic(family, id) }
99    }
100
101    pub fn size(&self) -> Size {
102        self.size
103    }
104}
105
106impl RegKind {
107    pub fn code(&self) -> Option<u8> {
108        match *self {
109            RegKind::Static(code) => Some(code.code()),
110            RegKind::Dynamic(_, _) => None
111        }
112    }
113
114    pub fn family(&self) -> RegFamily {
115        match *self {
116            RegKind::Static(code) => code.family(),
117            RegKind::Dynamic(family, _) => family
118        }
119    }
120
121    pub fn is_dynamic(&self) -> bool {
122        match *self {
123            RegKind::Static(_) => false,
124            RegKind::Dynamic(_, _) => true
125        }
126    }
127
128    pub fn is_extended(&self) -> bool {
129        match self.family() {
130            RegFamily::LEGACY  |
131            RegFamily::XMM     |
132            RegFamily::CONTROL |
133            RegFamily::DEBUG   => self.code().unwrap_or(8) > 7,
134            _ => false
135        }
136    }
137
138    pub fn encode(&self) -> u8 {
139        self.code().unwrap_or(0)
140    }
141
142    pub fn from_number(id: u8) -> RegKind {
143        RegKind::Static(RegId::from_number(id))
144    }
145}
146
147impl PartialEq<Register> for Register {
148    fn eq(&self, other: &Register) -> bool {
149        if self.size == other.size {
150            if let RegKind::Static(code) = self.kind {
151                if let RegKind::Static(other_code) = other.kind {
152                    return code == other_code
153                }
154            }
155        }
156        false
157    }
158}
159
160impl PartialEq<RegId> for Register {
161    fn eq(&self, other: &RegId) -> bool {
162        self.kind == *other
163    }
164}
165
166impl PartialEq<RegId> for RegKind {
167    fn eq(&self, other: &RegId) -> bool {
168        match *self {
169            RegKind::Static(id) => id == *other,
170            RegKind::Dynamic(_, _) => false
171        }
172    }
173}
174
175// workarounds to mask an impl<A, B> PartialEq<B> for Option<A: PartialEq<B>>
176impl PartialEq<RegId> for Option<Register> {
177    fn eq(&self, other: &RegId) -> bool {
178        match *self {
179            Some(ref a) => a == other,
180            None => false
181        }
182    }
183}
184
185impl PartialEq<RegId> for Option<RegKind> {
186    fn eq(&self, other: &RegId) -> bool {
187        match *self {
188            Some(ref a) => a == other,
189            None => false
190        }
191    }
192}
193
194impl RegId {
195    pub fn code(self) -> u8 {
196        self as u8 & 0xF
197    }
198
199    pub fn family(self) -> RegFamily {
200        match self as u8 >> 4 {
201            0 => RegFamily::LEGACY,
202            1 => RegFamily::RIP,
203            2 => RegFamily::HIGHBYTE,
204            3 => RegFamily::FP,
205            4 => RegFamily::MMX,
206            5 => RegFamily::XMM,
207            6 => RegFamily::SEGMENT,
208            7 => RegFamily::CONTROL,
209            8 => RegFamily::DEBUG,
210            9 => RegFamily::BOUND,
211            _ => unreachable!()
212        }
213    }
214
215    pub fn from_number(id: u8) -> RegId {
216        match id {
217            0  => RegId::RAX,
218            1  => RegId::RCX,
219            2  => RegId::RDX,
220            3  => RegId::RBX,
221            4  => RegId::RSP,
222            5  => RegId::RBP,
223            6  => RegId::RSI,
224            7  => RegId::RDI,
225            8  => RegId::R8,
226            9  => RegId::R9,
227            10 => RegId::R10,
228            11 => RegId::R11,
229            12 => RegId::R12,
230            13 => RegId::R13,
231            14 => RegId::R14,
232            15 => RegId::R15,
233            _ => panic!("invalid register code {:?}", id)
234        }
235    }
236}
237
238/**
239 * Memory ref items
240 */
241
242#[derive(Debug)]
243pub enum MemoryRefItem {
244    ScaledRegister(Register, isize),
245    Register(Register),
246    Displacement(syn::Expr)
247}
248
249/**
250 * Parsed ast
251 */
252
253#[derive(Debug)]
254pub enum RawArg {
255    // unprocessed typemapped argument
256    TypeMappedRaw {
257        span: Span,
258        nosplit: bool,
259        value_size: Option<Size>,
260        disp_size: Option<Size>,
261        base_reg: Register,
262        scale: syn::Path,
263        scaled_items: Vec<MemoryRefItem>,
264        attribute: Option<syn::Ident>,
265    },
266    // unprocessed memory reference argument
267    IndirectRaw {
268        span: Span,
269        nosplit: bool,
270        value_size: Option<Size>,
271        disp_size: Option<Size>,
272        items: Vec<MemoryRefItem>,
273    },
274    // direct register reference, 
275    Direct {
276        reg: Register
277    },
278    // a jump offset, i.e. ->foo
279    JumpTarget {
280        jump: Jump,
281        size: Option<Size>
282    },
283    // a memory reference to a label, i.e. [->foo]
284    IndirectJumpTarget {
285        jump: Jump,
286        size: Option<Size>
287    },
288    // just an arbitrary expression
289    Immediate {
290        value: syn::Expr,
291        size: Option<Size>
292    },
293    // used to not block the parser on a parsing error in a single arg
294    Invalid
295}
296
297#[derive(Debug)]
298pub enum CleanArg {
299    // memory reference
300    Indirect {
301        span: Span,
302        nosplit: bool,
303        size: Option<Size>,
304        disp_size: Option<Size>,
305        base: Option<Register>,
306        index: Option<(Register, isize, Option<syn::Expr>)>,
307        disp: Option<syn::Expr>
308    },
309    // direct register reference, 
310    Direct {
311        reg: Register
312    },
313    // a jump offset, i.e. ->foo
314    JumpTarget {
315        jump: Jump,
316        size: Option<Size>
317    },
318    // a memory reference to a label, i.e. [->foo]
319    IndirectJumpTarget {
320        jump: Jump,
321        size: Option<Size>
322    },
323    // just an arbitrary expression
324    Immediate {
325        value: syn::Expr,
326        size: Option<Size>
327    }
328}
329
330#[derive(Debug)]
331pub enum SizedArg {
332    // memory reference. size info is lost here as
333    // it is never actually encoded
334    Indirect {
335        disp_size: Option<Size>,
336        base: Option<Register>,
337        index: Option<(Register, isize, Option<syn::Expr>)>,
338        disp: Option<syn::Expr>
339    },
340    // direct register reference, 
341    Direct {
342        reg: Register
343    },
344    // a jump offset, i.e. ->foo
345    JumpTarget {
346        jump: Jump,
347        size: Size
348    },
349    // a memory reference to a label, i.e. [->foo]
350    IndirectJumpTarget {
351        jump: Jump
352    },
353    // just an arbitrary expression
354    Immediate {
355        value: syn::Expr,
356        size: Size
357    }
358}
359
360/**
361 * Parsed instruction
362 */
363
364pub struct Instruction {
365    pub span: Span,
366    pub idents: Vec<syn::Ident>
367}