dynasm/arch/x64/
ast.rs

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