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    core::{
7        buffer::{
8            CodeBuffer, CodeOffset, ConstantData, LabelUse, Reloc, RelocDistance, RelocTarget,
9        },
10        emitter::Emitter,
11        operand::*,
12        patch::{PatchBlockId, PatchSiteId},
13    },
14    X86Error,
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    fn emit(&mut self, opcode: i64, op0: &Operand, op1: &Operand, op2: &Operand, op3: &Operand) {
931        let mut opc = opcode as u64;
932        opc |= self.flags;
933        self.flags = 0;
934        let ops = &[*op0, *op1, *op2, *op3];
935
936        let mut epfx = 0;
937
938        if opc & OPC_GPH_OP0 != 0 && op0.is_reg() && op0.id() >= Gp::SP {
939            epfx |= EPFX_REX;
940        } else if opc & OPC_GPH_OP0 == 0 && op0.is_reg_type_of(RegType::Gp8Hi) {
941            self.last_error = Some(X86Error::InvalidRegister {
942                reg_id: op0.id(),
943                reg_type: "Gp8Hi",
944                reason: "high-byte register not allowed in this context",
945            });
946            return;
947        }
948
949        if opc & OPC_GPH_OP1 != 0 && op1.is_reg() && op1.id() >= Gp::SP {
950            epfx |= EPFX_REX;
951        } else if opc & OPC_GPH_OP1 == 0 && op1.is_reg_type_of(RegType::Gp8Hi) {
952            self.last_error = Some(X86Error::InvalidRegister {
953                reg_id: op1.id(),
954                reg_type: "Gp8Hi",
955                reason: "high-byte register not allowed in this context",
956            });
957            return;
958        }
959        let mut label_use = None;
960        let mut reloc = None;
961
962        loop {
963            macro_rules! next {
964                () => {
965                    let alt = opc >> 56;
966                    if alt != 0 {
967                        opc = ALT_TAB[alt as usize] as u64 | (opc & OPC_USER_MSK);
968                        continue;
969                    }
970                };
971            }
972
973            let enc = (opc >> 51) & 0x1f;
974            let ei = &ENCODING_INFOS[enc as usize];
975            let mut imm = 0xcci64;
976            let mut immsz = (opc >> 47) & 0xf;
977
978            if ei.zregidx != 0 && ops[ei.zregidx as usize ^ 3].id() != 0 {
979                next!();
980            }
981
982            if enc == Encoding::S as u64 {
983                if ((op0.id() as u64) << 3 & 0x20) != (opc & 0x20) {
984                    next!();
985                }
986
987                opc |= (op0.id() << 3) as u64;
988            }
989
990            if immsz != 0 {
991                imm = ops[ei.immidx as usize].as_::<Imm>().value() as i64;
992
993                if ei.immctl != 0 {
994                    if ei.immctl == 2 {
995                        immsz = if opc & OPC_67 != 0 { 4 } else { 8 };
996                        if immsz == 4 {
997                            imm = imm as i32 as i64; // addresses are zero-extended
998                        }
999                    } else if ei.immctl == 3 {
1000                        if !ops[ei.immidx as usize].is_reg_type_of(RegType::X86Xmm) {
1001                            self.last_error = Some(X86Error::InvalidRegister {
1002                                reg_id: ops[ei.immidx as usize].id(),
1003                                reg_type: "X86Xmm",
1004                                reason: "expected XMM register for immediate encoding",
1005                            });
1006                            return;
1007                        }
1008                        imm = (ops[ei.immidx as usize].id() << 4) as i64;
1009                        if !op_imm_n(*crate::core::operand::imm(imm).as_operand(), 1) {
1010                            self.last_error = Some(X86Error::InvalidImmediate {
1011                                value: imm,
1012                                size: 1,
1013                                reason: "XMM register index does not fit in 1 byte",
1014                            });
1015                            return;
1016                        }
1017                    } else if ei.immctl == 1 {
1018                        if imm != 1 {
1019                            next!();
1020                        }
1021
1022                        immsz = 0;
1023                    }
1024                } else if enc == Encoding::D as u64 {
1025                    let has_alt = opc >> 56 != 0;
1026                    //let skip_to_alt = has_alt && opc & OPC_JMPL != 0;
1027                    let imm_op = ops[ei.immidx as usize];
1028                    if imm_op.is_label() {
1029                        if immsz == 1 && has_alt {
1030                            immsz = 4;
1031                            if opc & 0x80 != 0 {
1032                                opc -= 2;
1033                            } else {
1034                                opc += 0x10010;
1035                            }
1036                        } else if immsz == 1 {
1037                            self.last_error = Some(X86Error::InvalidLabel {
1038                                label_id: imm_op.id(),
1039                                reason: "label requires 32-bit displacement, 8-bit not supported",
1040                            });
1041                            return;
1042                        }
1043                        label_use = Some((imm_op.id(), LabelUse::X86JmpRel32));
1044                    } else if imm_op.is_sym() {
1045                        let sym = imm_op.as_::<Sym>();
1046                        if immsz == 1 && has_alt {
1047                            immsz = 4;
1048                            if opc & 0x80 != 0 {
1049                                opc -= 2;
1050                            } else {
1051                                opc += 0x10010;
1052                            }
1053                        } else if immsz == 1 {
1054                            self.last_error = Some(X86Error::InvalidSymbol {
1055                                symbol_id: sym.id(),
1056                                reason: "symbol requires 32-bit displacement, 8-bit not supported",
1057                            });
1058                            return;
1059                        }
1060
1061                        let distance = self.buffer.symbol_distance(sym);
1062                        reloc = Some((
1063                            sym,
1064                            if distance == RelocDistance::Near {
1065                                Reloc::X86PCRel4
1066                            } else {
1067                                Reloc::X86GOTPCRel4
1068                            },
1069                        ));
1070                    }
1071                } else {
1072                    if !op_imm_n(*crate::core::operand::imm(imm).as_operand(), immsz as _) {
1073                        next!();
1074                    }
1075                }
1076            }
1077
1078            if (opc & 0xfffffff) == 0x90 && ops[0].id() == 0 {
1079                next!();
1080            }
1081
1082            if enc == Encoding::R as u64 {
1083                if self.enc_mr(opc, epfx, Operand::new(), ops[0], immsz as _) {
1084                    return;
1085                }
1086            } else if ei.modrm != 0 {
1087                let modreg = if ei.modreg != 0 {
1088                    ops[ei.modreg as usize ^ 3]
1089                } else {
1090                    *crate::x86::operands::Reg::from_type_and_id(
1091                        RegType::Gp64,
1092                        ((opc & 0xff00) >> 8) as u32,
1093                    )
1094                    .as_operand()
1095                };
1096
1097                if ei.vexreg != 0 {
1098                    epfx |= (ops[ei.vexreg as usize ^ 3].id() as u64) << EPFX_VVVV_IDX;
1099                }
1100
1101                if self.enc_mr(opc, epfx, ops[(ei.modrm ^ 3) as usize], modreg, immsz as _) {
1102                    next!();
1103                }
1104            } else if ei.modreg != 0 {
1105                if self.enc_o(opc, epfx, ops[(ei.modreg ^ 3) as usize]) {
1106                    return;
1107                }
1108            } else {
1109                if self.enc_opc(opc, epfx) {
1110                    return;
1111                }
1112            }
1113
1114            if immsz != 0 {
1115                let offset = self.buffer.cur_offset();
1116                if let Some((sym, reloc)) = reloc {
1117                    self.buffer
1118                        .add_reloc_at_offset(offset, reloc, RelocTarget::Sym(sym), -4);
1119                }
1120                if let Some((label_id, label_use)) = label_use {
1121                    self.buffer
1122                        .use_label_at_offset(offset, Label::from_id(label_id), label_use);
1123                }
1124
1125                if self.encode_imm(*crate::core::operand::imm(imm).as_operand(), immsz as _) {
1126                    return;
1127                }
1128            }
1129
1130            self.flags = 0;
1131
1132            break;
1133        }
1134    }
1135}
1136
1137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1138pub enum CondCode {
1139    O = 0x0,
1140    NO = 0x1,
1141    C = 0x2,
1142    NC = 0x3,
1143    Z = 0x4,
1144    NZ = 0x5,
1145    BE = 0x6,
1146    A = 0x7,
1147    S = 0x8,
1148    NS = 0x9,
1149    P = 0xa,
1150
1151    NP = 0xb,
1152    L = 0xc,
1153    GE = 0xd,
1154    LE = 0xe,
1155    G = 0xf,
1156}
1157
1158impl CondCode {
1159    pub const B: Self = Self::C;
1160    pub const NAE: Self = Self::C;
1161    pub const AE: Self = Self::NC;
1162    pub const NB: Self = Self::NC;
1163    pub const E: Self = Self::Z;
1164    pub const NE: Self = Self::NZ;
1165    pub const NA: Self = Self::BE;
1166    pub const NBE: Self = Self::A;
1167    pub const PO: Self = Self::NP;
1168    pub const NGE: Self = Self::L;
1169    pub const NL: Self = Self::GE;
1170    pub const NG: Self = Self::LE;
1171    pub const NLE: Self = Self::G;
1172    pub const PE: Self = Self::P;
1173
1174    pub const fn code(self) -> u8 {
1175        self as u8
1176    }
1177
1178    pub fn invert(self) -> Self {
1179        match self {
1180            Self::O => Self::NO,
1181            Self::NO => Self::O,
1182            Self::C => Self::NC,
1183            Self::NC => Self::C,
1184            Self::Z => Self::NZ,
1185            Self::NZ => Self::Z,
1186            Self::BE => Self::A,
1187            Self::A => Self::BE,
1188            Self::S => Self::NS,
1189            Self::NS => Self::S,
1190            Self::P => Self::NP,
1191            Self::NP => Self::P,
1192            Self::L => Self::GE,
1193            Self::GE => Self::L,
1194            Self::LE => Self::G,
1195            Self::G => Self::LE,
1196        }
1197    }
1198}