Skip to main content

asmkit/x86/
assembler.rs

1#![allow(dead_code, clippy::all)]
2use super::features::base::MovEmitter;
3use super::opcodes::ALT_TAB;
4use super::operands::*;
5use crate::{
6    X86Error,
7    core::{
8        buffer::{
9            CodeBuffer, CodeOffset, ConstantData, LabelUse, Reloc, RelocDistance, RelocTarget,
10        },
11        emitter::Emitter,
12        operand::*,
13        patch::{PatchBlockId, PatchSiteId},
14    },
15};
16
17/// X86/X64 Assembler implementation.
18pub struct Assembler<'a> {
19    pub buffer: &'a mut CodeBuffer,
20    flags: u64,
21    extra_reg: Reg,
22    last_error: Option<X86Error>,
23}
24
25const RC_RN: u64 = 0x0000000;
26const RC_RD: u64 = 0x0800000;
27const RC_RU: u64 = 0x1000000;
28const RC_RZ: u64 = 0x1800000;
29const SEG_MASK: u64 = 0xe0000000;
30const ADDR32: u64 = 0x10000000;
31const LONG: u64 = 0x100000000;
32
33const OPC_66: u64 = 0x80000;
34const OPC_F2: u64 = 0x100000;
35const OPC_F3: u64 = 0x200000;
36const OPC_REXW: u64 = 0x400000;
37const OPC_LOCK: u64 = 0x800000;
38const OPC_VEXL0: u64 = 0x1000000;
39const OPC_VEXL1: u64 = 0x1800000;
40const OPC_EVEXL0: u64 = 0x2000000;
41const OPC_EVEXL1: u64 = 0x2800000;
42const OPC_EVEXL2: u64 = 0x3000000;
43const OPC_EVEXL3: u64 = 0x3800000;
44const OPC_EVEXB: u64 = 0x4000000;
45const OPC_VSIB: u64 = 0x8000000;
46const OPC_67: u64 = ADDR32;
47const OPC_SEG_MSK: u64 = 0xe0000000;
48const OPC_JMPL: u64 = 0x100000000; // Placeholder for FE_JMPL, define as needed
49const OPC_MASK_MSK: u64 = 0xe00000000;
50const OPC_EVEXZ: u64 = 0x1000000000;
51const OPC_USER_MSK: u64 = OPC_67 | OPC_SEG_MSK | OPC_MASK_MSK;
52const OPC_FORCE_SIB: u64 = 0x2000000000;
53const OPC_DOWNGRADE_VEX: u64 = 0x4000000000;
54const OPC_DOWNGRADE_VEX_FLIPW: u64 = 0x40000000000;
55const OPC_EVEX_DISP8SCALE: u64 = 0x38000000000;
56const OPC_GPH_OP0: u64 = 0x200000000000;
57const OPC_GPH_OP1: u64 = 0x400000000000;
58const EPFX_REX_MSK: u64 = 0x43f;
59const EPFX_REX: u64 = 0x20;
60const EPFX_EVEX: u64 = 0x40;
61const EPFX_REXR: u64 = 0x10;
62const EPFX_REXX: u64 = 0x08;
63const EPFX_REXB: u64 = 0x04;
64const EPFX_REXR4: u64 = 0x02;
65const EPFX_REXB4: u64 = 0x01;
66const EPFX_REXX4: u64 = 0x400;
67const EPFX_VVVV_IDX: u64 = 11;
68
69fn op_imm_n(imm: Operand, immsz: usize) -> bool {
70    if !imm.is_imm() {
71        return false;
72    }
73    let imm = imm.as_::<Imm>();
74    if immsz == 0 && imm.value() == 0 {
75        return true;
76    }
77
78    if immsz == 1 && imm.is_int8() {
79        return true;
80    }
81    if immsz == 2 && imm.is_int16() {
82        return true;
83    }
84    if immsz == 3 && (imm.value() & 0xffffff) == imm.value() {
85        return true;
86    }
87    if immsz == 4 && imm.is_int32() {
88        return true;
89    }
90    if immsz == 8 {
91        return true;
92    }
93
94    false
95}
96
97fn opc_size(opc: u64, epfx: u64) -> usize {
98    let mut res = 1;
99
100    if (opc & OPC_EVEXL0) != 0 {
101        res += 4;
102    } else if (opc & OPC_VEXL0) != 0 {
103        if (opc & (OPC_REXW | 0x20000)) != 0 || (epfx & (EPFX_REXX | EPFX_REXB)) != 0 {
104            res += 3;
105        } else {
106            res += 2;
107        }
108    } else {
109        if (opc & OPC_LOCK) != 0 {
110            res += 1;
111        }
112        if (opc & OPC_66) != 0 {
113            res += 1;
114        }
115        if (opc & (OPC_F2 | OPC_F3)) != 0 {
116            res += 1;
117        }
118        if (opc & OPC_REXW) != 0 || (epfx & EPFX_REX_MSK) != 0 {
119            res += 1;
120        }
121        if (opc & 0x30000) != 0 {
122            res += 1;
123        }
124        if (opc & 0x20000) != 0 {
125            res += 1;
126        }
127    }
128    if (opc & OPC_SEG_MSK) != 0 {
129        res += 1;
130    }
131    if (opc & OPC_67) != 0 {
132        res += 1;
133    }
134    if (opc & 0x8000) != 0 {
135        res += 1;
136    }
137
138    res
139}
140
141#[derive(Copy, Clone, PartialEq, Eq, Debug)]
142enum Encoding {
143    NP,
144    M,
145    R,
146    M1,
147    MC,
148    MR,
149    RM,
150    RMA,
151    MRC,
152    AM,
153    MA,
154    I,
155    O,
156    OA,
157    S,
158    A,
159    D,
160    FD,
161    TD,
162    IM,
163    RVM,
164    RVMR,
165    RMV,
166    VM,
167    MVR,
168    MRV,
169    MAX,
170}
171#[repr(C)]
172#[derive(Copy, Clone, Debug)]
173struct EncodingInfo {
174    modrm: u8,
175    modreg: u8,
176    vexreg: u8,
177    immidx: u8,
178    immctl: u8,
179    zregidx: u8,
180    zregval: u8,
181}
182
183impl EncodingInfo {
184    pub const fn new() -> Self {
185        Self {
186            modreg: 0,
187            modrm: 0,
188            vexreg: 0,
189            immctl: 0,
190            immidx: 0,
191            zregidx: 0,
192            zregval: 0,
193        }
194    }
195}
196
197const ENCODING_INFOS: [EncodingInfo; Encoding::MAX as usize] = [
198    EncodingInfo::new(),
199    EncodingInfo {
200        modrm: 0x0 ^ 3,
201        immidx: 1,
202        ..EncodingInfo::new()
203    },
204    EncodingInfo {
205        modreg: 0x0 ^ 3,
206        ..EncodingInfo::new()
207    },
208    EncodingInfo {
209        modrm: 0x0 ^ 3,
210        immctl: 1,
211        immidx: 1,
212        ..EncodingInfo::new()
213    },
214    EncodingInfo {
215        modrm: 0x0 ^ 3,
216        zregidx: 0x1 ^ 3,
217        zregval: 1,
218        ..EncodingInfo::new()
219    },
220    EncodingInfo {
221        modrm: 0x0 ^ 3,
222        modreg: 0x1 ^ 3,
223        immidx: 2,
224        ..EncodingInfo::new()
225    },
226    EncodingInfo {
227        modrm: 0x1 ^ 3,
228        modreg: 0x0 ^ 3,
229        immidx: 2,
230        ..EncodingInfo::new()
231    },
232    EncodingInfo {
233        modrm: 0x1 ^ 3,
234        modreg: 0x0 ^ 3,
235        zregidx: 0x2 ^ 3,
236        zregval: 0,
237        ..EncodingInfo::new()
238    },
239    EncodingInfo {
240        modrm: 0x0 ^ 3,
241        modreg: 0x1 ^ 3,
242        zregidx: 0x2 ^ 3,
243        zregval: 1,
244        ..EncodingInfo::new()
245    },
246    EncodingInfo {
247        modrm: 0x1 ^ 3,
248        zregidx: 0x0 ^ 3,
249        zregval: 0,
250        ..EncodingInfo::new()
251    },
252    EncodingInfo {
253        modrm: 0x0 ^ 3,
254        zregidx: 0x1 ^ 3,
255        zregval: 0,
256        ..EncodingInfo::new()
257    },
258    EncodingInfo {
259        immidx: 0,
260        ..EncodingInfo::new()
261    },
262    EncodingInfo {
263        modreg: 0x0 ^ 3,
264        immidx: 1,
265        ..EncodingInfo::new()
266    },
267    EncodingInfo {
268        modreg: 0x0 ^ 3,
269        zregidx: 0x1 ^ 3,
270        zregval: 0,
271        ..EncodingInfo::new()
272    },
273    EncodingInfo::new(),
274    EncodingInfo {
275        zregidx: 0x0 ^ 3,
276        zregval: 0,
277        immidx: 1,
278        ..EncodingInfo::new()
279    },
280    EncodingInfo {
281        immidx: 0,
282        ..EncodingInfo::new()
283    },
284    EncodingInfo {
285        zregidx: 0x0 ^ 3,
286        zregval: 0,
287        immctl: 2,
288        immidx: 1,
289        ..EncodingInfo::new()
290    },
291    EncodingInfo {
292        zregidx: 0x1 ^ 3,
293        zregval: 0,
294        immctl: 2,
295        immidx: 0,
296        ..EncodingInfo::new()
297    },
298    EncodingInfo {
299        modrm: 0x1 ^ 3,
300        immidx: 0,
301        ..EncodingInfo::new()
302    },
303    EncodingInfo {
304        modrm: 0x2 ^ 3,
305        modreg: 0x0 ^ 3,
306        vexreg: 0x1 ^ 3,
307        immidx: 3,
308        ..EncodingInfo::new()
309    },
310    EncodingInfo {
311        modrm: 0x2 ^ 3,
312        modreg: 0x0 ^ 3,
313        vexreg: 0x1 ^ 3,
314        immctl: 3,
315        immidx: 3,
316        ..EncodingInfo::new()
317    },
318    EncodingInfo {
319        modrm: 0x1 ^ 3,
320        modreg: 0x0 ^ 3,
321        vexreg: 0x2 ^ 3,
322        ..EncodingInfo::new()
323    },
324    EncodingInfo {
325        modrm: 0x1 ^ 3,
326        vexreg: 0x0 ^ 3,
327        immidx: 2,
328        ..EncodingInfo::new()
329    },
330    EncodingInfo {
331        modrm: 0x0 ^ 3,
332        modreg: 0x2 ^ 3,
333        vexreg: 0x1 ^ 3,
334        ..EncodingInfo::new()
335    },
336    EncodingInfo {
337        modrm: 0x0 ^ 3,
338        modreg: 0x1 ^ 3,
339        vexreg: 0x2 ^ 3,
340        ..EncodingInfo::new()
341    },
342];
343
344impl<'a> Assembler<'a> {
345    pub fn new(buf: &'a mut CodeBuffer) -> Self {
346        Self {
347            buffer: buf,
348            extra_reg: Reg::new(),
349            flags: 0,
350            last_error: None,
351        }
352    }
353
354    /// Get the last error that occurred during assembly.
355    pub fn last_error(&self) -> Option<X86Error> {
356        self.last_error.clone()
357    }
358
359    /// Clear the last error.
360    pub fn clear_error(&mut self) {
361        self.last_error = None;
362    }
363
364    pub fn sae(&mut self) -> &mut Self {
365        self.flags |= 0x4000000;
366        self
367    }
368
369    pub fn rn_sae(&mut self) -> &mut Self {
370        self.flags |= 0x4000000 | RC_RN;
371        self
372    }
373
374    pub fn rd_sae(&mut self) -> &mut Self {
375        self.flags |= 0x4000000 | RC_RD;
376        self
377    }
378    pub fn ru_sae(&mut self) -> &mut Self {
379        self.flags |= 0x4000000 | RC_RU;
380        self
381    }
382
383    pub fn rz_sae(&mut self) -> &mut Self {
384        self.flags |= 0x4000000 | RC_RZ;
385        self
386    }
387
388    pub fn seg(&mut self, sreg: SReg) -> &mut Self {
389        self.flags |= ((sreg.id() & 0x7) as u64) << 29;
390        self
391    }
392
393    pub fn fs(&mut self) -> &mut Self {
394        self.seg(FS)
395    }
396
397    pub fn gs(&mut self) -> &mut Self {
398        self.seg(GS)
399    }
400
401    pub fn k(&mut self, k: KReg) -> &mut Self {
402        self.flags |= ((k.id() & 0x7) as u64) << 33;
403
404        self
405    }
406
407    pub fn rep(&mut self) -> &mut Self {
408        self.flags |= 0x200000;
409        self
410    }
411
412    pub fn repnz(&mut self) -> &mut Self {
413        self.flags |= 0x100000;
414        self
415    }
416
417    pub fn repz(&mut self) -> &mut Self {
418        self.rep()
419    }
420
421    pub fn lock(&mut self) -> &mut Self {
422        self.flags |= 0x800000;
423        self
424    }
425
426    pub fn long(&mut self) -> &mut Self {
427        self.flags |= LONG;
428        self
429    }
430
431    pub fn get_label(&mut self) -> Label {
432        self.buffer.get_label()
433    }
434
435    pub fn bind_label(&mut self, label: Label) {
436        self.buffer.bind_label(label);
437    }
438
439    pub fn add_constant(&mut self, c: impl Into<ConstantData>) -> Label {
440        let c = self.buffer.add_constant(c);
441        self.buffer.get_label_for_constant(c)
442    }
443
444    pub fn label_offset(&self, label: Label) -> CodeOffset {
445        self.buffer.label_offset(label)
446    }
447
448    pub fn patchable_jmp(&mut self, label: Label) -> PatchSiteId {
449        self.jmp(label);
450        let offset = self
451            .buffer
452            .cur_offset()
453            .saturating_sub(LabelUse::X86JmpRel32.patch_size() as u32);
454        self.buffer
455            .record_label_patch_site(offset, label, LabelUse::X86JmpRel32)
456    }
457
458    pub fn patchable_call(&mut self, label: Label) -> PatchSiteId {
459        self.call(label);
460        let offset = self
461            .buffer
462            .cur_offset()
463            .saturating_sub(LabelUse::X86JmpRel32.patch_size() as u32);
464        self.buffer
465            .record_label_patch_site(offset, label, LabelUse::X86JmpRel32)
466    }
467
468    pub fn patchable_mov<A, B>(&mut self, dst: A, src: B) -> PatchBlockId
469    where
470        A: OperandCast + Copy,
471        B: OperandCast + Copy,
472        Self: MovEmitter<A, B>,
473    {
474        let dst_op = *dst.as_operand();
475        let src_op = *src.as_operand();
476        if !src_op.is_imm() {
477            unreachable!("patchable_mov currently only supports immediate sources");
478        }
479
480        self.mov::<A, B>(dst, src);
481
482        if dst_op.is_reg_type_of(RegType::Gp64) {
483            let offset = self.buffer.cur_offset().saturating_sub(8);
484            self.buffer.record_patch_block(offset, 8, 1)
485        } else if dst_op.is_reg_type_of(RegType::Gp32) {
486            self.mov::<A, B>(dst, src);
487            let offset = self.buffer.cur_offset().saturating_sub(4);
488            self.buffer.record_patch_block(offset, 4, 1)
489        } else {
490            unreachable!("patchable_mov currently only supports Gp64 and Gp32 destinations");
491        }
492    }
493
494    fn enc_opc(&mut self, opc: u64, epfx: u64) -> bool {
495        if opc & OPC_SEG_MSK != 0 {
496            self.buffer
497                .put1(((0x65643e362e2600u64 >> (8 * ((opc >> 29) & 7))) & 0xff) as u8);
498        }
499
500        if opc & OPC_67 != 0 {
501            self.buffer.put1(0x67);
502        }
503
504        if opc & OPC_EVEXL0 != 0 {
505            self.buffer.put1(0x62);
506            let mut b1 = (opc >> 16 & 7) as u8;
507            if (epfx & EPFX_REXR) == 0 {
508                b1 |= 0x80;
509            }
510            if (epfx & EPFX_REXX) == 0 {
511                b1 |= 0x40;
512            }
513            if (epfx & EPFX_REXB) == 0 {
514                b1 |= 0x20;
515            }
516            if (epfx & EPFX_REXR4) == 0 {
517                b1 |= 0x10;
518            }
519            if (epfx & EPFX_REXB4) != 0 {
520                b1 |= 0x08;
521            }
522            self.buffer.put1(b1);
523
524            let mut b2 = (opc >> 20 & 3) as u8;
525            if (epfx & EPFX_REXX4) == 0 {
526                b2 |= 0x04;
527            }
528            b2 |= ((!(epfx >> EPFX_VVVV_IDX) & 0xf) << 3) as u8;
529            if opc & OPC_REXW != 0 {
530                b2 |= 0x80;
531            }
532            self.buffer.put1(b2);
533
534            let mut b3 = (opc >> 33 & 7) as u8;
535            b3 |= ((!(epfx >> EPFX_VVVV_IDX) & 0x10) >> 1) as u8;
536            if opc & OPC_EVEXB != 0 {
537                b3 |= 0x10;
538            }
539            b3 |= ((opc >> 23 & 3) << 5) as u8;
540            if opc & OPC_EVEXZ != 0 {
541                b3 |= 0x80;
542            }
543            self.buffer.put1(b3);
544        } else if opc & OPC_VEXL0 != 0 {
545            if (epfx & (EPFX_REXR4 | EPFX_REXX4 | EPFX_REXB4 | (0x10 << EPFX_VVVV_IDX))) != 0 {
546                self.last_error = Some(X86Error::InvalidVEX {
547                    field: "prefix",
548                    reason: "VEX prefix has invalid extended register bits",
549                });
550                return true;
551            }
552
553            let vex3 = (opc & (OPC_REXW | 0x20000)) != 0 || (epfx & (EPFX_REXX | EPFX_REXB)) != 0;
554            let pp = (opc >> 20 & 3) as u8;
555            self.buffer.put1(0xc4 | !vex3 as u8);
556
557            let mut b2 = pp | if (opc & 0x800000) != 0 { 0x4 } else { 0 };
558
559            if vex3 {
560                let mut b1 = (opc >> 16 & 3) as u8;
561                if (epfx & EPFX_REXR) == 0 {
562                    b1 |= 0x80;
563                }
564                if (epfx & EPFX_REXX) == 0 {
565                    b1 |= 0x40;
566                }
567                if (epfx & EPFX_REXB) == 0 {
568                    b1 |= 0x20;
569                }
570                self.buffer.put1(b1);
571
572                if (opc & OPC_REXW) != 0 {
573                    b2 |= 0x80;
574                }
575            } else {
576                if (epfx & EPFX_REXR) == 0 {
577                    b2 |= 0x80;
578                }
579            }
580
581            b2 |= ((!(epfx >> EPFX_VVVV_IDX) & 0xf) << 3) as u8;
582            self.buffer.put1(b2);
583        } else {
584            if opc & OPC_LOCK != 0 {
585                self.buffer.put1(0xF0);
586            }
587            if opc & OPC_66 != 0 {
588                self.buffer.put1(0x66);
589            }
590            if opc & OPC_F2 != 0 {
591                self.buffer.put1(0xF2);
592            }
593            if opc & OPC_F3 != 0 {
594                self.buffer.put1(0xF3);
595            }
596            if opc & OPC_REXW != 0 || epfx & EPFX_REX_MSK != 0 {
597                let mut rex = 0x40;
598                if opc & OPC_REXW != 0 {
599                    rex |= 0x08;
600                }
601                if epfx & EPFX_REXR != 0 {
602                    rex |= 0x04;
603                }
604                if epfx & EPFX_REXX != 0 {
605                    rex |= 0x02;
606                }
607                if epfx & EPFX_REXB != 0 {
608                    rex |= 0x01;
609                }
610                self.buffer.put1(rex);
611            }
612            if opc & 0x30000 != 0 {
613                self.buffer.put1(0x0F);
614            }
615            if opc & 0x30000 == 0x20000 {
616                self.buffer.put1(0x38);
617            }
618            if opc & 0x30000 == 0x30000 {
619                self.buffer.put1(0x3A);
620            }
621        }
622
623        self.buffer.put1((opc & 0xff) as u8);
624        if (opc & 0x8000) != 0 {
625            self.buffer.put1(((opc >> 8) & 0xff) as u8);
626        }
627        false
628    }
629
630    fn encode_imm(&mut self, imm: Operand, immsz: usize) -> bool {
631        if !op_imm_n(imm, immsz) {
632            self.last_error = Some(X86Error::InvalidImmediate {
633                value: imm.as_::<Imm>().value() as i64,
634                size: immsz,
635                reason: "immediate value does not fit in specified size",
636            });
637            return true;
638        }
639        let imm = imm.as_::<Imm>().value() as u64;
640        for i in 0..immsz {
641            self.buffer.put1((imm >> 8 * i) as u8);
642        }
643
644        false
645    }
646
647    fn enc_o(&mut self, opc: u64, mut epfx: u64, op0: Operand) -> bool {
648        if op0.id() & 0x8 != 0 {
649            epfx |= EPFX_REXB;
650        }
651
652        if self.enc_opc(opc, epfx) {
653            return true;
654        }
655
656        let ix = self.buffer.cur_offset() as usize - 1;
657        let byte = self.buffer.data()[ix];
658
659        self.buffer.data_mut()[ix] = (byte & 0xf8) | (op0.id() & 0x7) as u8;
660        false
661    }
662
663    fn enc_mr(
664        &mut self,
665        mut opc: u64,
666        mut epfx: u64,
667        op0: Operand,
668        op1: Operand,
669        immsz: usize,
670    ) -> bool {
671        if op0.is_reg() && op0.id() & 0x8 != 0 {
672            epfx |= EPFX_REXB;
673        }
674
675        if op0.is_reg() && op0.id() & 0x10 != 0 {
676            epfx |= EPFX_REXX | EPFX_EVEX;
677        }
678
679        if op0.is_mem() && op0.as_::<Mem>().base_id() & 0x8 != 0 {
680            epfx |= EPFX_REXB;
681        }
682
683        if op0.is_mem() && op0.as_::<Mem>().base_id() & 0x10 != 0 {
684            epfx |= EPFX_REXB4;
685        }
686
687        if op0.is_mem() && op0.as_::<Mem>().index_id() & 0x8 != 0 {
688            epfx |= EPFX_REXX;
689        }
690
691        if op0.is_mem() && op0.as_::<Mem>().index_id() & 0x10 != 0 {
692            epfx |= if opc & OPC_VSIB != 0 {
693                0x10 << EPFX_VVVV_IDX
694            } else {
695                EPFX_REXX4
696            };
697        }
698        if op1.is_reg() && op1.id() & 0x8 != 0 {
699            epfx |= EPFX_REXR;
700        }
701
702        if op1.is_reg() && op1.id() & 0x10 != 0 {
703            epfx |= EPFX_REXR4;
704        }
705
706        let has_rex =
707            (opc & (OPC_REXW | OPC_VEXL0 | OPC_EVEXL0) != 0) || (epfx & EPFX_REX_MSK) != 0;
708
709        if has_rex && (op0.is_reg_type_of(RegType::Gp8Hi) || op1.is_reg_type_of(RegType::Gp8Hi)) {
710            self.last_error = Some(X86Error::InvalidOperand {
711                operand_index: if op0.is_reg_type_of(RegType::Gp8Hi) {
712                    0
713                } else {
714                    1
715                },
716                reason: "high-byte registers cannot be used with REX prefix",
717            });
718            return true;
719        }
720
721        if epfx & (EPFX_EVEX | EPFX_REXB4 | EPFX_REXX4 | EPFX_REXR4 | (0x10 << EPFX_VVVV_IDX)) != 0
722        {
723            if (opc & OPC_EVEXL0) == 0 {
724                self.last_error = Some(X86Error::InvalidEVEX {
725                    field: "prefix",
726                    reason: "EVEX-specific bits set but EVEX prefix not present",
727                });
728                return true;
729            }
730        } else if opc & OPC_DOWNGRADE_VEX != 0 {
731            opc = (opc & !(OPC_EVEXL0 | OPC_EVEX_DISP8SCALE)) | OPC_VEXL0;
732            if opc & OPC_DOWNGRADE_VEX_FLIPW != 0 {
733                opc ^= OPC_REXW;
734            }
735        }
736
737        if op0.is_reg() {
738            if self.enc_opc(opc, epfx) {
739                return true;
740            }
741
742            self.buffer
743                .put1(0xc0 | ((op1.id() & 7) << 3) as u8 | (op0.id() & 7) as u8);
744            return false;
745        }
746
747        let opcsz = opc_size(opc, epfx);
748
749        let mut mod_ = 0;
750        let reg = op1.id() & 7;
751        let mut rm;
752        let mut scale = 0;
753        let mut idx = 4;
754        let mut base = 0;
755        let mut off = op0.as_::<Mem>().offset();
756        let mut withsib = opc & OPC_FORCE_SIB != 0;
757        let mem = op0.as_::<Mem>();
758
759        if mem.has_index() {
760            if opc & OPC_VSIB != 0 {
761                if mem.index_type() != RegType::X86Xmm {
762                    self.last_error = Some(X86Error::InvalidVSIB {
763                        index_reg: mem.index_id(),
764                        reason: "VSIB requires XMM register as index",
765                    });
766                    return true;
767                }
768
769                if opc & OPC_EVEXL0 != 0 && opc & OPC_MASK_MSK == 0 {
770                    self.last_error = Some(X86Error::InvalidMasking {
771                        mask_reg: 0,
772                        reason: "VSIB with EVEX requires masking",
773                    });
774                    return true;
775                }
776            } else {
777                if !matches!(mem.index_type(), RegType::Gp32 | RegType::Gp64) {
778                    self.last_error = Some(X86Error::InvalidMemoryOperand {
779                        base: Some(mem.base_id()),
780                        index: Some(mem.index_id()),
781                        scale: mem.shift() as _,
782                        offset: mem.offset(),
783                        reason: "index register must be Gp32 or Gp64",
784                    });
785                    return true;
786                }
787
788                if mem.index_id() == 4 {
789                    self.last_error = Some(X86Error::InvalidSIB {
790                        sib: 0,
791                        reason: "index register cannot be RSP/R12",
792                    });
793                    return true;
794                }
795            }
796
797            idx = mem.index_id() & 7;
798            let scalabs = mem.shift();
799            if scalabs & (scalabs.wrapping_sub(1)) != 0 {
800                self.last_error = Some(X86Error::InvalidSIB {
801                    sib: 0,
802                    reason: "scale must be 1, 2, 4, or 8",
803                });
804                return true;
805            }
806
807            scale = if scalabs & 0xA != 0 { 1 } else { 0 } | if scalabs & 0xC != 0 { 2 } else { 0 };
808            withsib = true;
809        }
810
811        let mut dispsz = 0;
812        let mut label_use = None;
813        let mut reloc = None;
814
815        if !mem.has_base() {
816            base = 5;
817            rm = 4;
818            dispsz = 4;
819        } else if mem.has_base_reg() && mem.base_reg().is_rip() {
820            rm = 5;
821            dispsz = 4;
822            off -= (opcsz + 5 + immsz) as i64;
823            if withsib {
824                self.last_error = Some(X86Error::InvalidRIPRelative {
825                    offset: off,
826                    reason: "RIP-relative addressing cannot be used with SIB",
827                });
828                return true;
829            }
830        } else if mem.has_base_label() {
831            rm = 5;
832            if withsib {
833                self.last_error = Some(X86Error::InvalidLabel {
834                    label_id: mem.base_id(),
835                    reason: "label base cannot be used with SIB",
836                });
837                return true;
838            }
839            dispsz = 4;
840            label_use = Some((mem.base_id(), LabelUse::X86JmpRel32));
841        } else if mem.has_base_sym() {
842            rm = 5;
843            if withsib {
844                self.last_error = Some(X86Error::InvalidSymbol {
845                    symbol_id: mem.base_id(),
846                    reason: "symbol base cannot be used with SIB",
847                });
848                return true;
849            }
850            dispsz = 4;
851            let sym = Sym::from_id(mem.base_id());
852            let distance = self.buffer.symbol_distance(sym);
853
854            if distance == RelocDistance::Near {
855                reloc = Some((sym, Reloc::X86PCRel4));
856            } else {
857                reloc = Some((sym, Reloc::X86GOTPCRel4))
858            }
859        } else {
860            if !matches!(mem.base_type(), RegType::Gp32 | RegType::Gp64) {
861                self.last_error = Some(X86Error::InvalidMemoryOperand {
862                    base: Some(mem.base_id()),
863                    index: Some(mem.index_id()),
864                    scale: mem.shift() as _,
865                    offset: mem.offset(),
866                    reason: "base register must be Gp32 or Gp64",
867                });
868                return true;
869            }
870
871            rm = mem.base_id() & 0x7;
872
873            if withsib || rm == 4 {
874                base = rm;
875                rm = 4;
876            }
877
878            if off != 0 {
879                let disp8scale = (opc & OPC_EVEX_DISP8SCALE) >> 39;
880
881                if (off & ((1 << (disp8scale)) - 1)) == 0
882                    && op_imm_n(*imm(off >> disp8scale).as_operand(), 1)
883                    && opc & LONG == 0
884                {
885                    mod_ = 0x40;
886                    dispsz = 1;
887                    off >>= disp8scale;
888                } else {
889                    mod_ = 0x80;
890                    dispsz = 1;
891                }
892            } else if rm == 5 {
893                mod_ = 0x40;
894                dispsz = 1;
895            }
896        }
897
898        if opcsz + 1 + (rm == 4) as usize + dispsz + immsz > 15 {
899            self.last_error = Some(X86Error::TooLongInstruction {
900                length: opcsz + 1 + (rm == 4) as usize + dispsz + immsz,
901                max_length: 15,
902            });
903            return true;
904        }
905
906        if self.enc_opc(opc, epfx) {
907            return true;
908        }
909
910        self.buffer.put1(mod_ as u8 | (reg << 3) as u8 | rm as u8);
911        if rm == 4 {
912            self.buffer
913                .put1((scale << 6) as u8 | (idx << 3) as u8 | base as u8);
914        }
915        let offset = self.buffer.cur_offset();
916        if let Some((label, label_use)) = label_use {
917            self.buffer
918                .use_label_at_offset(offset, Label::from_id(label), label_use);
919        }
920
921        if let Some((sym, reloc)) = reloc {
922            self.buffer
923                .add_reloc_at_offset(offset, reloc, RelocTarget::Sym(sym), -4);
924        }
925        self.encode_imm(*imm(off).as_operand(), dispsz)
926    }
927}
928
929impl<'a> Emitter for Assembler<'a> {
930    
931    fn emit(&mut self, opcode: i64, op0: &Operand, op1: &Operand, op2: &Operand, op3: &Operand) {
932        let mut opc = opcode as u64;
933        opc |= self.flags;
934        self.flags = 0;
935        let ops = &[*op0, *op1, *op2, *op3];
936
937        let mut epfx = 0;
938
939        if opc & OPC_GPH_OP0 != 0 && op0.is_reg() && op0.id() >= Gp::SP {
940            epfx |= EPFX_REX;
941        } else if opc & OPC_GPH_OP0 == 0 && op0.is_reg_type_of(RegType::Gp8Hi) {
942            self.last_error = Some(X86Error::InvalidRegister {
943                reg_id: op0.id(),
944                reg_type: "Gp8Hi",
945                reason: "high-byte register not allowed in this context",
946            });
947            return;
948        }
949
950        if opc & OPC_GPH_OP1 != 0 && op1.is_reg() && op1.id() >= Gp::SP {
951            epfx |= EPFX_REX;
952        } else if opc & OPC_GPH_OP1 == 0 && op1.is_reg_type_of(RegType::Gp8Hi) {
953            self.last_error = Some(X86Error::InvalidRegister {
954                reg_id: op1.id(),
955                reg_type: "Gp8Hi",
956                reason: "high-byte register not allowed in this context",
957            });
958            return;
959        }
960        let mut label_use = None;
961        let mut reloc = None;
962
963        loop {
964            macro_rules! next {
965                () => {
966                    let alt = opc >> 56;
967                    if alt != 0 {
968                        opc = ALT_TAB[alt as usize] as u64 | (opc & OPC_USER_MSK);
969                        continue;
970                    }
971                };
972            }
973
974            let enc = (opc >> 51) & 0x1f;
975            let ei = &ENCODING_INFOS[enc as usize];
976            let mut imm = 0xcci64;
977            let mut immsz = (opc >> 47) & 0xf;
978
979            if ei.zregidx != 0 && ops[ei.zregidx as usize ^ 3].id() != 0 {
980                next!();
981            }
982
983            if enc == Encoding::S as u64 {
984                if ((op0.id() as u64) << 3 & 0x20) != (opc & 0x20) {
985                    next!();
986                }
987
988                opc |= (op0.id() << 3) as u64;
989            }
990
991            if immsz != 0 {
992                imm = ops[ei.immidx as usize].as_::<Imm>().value() as i64;
993
994                if ei.immctl != 0 {
995                    if ei.immctl == 2 {
996                        immsz = if opc & OPC_67 != 0 { 4 } else { 8 };
997                        if immsz == 4 {
998                            imm = imm as i32 as i64; // addresses are zero-extended
999                        }
1000                    } else if ei.immctl == 3 {
1001                        if !ops[ei.immidx as usize].is_reg_type_of(RegType::X86Xmm) {
1002                            self.last_error = Some(X86Error::InvalidRegister {
1003                                reg_id: ops[ei.immidx as usize].id(),
1004                                reg_type: "X86Xmm",
1005                                reason: "expected XMM register for immediate encoding",
1006                            });
1007                            return;
1008                        }
1009                        imm = (ops[ei.immidx as usize].id() << 4) as i64;
1010                        if !op_imm_n(*crate::core::operand::imm(imm).as_operand(), 1) {
1011                            self.last_error = Some(X86Error::InvalidImmediate {
1012                                value: imm,
1013                                size: 1,
1014                                reason: "XMM register index does not fit in 1 byte",
1015                            });
1016                            return;
1017                        }
1018                    } else if ei.immctl == 1 {
1019                        if imm != 1 {
1020                            next!();
1021                        }
1022
1023                        immsz = 0;
1024                    }
1025                } else if enc == Encoding::D as u64 {
1026                    let has_alt = opc >> 56 != 0;
1027                    //let skip_to_alt = has_alt && opc & OPC_JMPL != 0;
1028                    let imm_op = ops[ei.immidx as usize];
1029                    if imm_op.is_label() {
1030                        if immsz == 1 && has_alt {
1031                            immsz = 4;
1032                            if opc & 0x80 != 0 {
1033                                opc -= 2;
1034                            } else {
1035                                opc += 0x10010;
1036                            }
1037                        } else if immsz == 1 {
1038                            self.last_error = Some(X86Error::InvalidLabel {
1039                                label_id: imm_op.id(),
1040                                reason: "label requires 32-bit displacement, 8-bit not supported",
1041                            });
1042                            return;
1043                        }
1044                        label_use = Some((imm_op.id(), LabelUse::X86JmpRel32));
1045                    } else if imm_op.is_sym() {
1046                        let sym = imm_op.as_::<Sym>();
1047                        if immsz == 1 && has_alt {
1048                            immsz = 4;
1049                            if opc & 0x80 != 0 {
1050                                opc -= 2;
1051                            } else {
1052                                opc += 0x10010;
1053                            }
1054                        } else if immsz == 1 {
1055                            self.last_error = Some(X86Error::InvalidSymbol {
1056                                symbol_id: sym.id(),
1057                                reason: "symbol requires 32-bit displacement, 8-bit not supported",
1058                            });
1059                            return;
1060                        }
1061
1062                        let distance = self.buffer.symbol_distance(sym);
1063                        reloc = Some((
1064                            sym,
1065                            if distance == RelocDistance::Near {
1066                                Reloc::X86PCRel4
1067                            } else {
1068                                Reloc::X86GOTPCRel4
1069                            },
1070                        ));
1071                    }
1072                } else {
1073                    if !op_imm_n(*crate::core::operand::imm(imm).as_operand(), immsz as _) {
1074                        next!();
1075                    }
1076                }
1077            }
1078
1079            if (opc & 0xfffffff) == 0x90 && ops[0].id() == 0 {
1080                next!();
1081            }
1082
1083            if enc == Encoding::R as u64 {
1084                if self.enc_mr(opc, epfx, Operand::new(), ops[0], immsz as _) {
1085                    return;
1086                }
1087            } else if ei.modrm != 0 {
1088                let modreg = if ei.modreg != 0 {
1089                    ops[ei.modreg as usize ^ 3]
1090                } else {
1091                    *crate::x86::operands::Reg::from_type_and_id(
1092                        RegType::Gp64,
1093                        ((opc & 0xff00) >> 8) as u32,
1094                    )
1095                    .as_operand()
1096                };
1097
1098                if ei.vexreg != 0 {
1099                    epfx |= (ops[ei.vexreg as usize ^ 3].id() as u64) << EPFX_VVVV_IDX;
1100                }
1101
1102                if self.enc_mr(opc, epfx, ops[(ei.modrm ^ 3) as usize], modreg, immsz as _) {
1103                    next!();
1104                }
1105            } else if ei.modreg != 0 {
1106                if self.enc_o(opc, epfx, ops[(ei.modreg ^ 3) as usize]) {
1107                    return;
1108                }
1109            } else {
1110                if self.enc_opc(opc, epfx) {
1111                    return;
1112                }
1113            }
1114
1115            if immsz != 0 {
1116                let offset = self.buffer.cur_offset();
1117                if let Some((sym, reloc)) = reloc {
1118                    self.buffer
1119                        .add_reloc_at_offset(offset, reloc, RelocTarget::Sym(sym), -4);
1120                }
1121                if let Some((label_id, label_use)) = label_use {
1122                    self.buffer
1123                        .use_label_at_offset(offset, Label::from_id(label_id), label_use);
1124                }
1125
1126                if self.encode_imm(*crate::core::operand::imm(imm).as_operand(), immsz as _) {
1127                    return;
1128                }
1129            }
1130
1131            self.flags = 0;
1132
1133            break;
1134        }
1135    }
1136}
1137
1138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1139pub enum CondCode {
1140    O = 0x0,
1141    NO = 0x1,
1142    C = 0x2,
1143    NC = 0x3,
1144    Z = 0x4,
1145    NZ = 0x5,
1146    BE = 0x6,
1147    A = 0x7,
1148    S = 0x8,
1149    NS = 0x9,
1150    P = 0xa,
1151
1152    NP = 0xb,
1153    L = 0xc,
1154    GE = 0xd,
1155    LE = 0xe,
1156    G = 0xf,
1157}
1158
1159impl CondCode {
1160    pub const B: Self = Self::C;
1161    pub const NAE: Self = Self::C;
1162    pub const AE: Self = Self::NC;
1163    pub const NB: Self = Self::NC;
1164    pub const E: Self = Self::Z;
1165    pub const NE: Self = Self::NZ;
1166    pub const NA: Self = Self::BE;
1167    pub const NBE: Self = Self::A;
1168    pub const PO: Self = Self::NP;
1169    pub const NGE: Self = Self::L;
1170    pub const NL: Self = Self::GE;
1171    pub const NG: Self = Self::LE;
1172    pub const NLE: Self = Self::G;
1173    pub const PE: Self = Self::P;
1174
1175    pub const fn code(self) -> u8 {
1176        self as u8
1177    }
1178
1179    pub fn invert(self) -> Self {
1180        match self {
1181            Self::O => Self::NO,
1182            Self::NO => Self::O,
1183            Self::C => Self::NC,
1184            Self::NC => Self::C,
1185            Self::Z => Self::NZ,
1186            Self::NZ => Self::Z,
1187            Self::BE => Self::A,
1188            Self::A => Self::BE,
1189            Self::S => Self::NS,
1190            Self::NS => Self::S,
1191            Self::P => Self::NP,
1192            Self::NP => Self::P,
1193            Self::L => Self::GE,
1194            Self::GE => Self::L,
1195            Self::LE => Self::G,
1196            Self::G => Self::LE,
1197        }
1198    }
1199}