1#![allow(non_camel_case_types)]
2
3use crate::misc::{FixupKind, InstBuf, Instruction, Label};
4
5const REX: u8 = 0x40;
7const REX_64B_OP: u8 = REX | (1 << 3);
8const REX_EXT_MODRM_REG: u8 = REX | (1 << 2);
9const REX_EXT_MODRM_SIB_INDEX: u8 = REX | (1 << 1);
10const REX_EXT_MODRM_RM: u8 = REX | (1 << 0);
11
12const PREFIX_REP: u8 = 0xf3;
13const PREFIX_OVERRIDE_SEGMENT_FS: u8 = 0x64;
14const PREFIX_OVERRIDE_SEGMENT_GS: u8 = 0x65;
15const PREFIX_OVERRIDE_OP_SIZE: u8 = 0x66;
16const PREFIX_OVERRIDE_ADDR_SIZE: u8 = 0x67;
17
18#[derive(Copy, Clone, PartialEq, Eq, Debug)]
19pub enum Reg {
20 rax = 0,
21 rcx = 1,
22 rdx = 2,
23 rbx = 3,
24 rsp = 4,
25 rbp = 5,
26 rsi = 6,
27 rdi = 7,
28 r8 = 8,
29 r9 = 9,
30 r10 = 10,
31 r11 = 11,
32 r12 = 12,
33 r13 = 13,
34 r14 = 14,
35 r15 = 15,
36}
37
38impl Reg {
39 pub const fn is_reg_preserved(self) -> bool {
40 use Reg::*;
42 match self {
43 rbx | rsp | rbp | r12 | r13 | r14 | r15 => true,
44 rax | rcx | rdx | rsi | rdi | r8 | r9 | r10 | r11 => false,
45 }
46 }
47
48 #[inline]
49 pub const fn needs_rex(self) -> bool {
50 self as usize >= Reg::r8 as usize
51 }
52
53 #[inline]
54 pub const fn modrm_rm_bits(self) -> u8 {
55 (self as usize & 0b111) as u8
56 }
57
58 #[inline]
59 pub const fn modrm_reg_bits(self) -> u8 {
60 (((self as usize) << 3) & 0b111000) as u8
61 }
62
63 #[inline]
64 pub const fn rex_bit(self) -> u8 {
65 if self as usize >= Reg::r8 as usize {
66 REX_EXT_MODRM_RM
67 } else {
68 0
69 }
70 }
71
72 #[inline]
73 pub const fn rex_modrm_reg(self) -> u8 {
74 if self as usize >= Reg::r8 as usize {
75 REX_EXT_MODRM_REG
76 } else {
77 0
78 }
79 }
80
81 pub const fn name_from(self, size: RegSize) -> &'static str {
82 match size {
83 RegSize::R64 => self.name(),
84 RegSize::R32 => self.name32(),
85 }
86 }
87
88 pub const fn name_from_size(self, kind: Size) -> &'static str {
89 match kind {
90 Size::U64 => self.name(),
91 Size::U32 => self.name32(),
92 Size::U16 => self.name16(),
93 Size::U8 => self.name8(),
94 }
95 }
96}
97
98impl core::fmt::Display for Reg {
99 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
100 fmt.write_str(self.name())
101 }
102}
103
104macro_rules! impl_regs {
105 ($(($r64:ident, $r32:ident, $r16:ident, $r8:ident)),+) => {
106 impl Reg {
107 pub const fn name(self) -> &'static str {
108 match self {
109 $(
110 Reg::$r64 => stringify!($r64),
111 )+
112 }
113 }
114
115 pub const fn name32(self) -> &'static str {
116 match self {
117 $(
118 Reg::$r64 => stringify!($r32),
119 )+
120 }
121 }
122
123 pub const fn name16(self) -> &'static str {
124 match self {
125 $(
126 Reg::$r64 => stringify!($r16),
127 )+
128 }
129 }
130
131 pub const fn name8(self) -> &'static str {
132 match self {
133 $(
134 Reg::$r64 => stringify!($r8),
135 )+
136 }
137 }
138 }
139 };
140}
141
142impl_regs! {
143 (rax, eax, ax, al),
144 (rcx, ecx, cx, cl),
145 (rdx, edx, dx, dl),
146 (rbx, ebx, bx, bl),
147 (rsp, esp, sp, spl),
148 (rbp, ebp, bp, bpl),
149 (rsi, esi, si, sil),
150 (rdi, edi, di, dil),
151 (r8, r8d, r8w, r8b),
152 (r9, r9d, r9w, r9b),
153 (r10, r10d, r10w, r10b),
154 (r11, r11d, r11w, r11b),
155 (r12, r12d, r12w, r12b),
156 (r13, r13d, r13w, r13b),
157 (r14, r14d, r14w, r14b),
158 (r15, r15d, r15w, r15b)
159}
160
161#[derive(Copy, Clone, PartialEq, Eq, Debug)]
162pub enum RegIndex {
163 rax = 0,
164 rcx = 1,
165 rdx = 2,
166 rbx = 3,
167 rbp = 5,
169 rsi = 6,
170 rdi = 7,
171 r8 = 8,
172 r9 = 9,
173 r10 = 10,
174 r11 = 11,
175 r12 = 12,
176 r13 = 13,
177 r14 = 14,
178 r15 = 15,
179}
180
181impl From<RegIndex> for Reg {
182 #[inline]
183 fn from(reg: RegIndex) -> Reg {
184 reg.into_reg()
185 }
186}
187
188impl RegIndex {
189 #[inline]
190 pub const fn into_reg(self) -> Reg {
191 match self {
192 RegIndex::rax => Reg::rax,
193 RegIndex::rcx => Reg::rcx,
194 RegIndex::rdx => Reg::rdx,
195 RegIndex::rbx => Reg::rbx,
196 RegIndex::rbp => Reg::rbp,
197 RegIndex::rsi => Reg::rsi,
198 RegIndex::rdi => Reg::rdi,
199 RegIndex::r8 => Reg::r8,
200 RegIndex::r9 => Reg::r9,
201 RegIndex::r10 => Reg::r10,
202 RegIndex::r11 => Reg::r11,
203 RegIndex::r12 => Reg::r12,
204 RegIndex::r13 => Reg::r13,
205 RegIndex::r14 => Reg::r14,
206 RegIndex::r15 => Reg::r15,
207 }
208 }
209 pub const fn name(self) -> &'static str {
210 self.into_reg().name()
211 }
212
213 pub const fn name32(self) -> &'static str {
214 self.into_reg().name32()
215 }
216
217 pub const fn name16(self) -> &'static str {
218 self.into_reg().name16()
219 }
220
221 pub const fn name8(self) -> &'static str {
222 self.into_reg().name8()
223 }
224
225 pub const fn name_from(self, size: RegSize) -> &'static str {
226 match size {
227 RegSize::R64 => self.name(),
228 RegSize::R32 => self.name32(),
229 }
230 }
231
232 #[inline]
233 pub const fn equals(self, other: Self) -> bool {
234 (self as u8) == (other as u8)
235 }
236}
237
238impl core::fmt::Display for RegIndex {
239 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
240 let reg: Reg = (*self).into();
241 reg.fmt(fmt)
242 }
243}
244
245#[derive(Copy, Clone, PartialEq, Eq, Debug)]
246pub enum SegReg {
247 fs,
248 gs,
249}
250
251impl core::fmt::Display for SegReg {
252 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
253 let name = match *self {
254 Self::fs => "fs",
255 Self::gs => "gs",
256 };
257 fmt.write_str(name)
258 }
259}
260
261#[derive(Copy, Clone, PartialEq, Eq, Debug)]
262pub enum Scale {
263 x1 = 0,
264 x2 = 1,
265 x4 = 2,
266 x8 = 3,
267}
268
269#[derive(Copy, Clone, PartialEq, Eq, Debug)]
270pub enum MemOp {
271 BaseOffset(Option<SegReg>, RegSize, Reg, i32),
273 BaseIndexScaleOffset(Option<SegReg>, RegSize, Reg, RegIndex, Scale, i32),
275 IndexScaleOffset(Option<SegReg>, RegSize, RegIndex, Scale, i32),
277 Offset(Option<SegReg>, RegSize, i32),
279 RipRelative(Option<SegReg>, i32),
281}
282
283#[derive(Copy, Clone, PartialEq, Eq, Debug)]
284pub enum RegMem {
285 Reg(Reg),
286 Mem(MemOp),
287}
288
289#[derive(Copy, Clone, PartialEq, Eq, Debug)]
290pub enum Operands {
291 RegMem_Reg(Size, RegMem, Reg),
292 Reg_RegMem(Size, Reg, RegMem),
293 RegMem_Imm(RegMem, ImmKind),
294}
295
296impl MemOp {
297 #[inline]
298 const fn needs_rex(self) -> bool {
299 match self {
300 MemOp::BaseOffset(_, _, base, _) => base.needs_rex(),
301 MemOp::BaseIndexScaleOffset(_, _, base, index, _, _) => base.needs_rex() || index.into_reg().needs_rex(),
302 MemOp::IndexScaleOffset(_, _, index, _, _) => index.into_reg().needs_rex(),
303 MemOp::Offset(..) => false,
304 MemOp::RipRelative(..) => false,
305 }
306 }
307
308 #[inline]
309 const fn simplify(self) -> Self {
310 match self {
311 MemOp::IndexScaleOffset(segment, reg_size, index, Scale::x1, offset) => {
313 MemOp::BaseOffset(segment, reg_size, index.into_reg(), offset)
314 }
315 operand => operand,
316 }
317 }
318}
319
320impl core::fmt::Display for MemOp {
321 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
322 let (segment, base, index, offset_reg_size, offset) = match self.simplify() {
323 MemOp::BaseOffset(segment, reg_size, base, offset) => (segment, Some((reg_size, base)), None, reg_size, offset),
324 MemOp::BaseIndexScaleOffset(segment, reg_size, base, index, scale, offset) => {
325 (segment, Some((reg_size, base)), Some((reg_size, index, scale)), reg_size, offset)
326 }
327 MemOp::IndexScaleOffset(segment, reg_size, index, scale, offset) => {
328 (segment, None, Some((reg_size, index, scale)), reg_size, offset)
329 }
330 MemOp::Offset(segment, reg_size, offset) => (segment, None, None, reg_size, offset),
331 MemOp::RipRelative(segment, offset) => {
332 fmt.write_str("[")?;
333 if let Some(segment) = segment {
334 fmt.write_fmt(core::format_args!("{}:", segment))?;
335 }
336
337 fmt.write_str("rip")?;
338 if offset != 0 {
339 if offset > 0 {
340 fmt.write_fmt(core::format_args!("+0x{:x}", offset))?;
341 } else {
342 fmt.write_fmt(core::format_args!("-0x{:x}", -i64::from(offset)))?;
343 }
344 }
345
346 return fmt.write_str("]");
347 }
348 };
349
350 fmt.write_str("[")?;
351 if let Some(segment) = segment {
352 fmt.write_fmt(core::format_args!("{}:", segment))?;
353 }
354
355 if let Some((reg_size, base)) = base {
356 base.name_from(reg_size).fmt(fmt)?;
357 }
358
359 if let Some((reg_size, index, scale)) = index {
360 if base.is_some() {
361 fmt.write_str("+")?;
362 }
363
364 index.name_from(reg_size).fmt(fmt)?;
365 match scale {
366 Scale::x1 if base.is_some() => {}
367 Scale::x1 => fmt.write_str("*1")?,
368 Scale::x2 => fmt.write_str("*2")?,
369 Scale::x4 => fmt.write_str("*4")?,
370 Scale::x8 => fmt.write_str("*8")?,
371 }
372 }
373
374 if offset != 0 || (base.is_none() && index.is_none()) {
375 if base.is_some() || index.is_some() {
376 if offset > 0 {
377 fmt.write_fmt(core::format_args!("+0x{:x}", offset))?;
378 } else if offset_reg_size == RegSize::R32 {
379 if let Some(offset) = offset.checked_neg() {
380 fmt.write_fmt(core::format_args!("-0x{:x}", offset))?;
381 } else {
382 fmt.write_fmt(core::format_args!("-0x{:x}", offset as u32))?;
383 }
384 } else {
385 fmt.write_fmt(core::format_args!("-0x{:x}", -i64::from(offset)))?;
386 }
387 } else if offset_reg_size == RegSize::R32 {
388 fmt.write_fmt(core::format_args!("0x{:x}", offset))?;
389 } else {
390 fmt.write_fmt(core::format_args!("0x{:x}", i64::from(offset)))?;
391 }
392 }
393
394 fmt.write_str("]")
395 }
396}
397
398impl RegMem {
399 fn display_without_prefix(self, size: Size) -> impl core::fmt::Display {
400 struct Impl(Size, RegMem);
401
402 impl core::fmt::Display for Impl {
403 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
404 match self.1 {
405 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("{}", reg.name_from_size(self.0))),
406 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("{}", mem)),
407 }
408 }
409 }
410
411 Impl(size, self)
412 }
413
414 fn display(self, size: Size) -> impl core::fmt::Display {
415 struct Impl(Size, RegMem);
416
417 impl core::fmt::Display for Impl {
418 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
419 match self.1 {
420 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("{}", reg.name_from_size(self.0))),
421 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("{} {}", self.0.name(), mem)),
422 }
423 }
424 }
425
426 Impl(size, self)
427 }
428}
429
430impl From<Reg> for RegMem {
431 #[inline]
432 fn from(reg: Reg) -> Self {
433 RegMem::Reg(reg)
434 }
435}
436
437impl From<RegIndex> for RegMem {
438 #[inline]
439 fn from(reg: RegIndex) -> Self {
440 RegMem::Reg(reg.into())
441 }
442}
443
444impl From<MemOp> for RegMem {
445 #[inline]
446 fn from(mem: MemOp) -> Self {
447 RegMem::Mem(mem)
448 }
449}
450
451struct Inst {
452 op_rep_prefix: bool,
453 override_op_size: bool,
454 override_addr_size: bool,
455 op_alt: bool,
456 force_enable_modrm: bool,
457 rex: u8,
458 opcode: u8,
459 modrm: u8,
460 sib: u8,
461 displacement: u32,
462 displacement_length: u32,
463 immediate: u32,
464 immediate_length: u32,
465 override_segment: Option<SegReg>,
466}
467
468impl Inst {
470 #[inline]
471 const fn new(opcode: u8) -> Self {
472 Inst {
473 op_rep_prefix: false,
474 override_op_size: false,
475 override_addr_size: false,
476 op_alt: false,
477 force_enable_modrm: false,
478 rex: 0,
479 opcode,
480 modrm: 0,
481 sib: 0,
482 displacement: 0,
483 displacement_length: 0,
484 immediate: 0,
485 immediate_length: 0,
486 override_segment: None,
487 }
488 }
489
490 #[inline]
491 const fn with_reg_in_op(opcode: u8, reg: Reg) -> Self {
492 Inst::new(opcode | reg.modrm_rm_bits()).rex_from_reg(reg)
493 }
494
495 #[inline]
496 const fn op_rep_prefix(mut self) -> Self {
497 self.op_rep_prefix = true;
498 self
499 }
500
501 #[inline]
502 const fn override_op_size(mut self) -> Self {
503 self.override_op_size = true;
504 self
505 }
506
507 #[inline]
508 const fn override_addr_size_if(mut self, cond: bool) -> Self {
509 if cond {
510 self.override_addr_size = true;
511 }
512 self
513 }
514
515 #[inline]
516 const fn op_alt(mut self) -> Self {
517 self.op_alt = true;
518 self
519 }
520
521 #[inline]
522 const fn rex(mut self) -> Self {
523 self.rex |= REX;
524 self
525 }
526
527 #[inline]
528 const fn rex_if(mut self, cond: bool) -> Self {
529 if cond {
530 self = self.rex();
531 }
532 self
533 }
534
535 #[inline]
536 const fn rex_from_reg(mut self, reg: Reg) -> Self {
537 if reg.needs_rex() {
538 self.rex |= REX_EXT_MODRM_RM;
539 }
540 self
541 }
542
543 #[inline]
544 const fn rex_64b(mut self) -> Self {
545 self.rex |= REX_64B_OP;
546 self
547 }
548
549 #[inline]
550 const fn rex_64b_if(mut self, cond: bool) -> Self {
551 if cond {
552 self.rex |= REX_64B_OP;
553 }
554 self
555 }
556
557 #[inline]
558 const fn modrm_rm_direct(mut self, value: Reg) -> Self {
559 if value.needs_rex() {
560 self.rex |= REX_EXT_MODRM_RM;
561 }
562 self.modrm |= value.modrm_rm_bits() | 0b11000000;
563 self
564 }
565
566 #[inline(always)]
567 const fn regmem(self, operand: RegMem) -> Self {
568 match operand {
569 RegMem::Reg(reg) => self.modrm_rm_direct(reg),
570 RegMem::Mem(mem) => self.mem(mem),
571 }
572 }
573
574 #[cfg_attr(not(debug_assertions), inline(always))]
575 const fn mem(mut self, operand: MemOp) -> Self {
576 match operand.simplify() {
577 MemOp::BaseOffset(segment, reg_size, base, offset) => {
578 self.force_enable_modrm = true;
579
580 if base.needs_rex() {
581 self.rex |= REX_EXT_MODRM_RM;
582 }
583
584 if matches!(base, Reg::rsp | Reg::r12) {
585 self.sib = 0b00100100;
586 }
587
588 self.modrm |= base.modrm_rm_bits();
589
590 let set_displacement = (offset != 0) | matches!(base, Reg::rbp | Reg::r13);
591 let set_displacement_mask = (-(set_displacement as i32)) as u32;
592 if offset <= i8::MAX as i32 && offset >= i8::MIN as i32 {
593 self.modrm |= 0b01000000 & set_displacement_mask as u8;
594 self.displacement = (offset as u8 as u32) & set_displacement_mask;
595 self.displacement_length = 8 & set_displacement_mask;
596 } else {
597 self.modrm |= 0b10000000 & set_displacement_mask as u8;
598 self.displacement = (offset as u32) & set_displacement_mask;
599 self.displacement_length = 32 & set_displacement_mask;
600 }
601
602 self.override_segment = segment;
603 self.override_addr_size_if(matches!(reg_size, RegSize::R32))
604 }
605 MemOp::BaseIndexScaleOffset(segment, reg_size, base, index, scale, offset) => {
606 if base.needs_rex() {
607 self.rex |= REX_EXT_MODRM_RM;
608 }
609
610 if index.into_reg().needs_rex() {
611 self.rex |= REX_EXT_MODRM_SIB_INDEX;
612 }
613
614 self.modrm |= 0b00000100;
615 self.sib |= index.into_reg().modrm_reg_bits();
616 self.sib |= base.modrm_rm_bits();
617 self.sib |= ((scale as usize) << 6) as u8;
618
619 let set_displacement = (offset != 0) | matches!(base, Reg::rbp | Reg::r13);
620 let set_displacement_mask = (-(set_displacement as i32)) as u32;
621 if offset <= i8::MAX as i32 && offset >= i8::MIN as i32 {
622 self.modrm |= 0b01000000 & set_displacement_mask as u8;
623 self.displacement = (offset as u8 as u32) & set_displacement_mask;
624 self.displacement_length = 8 & set_displacement_mask;
625 } else {
626 self.modrm |= 0b10000000 & set_displacement_mask as u8;
627 self.displacement = (offset as u32) & set_displacement_mask;
628 self.displacement_length = 32 & set_displacement_mask;
629 }
630
631 self.override_segment = segment;
632 self.override_addr_size_if(matches!(reg_size, RegSize::R32))
633 }
634 MemOp::IndexScaleOffset(segment, reg_size, index, scale, offset) => {
635 if index.into_reg().needs_rex() {
636 self.rex |= REX_EXT_MODRM_SIB_INDEX;
637 }
638
639 self.modrm |= 0b00000100;
640 self.sib |= index.into_reg().modrm_reg_bits();
641 self.sib |= 0b00000101;
642 self.sib |= ((scale as usize) << 6) as u8;
643 self.displacement = offset as u32;
644 self.displacement_length = 32;
645 self.override_segment = segment;
646 self.override_addr_size_if(matches!(reg_size, RegSize::R32))
647 }
648 MemOp::Offset(segment, reg_size, offset) => {
649 self.modrm |= 0b00000100;
650 self.sib |= 0b00100101;
651 self.displacement = offset as u32;
652 self.displacement_length = 32;
653 self.override_segment = segment;
654 self.override_addr_size_if(matches!(reg_size, RegSize::R32) && offset < 0)
655 }
656 MemOp::RipRelative(segment, offset) => {
657 self.modrm |= 0b00000101;
658 self.displacement = offset as u32;
659 self.displacement_length = 32;
660 self.override_segment = segment;
661 self
662 }
663 }
664 }
665
666 #[inline]
667 const fn modrm_reg(mut self, value: Reg) -> Self {
668 if value.needs_rex() {
669 self.rex |= REX_EXT_MODRM_REG;
670 }
671 self.modrm |= value.modrm_reg_bits();
672 self.force_enable_modrm = true;
673 self
674 }
675
676 #[inline]
677 const fn modrm_opext(mut self, ext: u8) -> Self {
678 self.modrm |= ext << 3;
679 self.force_enable_modrm = true;
680 self
681 }
682
683 #[inline]
684 const fn imm8(mut self, value: u8) -> Self {
685 self.immediate = value as u32;
686 self.immediate_length = 8;
687 self
688 }
689
690 #[inline]
691 const fn imm16(mut self, value: u16) -> Self {
692 self.immediate = value as u32;
693 self.immediate_length = 16;
694 self
695 }
696
697 #[inline]
698 const fn imm32(mut self, value: u32) -> Self {
699 self.immediate = value;
700 self.immediate_length = 32;
701 self
702 }
703
704 #[inline]
705 fn encode(self) -> InstBuf {
706 let mut enc = InstBuf::new();
707 self.encode_into(&mut enc);
708 enc
709 }
710
711 #[inline(always)]
712 fn encode_into(self, buf: &mut InstBuf) {
713 if self.op_rep_prefix {
714 buf.append(PREFIX_REP);
715 }
716
717 match self.override_segment {
718 Some(SegReg::fs) => buf.append(PREFIX_OVERRIDE_SEGMENT_FS),
719 Some(SegReg::gs) => buf.append(PREFIX_OVERRIDE_SEGMENT_GS),
720 None => {}
721 }
722
723 if self.override_op_size {
724 buf.append(PREFIX_OVERRIDE_OP_SIZE);
725 }
726
727 if self.override_addr_size {
728 buf.append(PREFIX_OVERRIDE_ADDR_SIZE);
729 }
730
731 if self.rex != 0 {
732 buf.append(self.rex);
733 }
734
735 if self.op_alt {
736 buf.append(0x0f);
737 }
738
739 buf.append(self.opcode);
740
741 if self.modrm != 0 || self.force_enable_modrm {
742 buf.append(self.modrm);
743 if self.modrm & 0b11000000 != 0b11000000 && self.modrm & 0b111 == 0b100 {
744 buf.append(self.sib);
745 }
746 }
747
748 buf.append_packed_bytes(self.displacement, self.displacement_length);
749 buf.append_packed_bytes(self.immediate, self.immediate_length);
750 }
751}
752
753macro_rules! impl_inst {
754 (@generate_test_values $cb:expr, $name:ident, $arg0:ty, $arg1:ty, $arg2:ty, $arg3:ty, $arg4:ty, $arg5:ty) => {
755 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
756 <$arg1 as super::tests::GenerateTestValues>::generate_test_values(|arg1|
757 <$arg2 as super::tests::GenerateTestValues>::generate_test_values(|arg2|
758 <$arg3 as super::tests::GenerateTestValues>::generate_test_values(|arg3|
759 <$arg4 as super::tests::GenerateTestValues>::generate_test_values(|arg4|
760 <$arg5 as super::tests::GenerateTestValues>::generate_test_values(|arg5|
761 $cb($name(arg0, arg1, arg2, arg3, arg4, arg5))
762 )
763 )
764 )
765 )
766 )
767 )
768 };
769
770 (@generate_test_values $cb:expr, $name:ident, $arg0:ty, $arg1:ty, $arg2:ty, $arg3:ty, $arg4:ty) => {
771 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
772 <$arg1 as super::tests::GenerateTestValues>::generate_test_values(|arg1|
773 <$arg2 as super::tests::GenerateTestValues>::generate_test_values(|arg2|
774 <$arg3 as super::tests::GenerateTestValues>::generate_test_values(|arg3|
775 <$arg4 as super::tests::GenerateTestValues>::generate_test_values(|arg4|
776 $cb($name(arg0, arg1, arg2, arg3, arg4))
777 )
778 )
779 )
780 )
781 )
782 };
783
784 (@generate_test_values $cb:expr, $name:ident, $arg0:ty, $arg1:ty, $arg2:ty, $arg3:ty) => {
785 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
786 <$arg1 as super::tests::GenerateTestValues>::generate_test_values(|arg1|
787 <$arg2 as super::tests::GenerateTestValues>::generate_test_values(|arg2|
788 <$arg3 as super::tests::GenerateTestValues>::generate_test_values(|arg3|
789 $cb($name(arg0, arg1, arg2, arg3))
790 )
791 )
792 )
793 )
794 };
795
796 (@generate_test_values $cb:expr, $name:ident, $arg0:ty, $arg1:ty, $arg2:ty) => {
797 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
798 <$arg1 as super::tests::GenerateTestValues>::generate_test_values(|arg1|
799 <$arg2 as super::tests::GenerateTestValues>::generate_test_values(|arg2|
800 $cb($name(arg0, arg1, arg2))
801 )
802 )
803 )
804 };
805
806 (@generate_test_values $cb:expr, $name:ident, $arg0:ty, $arg1:ty) => {
807 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
808 <$arg1 as super::tests::GenerateTestValues>::generate_test_values(|arg1|
809 $cb($name(arg0, arg1))
810 )
811 )
812 };
813
814 (@generate_test_values $cb:expr, $name:ident, $arg0:ty) => {
815 <$arg0 as super::tests::GenerateTestValues>::generate_test_values(|arg0|
816 $cb($name(arg0))
817 )
818 };
819
820 (@generate_test_values $cb:expr, $name:ident,) => {
821 $cb($name())
822 };
823
824 (@impl |$self:ident, $fmt:ident| $($name:ident($($arg:ty),*) => $body:expr, $fixup:expr, ($fmt_body:expr),)+) => {
825 pub(crate) mod types {
826 use super::*;
827 $(
828 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
829 pub struct $name($(pub $arg),*);
830
831 impl core::fmt::Display for $name {
832 fn fmt(&$self, $fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
833 $fmt_body
834 }
835 }
836
837 impl $name {
838 #[inline(always)]
839 pub fn encode($self) -> InstBuf {
840 $body
841 }
842
843 #[inline(always)]
844 pub(crate) fn fixup($self) -> Option<(Label, FixupKind)> {
845 $fixup
846 }
847 }
848
849 #[cfg(feature = "alloc")]
850 #[cfg(test)]
851 impl super::tests::GenerateTestValues for $name {
852 fn generate_test_values(mut cb: impl FnMut(Self)) {
853 impl_inst!(@generate_test_values cb, $name, $($arg),*);
854 }
855 }
856 )+
857 }
858 };
859
860 (@conv_ty i8) => {
861 i8
862 };
863
864 (@conv_ty i32) => {
865 i32
866 };
867
868 (@conv_ty Label) => {
869 Label
870 };
871
872 (@conv_ty $type:ty) => {
873 impl Into<$type>
874 };
875
876 (@ctor_impl $name:ident, $(($arg_name:ident: $arg_ty:tt)),*) => {
877 #[inline(always)]
878 pub fn $name($($arg_name: impl_inst!(@conv_ty $arg_ty)),*) -> Instruction<types::$name> {
879 let instruction = self::types::$name($($arg_name.into()),*);
880 Instruction {
881 instruction,
882 bytes: instruction.encode(),
883 fixup: instruction.fixup(),
884 }
885 }
886 };
887
888 (@ctor $name:ident,) => {
889 impl_inst!(@ctor_impl $name,);
890 };
891
892 (@ctor $name:ident, $a0:tt) => {
893 impl_inst!(@ctor_impl $name, (a0: $a0));
894 };
895
896 (@ctor $name:ident, $a0:tt, $a1:tt) => {
897 impl_inst!(@ctor_impl $name, (a0: $a0), (a1: $a1));
898 };
899
900 (@ctor $name:ident, $a0:tt, $a1:tt, $a2:tt) => {
901 impl_inst!(@ctor_impl $name, (a0: $a0), (a1: $a1), (a2: $a2));
902 };
903
904 (@ctor $name:ident, $a0:tt, $a1:tt, $a2:tt, $a3:tt) => {
905 impl_inst!(@ctor_impl $name, (a0: $a0), (a1: $a1), (a2: $a2), (a3: $a3));
906 };
907
908 (|$self:ident, $fmt:ident| $($name:ident($($arg:tt),*) => $body:expr, $fixup:expr, ($fmt_body:expr),)+) => {
909 impl_inst!(@impl |$self, $fmt| $($name($($arg),*) => $body, $fixup, ($fmt_body),)+);
910 $(
911 impl_inst!(@ctor $name, $($arg),*);
912 )+
913 };
914}
915
916pub mod addr {
917 use super::*;
918
919 impl core::ops::Add<i32> for Reg {
920 type Output = (Reg, i32);
921
922 #[inline]
923 fn add(self, offset: i32) -> Self::Output {
924 (self, offset)
925 }
926 }
927
928 impl core::ops::Add<i32> for RegIndex {
929 type Output = (RegIndex, i32);
930
931 #[inline]
932 fn add(self, offset: i32) -> Self::Output {
933 (self, offset)
934 }
935 }
936
937 impl core::ops::Sub<i32> for Reg {
938 type Output = (Reg, i32);
939
940 #[inline]
941 fn sub(self, offset: i32) -> Self::Output {
942 (self, -offset)
943 }
944 }
945
946 impl core::ops::Sub<i32> for RegIndex {
947 type Output = (RegIndex, i32);
948
949 #[inline]
950 fn sub(self, offset: i32) -> Self::Output {
951 (self, -offset)
952 }
953 }
954
955 pub trait IntoMemOp {
956 #[doc(hidden)]
957 fn into_mem_op(self, segment: Option<SegReg>, reg_size: RegSize) -> MemOp;
958 }
959
960 impl IntoMemOp for Reg {
961 #[doc(hidden)]
962 #[inline]
963 fn into_mem_op(self, segment: Option<SegReg>, reg_size: RegSize) -> MemOp {
964 MemOp::BaseOffset(segment, reg_size, self, 0)
965 }
966 }
967
968 impl IntoMemOp for RegIndex {
969 #[doc(hidden)]
970 #[inline]
971 fn into_mem_op(self, segment: Option<SegReg>, reg_size: RegSize) -> MemOp {
972 MemOp::BaseOffset(segment, reg_size, self.into(), 0)
973 }
974 }
975
976 impl IntoMemOp for (Reg, i32) {
977 #[doc(hidden)]
978 #[inline]
979 fn into_mem_op(self, segment: Option<SegReg>, reg_size: RegSize) -> MemOp {
980 MemOp::BaseOffset(segment, reg_size, self.0, self.1)
981 }
982 }
983
984 impl IntoMemOp for (RegIndex, i32) {
985 #[doc(hidden)]
986 #[inline]
987 fn into_mem_op(self, segment: Option<SegReg>, reg_size: RegSize) -> MemOp {
988 MemOp::BaseOffset(segment, reg_size, self.0.into(), self.1)
989 }
990 }
991
992 #[inline]
993 pub fn reg_indirect(reg_size: RegSize, op: impl IntoMemOp) -> MemOp {
994 op.into_mem_op(None, reg_size)
995 }
996
997 #[inline]
998 pub fn abs(reg_size: RegSize, offset: i32) -> MemOp {
999 MemOp::Offset(None, reg_size, offset)
1000 }
1001
1002 #[inline]
1003 pub fn base_index(reg_size: RegSize, base: impl Into<Reg>, index: RegIndex) -> MemOp {
1004 MemOp::BaseIndexScaleOffset(None, reg_size, base.into(), index, Scale::x1, 0)
1005 }
1006
1007 impl From<(RegSize, Reg, Reg)> for Operands {
1008 #[inline]
1009 fn from((reg_size, dst, src): (RegSize, Reg, Reg)) -> Self {
1010 Self::RegMem_Reg(reg_size.into(), RegMem::Reg(dst), src)
1011 }
1012 }
1013
1014 impl From<(RegSize, RegIndex, RegIndex)> for Operands {
1015 #[inline]
1016 fn from((reg_size, dst, src): (RegSize, RegIndex, RegIndex)) -> Self {
1017 Self::RegMem_Reg(reg_size.into(), RegMem::Reg(dst.into()), src.into())
1018 }
1019 }
1020
1021 impl From<(RegSize, MemOp, RegIndex)> for Operands {
1022 #[inline]
1023 fn from((reg_size, dst, src): (RegSize, MemOp, RegIndex)) -> Self {
1024 Self::RegMem_Reg(reg_size.into(), RegMem::Mem(dst), src.into())
1025 }
1026 }
1027
1028 impl From<(RegSize, Reg, MemOp)> for Operands {
1029 #[inline]
1030 fn from((reg_size, dst, src): (RegSize, Reg, MemOp)) -> Self {
1031 Self::Reg_RegMem(reg_size.into(), dst, src.into())
1032 }
1033 }
1034
1035 impl From<(RegSize, RegIndex, MemOp)> for Operands {
1036 #[inline]
1037 fn from((reg_size, dst, src): (RegSize, RegIndex, MemOp)) -> Self {
1038 Self::Reg_RegMem(reg_size.into(), dst.into(), src.into())
1039 }
1040 }
1041
1042 impl From<(Reg, ImmKind)> for Operands {
1043 #[inline]
1044 fn from((dst, imm): (Reg, ImmKind)) -> Self {
1045 Self::RegMem_Imm(RegMem::Reg(dst), imm)
1046 }
1047 }
1048
1049 impl From<(RegIndex, ImmKind)> for Operands {
1050 #[inline]
1051 fn from((dst, imm): (RegIndex, ImmKind)) -> Self {
1052 Self::RegMem_Imm(RegMem::Reg(dst.into()), imm)
1053 }
1054 }
1055
1056 impl From<(MemOp, ImmKind)> for Operands {
1057 #[inline]
1058 fn from((dst, imm): (MemOp, ImmKind)) -> Self {
1059 Self::RegMem_Imm(RegMem::Mem(dst), imm)
1060 }
1061 }
1062
1063 #[inline]
1064 pub fn imm8(value: u8) -> ImmKind {
1065 ImmKind::I8(value)
1066 }
1067
1068 #[inline]
1069 pub fn imm16(value: u16) -> ImmKind {
1070 ImmKind::I16(value)
1071 }
1072
1073 #[inline]
1074 pub fn imm32(value: u32) -> ImmKind {
1075 ImmKind::I32(value)
1076 }
1077
1078 #[inline]
1079 pub fn imm64(value: i32) -> ImmKind {
1080 ImmKind::I64(value)
1081 }
1082}
1083
1084pub mod inst {
1085 use super::*;
1086 use crate::misc::InstBuf;
1087
1088 #[inline(always)]
1089 const fn new_rm(op: u8, size: Size, regmem: RegMem, reg: Option<Reg>) -> Inst {
1090 let inst = match size {
1091 Size::U8 => {
1092 let force_rex = (match regmem {
1093 RegMem::Mem(_) => false,
1094 RegMem::Reg(reg) => !matches!(reg, Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx),
1095 }) || (if let Some(reg) = reg {
1096 !matches!(reg, Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)
1097 } else {
1098 false
1099 });
1100 Inst::new(op).rex_if(force_rex)
1101 }
1102 Size::U16 => Inst::new(op + 1).override_op_size(),
1103 Size::U32 => Inst::new(op + 1),
1104 Size::U64 => Inst::new(op + 1).rex_64b(),
1105 }
1106 .regmem(regmem);
1107
1108 if let Some(reg) = reg {
1109 inst.modrm_reg(reg)
1110 } else {
1111 inst
1112 }
1113 }
1114
1115 #[inline(always)]
1116 const fn new_rm_imm(op: u8, regmem: RegMem, imm: ImmKind) -> Inst {
1117 let inst = new_rm(op, imm.size(), regmem, None);
1118 match imm {
1119 ImmKind::I8(imm) => inst.imm8(imm),
1120 ImmKind::I16(imm) => inst.imm16(imm),
1121 ImmKind::I32(imm) => inst.imm32(imm),
1122 ImmKind::I64(imm) => inst.imm32(imm as u32),
1123 }
1124 }
1125
1126 #[inline(always)]
1127 fn alu_impl(op_reg2rm: u8, op_rm2reg: u8, opext: u8, operands: Operands) -> InstBuf {
1128 match operands {
1129 Operands::RegMem_Reg(size, dst, src) => new_rm(op_reg2rm, size, dst, Some(src)).encode(),
1130 Operands::Reg_RegMem(size, dst, src) => new_rm(op_rm2reg, size, src, Some(dst)).encode(),
1131 Operands::RegMem_Imm(dst, imm) => match imm {
1132 ImmKind::I8(imm) => Inst::new(0x80)
1133 .rex_if(!matches!(dst, RegMem::Reg(Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)))
1134 .imm8(imm),
1135
1136 ImmKind::I16(value) => {
1137 if value as i16 <= i16::from(i8::MAX) && value as i16 >= i16::from(i8::MIN) {
1140 Inst::new(0x83).imm8(value as u8)
1141 } else {
1142 Inst::new(0x81).imm16(value)
1143 }
1144 .override_op_size()
1145 }
1146 ImmKind::I32(value) => {
1147 if value as i32 <= i32::from(i8::MAX) && value as i32 >= i32::from(i8::MIN) {
1148 Inst::new(0x83).imm8(value as u8)
1149 } else {
1150 Inst::new(0x81).imm32(value)
1151 }
1152 }
1153 ImmKind::I64(value) => if value <= i32::from(i8::MAX) && value >= i32::from(i8::MIN) {
1154 Inst::new(0x83).imm8(value as u8)
1155 } else {
1156 Inst::new(0x81).imm32(value as u32)
1157 }
1158 .rex_64b(),
1159 }
1160 .modrm_opext(opext)
1161 .regmem(dst)
1162 .encode(),
1163 }
1164 }
1165
1166 fn display_with_operands(fmt: &mut core::fmt::Formatter, inst_name: &str, operands: Operands) -> core::fmt::Result {
1167 fmt.write_str(inst_name)?;
1168 fmt.write_str(" ")?;
1169
1170 match operands {
1171 Operands::RegMem_Reg(reg_size, dst, src) => match dst {
1172 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("{}, {}", mem, src.name_from_size(reg_size))),
1173 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!(
1174 "{}, {}",
1175 reg.name_from_size(reg_size),
1176 src.name_from_size(reg_size)
1177 )),
1178 },
1179 Operands::Reg_RegMem(reg_size, dst, src) => match src {
1180 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("{}, {}", dst.name_from_size(reg_size), mem)),
1181 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!(
1182 "{}, {}",
1183 dst.name_from_size(reg_size),
1184 reg.name_from_size(reg_size)
1185 )),
1186 },
1187 Operands::RegMem_Imm(dst, imm) => {
1188 if matches!(dst, RegMem::Mem(..)) {
1189 fmt.write_str(imm.size().name())?;
1190 fmt.write_str(" ")?;
1191 }
1192
1193 fmt.write_fmt(core::format_args!("{}, {imm}", dst.display_without_prefix(imm.size())))
1194 }
1195 }
1196 }
1197
1198 impl_inst! { |self, fmt|
1199 ud2() =>
1200 InstBuf::from_array([0x0f, 0x0b]),
1201 None,
1202 (fmt.write_str("ud2")),
1203
1204 endbr64() =>
1206 InstBuf::from_array([0xf3, 0x0f, 0x1e, 0xfa]),
1207 None,
1208 (fmt.write_str("endbr64")),
1209
1210 syscall() =>
1212 InstBuf::from_array([0x0f, 0x05]),
1213 None,
1214 (fmt.write_str("syscall")),
1215
1216 push(Reg) =>
1218 Inst::with_reg_in_op(0x50, self.0).encode(),
1219 None,
1220 (fmt.write_fmt(core::format_args!("push {}", self.0))),
1221
1222 push_imm(i32) =>
1223 {
1224 let value = self.0;
1225 if value <= i32::from(i8::MAX) && value >= i32::from(i8::MIN) {
1226 Inst::new(0x6a).imm8(value as u8).rex_64b()
1227 } else {
1228 Inst::new(0x68).imm32(value as u32).rex_64b()
1229 }.encode()
1230 },
1231 None,
1232 (fmt.write_fmt(core::format_args!("push 0x{:x}", i64::from(self.0)))),
1233
1234 pop(Reg) =>
1236 Inst::with_reg_in_op(0x58, self.0).encode(),
1237 None,
1238 (fmt.write_fmt(core::format_args!("pop {}", self.0))),
1239
1240 nop() =>
1242 InstBuf::from_array([0x90]),
1243 None,
1244 (fmt.write_str("nop")),
1245
1246 nop2() =>
1247 InstBuf::from_array([0x66, 0x90]),
1248 None,
1249 (fmt.write_str("xchg ax, ax")),
1250
1251 nop3() =>
1252 InstBuf::from_array([0x0f, 0x1f, 0x00]),
1253 None,
1254 (fmt.write_str("nop dword [rax]")),
1255
1256 nop4() =>
1257 InstBuf::from_array([0x0f, 0x1f, 0x40, 0x00]),
1258 None,
1259 (fmt.write_str("nop dword [rax]")),
1260
1261 nop5() =>
1262 InstBuf::from_array([0x0f, 0x1f, 0x44, 0x00, 0x00]),
1263 None,
1264 (fmt.write_str("nop dword [rax+rax]")),
1265
1266 nop6() =>
1267 InstBuf::from_array([0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00]),
1268 None,
1269 (fmt.write_str("nop word [rax+rax]")),
1270
1271 nop7() =>
1272 InstBuf::from_array([0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00]),
1273 None,
1274 (fmt.write_str("nop dword [rax]")), nop8() =>
1277 InstBuf::from_array([0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1278 None,
1279 (fmt.write_str("nop dword [rax+rax]")),
1280
1281 nop9() =>
1282 InstBuf::from_array([0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1283 None,
1284 (fmt.write_str("nop word [rax+rax]")), nop10() =>
1287 InstBuf::from_array([0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1288 None,
1289 (fmt.write_str("nop word [cs:rax+rax]")),
1290
1291 nop11() =>
1292 InstBuf::from_array([0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1293 None,
1294 (fmt.write_str("nop word [cs:rax+rax]")),
1295
1296 clflushopt(MemOp) =>
1298 Inst::new(0xae).override_op_size().op_alt().modrm_opext(0b111).mem(self.0).encode(),
1299 None,
1300 (fmt.write_fmt(core::format_args!("clflushopt {}", self.0))),
1301
1302 ret() =>
1304 InstBuf::from_array([0xc3]),
1305 None,
1306 (fmt.write_str("ret")),
1307
1308 mov(RegSize, Reg, Reg) =>
1312 Inst::new(0x89).rex_64b_if(matches!(self.0, RegSize::R64)).modrm_rm_direct(self.1).modrm_reg(self.2).encode(),
1313 None,
1314 (fmt.write_fmt(core::format_args!("mov {}, {}", self.1.name_from(self.0), self.2.name_from(self.0)))),
1315
1316 movsx_8_to_64(RegSize, Reg, Reg) =>
1317 Inst::new(0xbe).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1318 None,
1319 (fmt.write_fmt(core::format_args!("movsx {}, {}", self.1.name(), self.2.name8()))),
1320
1321 movsx_16_to_64(RegSize, Reg, Reg) =>
1322 Inst::new(0xbf).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1323 None,
1324 (fmt.write_fmt(core::format_args!("movsx {}, {}", self.1.name(), self.2.name16()))),
1325
1326 movzx_16_to_64(RegSize, Reg, Reg) =>
1327 Inst::new(0xb7).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1328 None,
1329 (fmt.write_fmt(core::format_args!("movzx {}, {}", self.1.name(), self.2.name16()))),
1330
1331 movsxd_32_to_64(Reg, Reg) =>
1332 Inst::new(0x63).rex_64b().modrm_rm_direct(self.1).modrm_reg(self.0).encode(),
1333 None,
1334 (fmt.write_fmt(core::format_args!("movsxd {}, {}", self.0.name(), self.1.name32()))),
1335
1336 mov_imm64(Reg, u64) =>
1337 {
1338 if self.1 <= 0x7fffffff {
1339 mov_imm(RegMem::Reg(self.0), ImmKind::I32(self.1 as u32)).encode()
1340 } else {
1341 let xs = self.1.to_le_bytes();
1342 InstBuf::from_array([
1343 REX_64B_OP | self.0.rex_bit(),
1344 0xb8 | self.0.modrm_rm_bits(),
1345 xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6], xs[7]
1346 ])
1347 }
1348 },
1349 None,
1350 ({
1351 if self.1 <= 0x7fffffff {
1352 mov_imm(RegMem::Reg(self.0), ImmKind::I32(self.1 as u32)).fmt(fmt)
1353 } else {
1354 fmt.write_fmt(core::format_args!("mov {}, 0x{:x}", self.0, self.1))
1355 }
1356 }),
1357
1358 mov_imm(RegMem, ImmKind) =>
1359 {
1360 match self.0 {
1361 RegMem::Mem(..) => new_rm_imm(0xc6, self.0, self.1).encode(),
1362 RegMem::Reg(reg) => {
1363 match self.1 {
1364 ImmKind::I8(value) => Inst::with_reg_in_op(0xb0, reg).imm8(value).rex_if(!matches!(reg, Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)),
1365 ImmKind::I16(value) => Inst::with_reg_in_op(0xb8, reg).imm16(value).override_op_size(),
1366 ImmKind::I32(value) => Inst::with_reg_in_op(0xb8, reg).imm32(value),
1367 ImmKind::I64(..) => new_rm_imm(0xc6, self.0, self.1),
1368 }.encode()
1369 }
1370 }
1371 },
1372 None,
1373 (display_with_operands(fmt, "mov", Operands::RegMem_Imm(self.0, self.1))),
1374
1375 store(Size, MemOp, Reg) =>
1376 new_rm(0x88, self.0, RegMem::Mem(self.1), Some(self.2)).encode(),
1377 None,
1378 (fmt.write_fmt(core::format_args!("mov {}, {}", self.1, self.2.name_from_size(self.0)))),
1379
1380 load(LoadKind, Reg, MemOp) =>
1381 {
1382 let inst = match self.0 {
1383 LoadKind::U8 | LoadKind::U16 | LoadKind::I8 | LoadKind::I16 => {
1384 let op = match self.0 {
1385 LoadKind::U8 => 0xb6,
1386 LoadKind::I8 => 0xbe,
1387 LoadKind::U16 => 0xb7,
1388 LoadKind::I16 => 0xbf,
1389 | LoadKind::I32
1390 | LoadKind::U32
1391 | LoadKind::U64
1392 => unreachable!()
1393 };
1394
1395 Inst::new(op)
1396 .op_alt()
1397 .rex_64b_if(!(matches!(self.0, LoadKind::U8 | LoadKind::U16) && !self.1.needs_rex() && !self.2.needs_rex()))
1399 },
1400 LoadKind::I32 => Inst::new(0x63).rex_64b(),
1401 LoadKind::U32 => Inst::new(0x8b),
1402 LoadKind::U64 => Inst::new(0x8b).rex_64b()
1403 };
1404
1405 inst
1406 .modrm_reg(self.1)
1407 .mem(self.2)
1408 .encode()
1409 },
1410 None,
1411 ({
1412 let (name, kind, size) = match self.0 {
1413 LoadKind::U8 if !self.1.needs_rex() && !self.2.needs_rex() => (self.1.name32(), "zx", "byte "),
1414 LoadKind::U16 if !self.1.needs_rex() && !self.2.needs_rex() => (self.1.name32(), "zx", "word "),
1415 LoadKind::U8 => (self.1.name(), "zx", "byte "),
1416 LoadKind::I8 => (self.1.name(), "sx", "byte "),
1417 LoadKind::U16 => (self.1.name(), "zx", "word "),
1418 LoadKind::U32 => (self.1.name32(), "", ""),
1419 LoadKind::I16 => (self.1.name(), "sx", "word "),
1420 LoadKind::I32 => (self.1.name(), "sxd", ""),
1421 LoadKind::U64 => (self.1.name(), "", ""),
1422 };
1423
1424 fmt.write_fmt(core::format_args!("mov{} {}, {}{}", kind, name, size, self.2))
1425 }),
1426
1427 cmov(Condition, RegSize, Reg, RegMem) =>
1429 {
1430 Inst::new(0x40 | self.0 as u8)
1431 .op_alt()
1432 .rex_64b_if(matches!(self.1, RegSize::R64))
1433 .modrm_reg(self.2)
1434 .regmem(self.3)
1435 .encode()
1436 },
1437 None,
1438 (fmt.write_fmt(core::format_args!("cmov{} {}, {}", self.0.suffix(), self.2.name_from(self.1), self.3.display_without_prefix(Size::from(self.1))))),
1439
1440 xchg_mem(RegSize, Reg, MemOp) =>
1442 Inst::new(0x87).rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).mem(self.2).encode(),
1443 None,
1444 (fmt.write_fmt(core::format_args!("xchg {}, {}", self.1.name_from(self.0), self.2))),
1445
1446 add(Operands) =>
1448 alu_impl(0x00, 0x02, 0b000, self.0),
1449 None,
1450 (display_with_operands(fmt, "add", self.0)),
1451
1452 inc(Size, RegMem) =>
1454 new_rm(0xfe, self.0, self.1, None).encode(),
1455 None,
1456 (fmt.write_fmt(core::format_args!("inc {}", self.1.display(self.0)))),
1457
1458 dec(Size, RegMem) =>
1460 new_rm(0xfe, self.0, self.1, None).modrm_opext(0b001).encode(),
1461 None,
1462 (fmt.write_fmt(core::format_args!("dec {}", self.1.display(self.0)))),
1463
1464 sub(Operands) =>
1466 alu_impl(0x28, 0x2a, 0b101, self.0),
1467 None,
1468 (display_with_operands(fmt, "sub", self.0)),
1469
1470 or(Operands) =>
1472 alu_impl(0x08, 0x0a, 0b001, self.0),
1473 None,
1474 (display_with_operands(fmt, "or", self.0)),
1475
1476 and(Operands) =>
1478 alu_impl(0x20, 0x22, 0b100, self.0),
1479 None,
1480 (display_with_operands(fmt, "and", self.0)),
1481
1482 xor(Operands) =>
1484 alu_impl(0x30, 0x32, 0b110, self.0),
1485 None,
1486 (display_with_operands(fmt, "xor", self.0)),
1487
1488 bts(RegSize, RegMem, u8) =>
1490 Inst::new(0xba).op_alt().modrm_opext(0b101).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).imm8(self.2).encode(),
1491 None,
1492 ({
1493 match self.0 {
1494 RegSize::R64 => fmt.write_fmt(core::format_args!("bts {}, 0x{:x}", self.1.display(Size::from(self.0)), i64::from(self.2))),
1495 RegSize::R32 => fmt.write_fmt(core::format_args!("bts {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2)),
1496 }
1497 }),
1498
1499 neg(Size, RegMem) =>
1501 new_rm(0xf6, self.0, self.1, None).modrm_opext(0b011).encode(),
1502 None,
1503 (fmt.write_fmt(core::format_args!("neg {}", self.1.display(self.0)))),
1504
1505 not(Size, RegMem) =>
1507 new_rm(0xf6, self.0, self.1, None).modrm_opext(0b010).encode(),
1508 None,
1509 (fmt.write_fmt(core::format_args!("not {}", self.1.display(self.0)))),
1510
1511 cmp(Operands) =>
1513 alu_impl(0x38, 0x3a, 0b111, self.0),
1514 None,
1515 (display_with_operands(fmt, "cmp", self.0)),
1516
1517 sar_cl(RegSize, RegMem) =>
1519 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b111).encode(),
1520 None,
1521 (fmt.write_fmt(core::format_args!("sar {}, cl", self.1.display(Size::from(self.0))))),
1522
1523 sar_imm(RegSize, RegMem, u8) =>
1524 {
1525 if self.2 == 1 {
1526 Inst::new(0xd1)
1527 } else {
1528 Inst::new(0xc1).imm8(self.2)
1529 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b111).encode()
1530 },
1531 None,
1532 (fmt.write_fmt(core::format_args!("sar {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1533
1534 shl_cl(RegSize, RegMem) =>
1535 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b100).encode(),
1536 None,
1537 (fmt.write_fmt(core::format_args!("shl {}, cl", self.1.display(Size::from(self.0))))),
1538
1539 shl_imm(RegSize, RegMem, u8) =>
1540 {
1541 if self.2 == 1 {
1542 Inst::new(0xd1)
1543 } else {
1544 Inst::new(0xc1).imm8(self.2)
1545 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b100).encode()
1546 },
1547 None,
1548 (fmt.write_fmt(core::format_args!("shl {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1549
1550 shr_cl(RegSize, RegMem) =>
1551 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b101).encode(),
1552 None,
1553 (fmt.write_fmt(core::format_args!("shr {}, cl", self.1.display(Size::from(self.0))))),
1554
1555 shr_imm(RegSize, RegMem, u8) =>
1556 {
1557 if self.2 == 1 {
1558 Inst::new(0xd1)
1559 } else {
1560 Inst::new(0xc1).imm8(self.2)
1561 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b101).encode()
1562 },
1563 None,
1564 (fmt.write_fmt(core::format_args!("shr {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1565
1566 ror_imm(RegSize, RegMem, u8) =>
1568 {
1569 if self.2 == 1 {
1570 Inst::new(0xd1)
1571 } else {
1572 Inst::new(0xc1).imm8(self.2)
1573 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b001).encode()
1574 },
1575 None,
1576 (fmt.write_fmt(core::format_args!("ror {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1577
1578 rol_cl(RegSize, RegMem) =>
1579 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b000).encode(),
1580 None,
1581 (fmt.write_fmt(core::format_args!("rol {}, cl", self.1.display(Size::from(self.0))))),
1582
1583 ror_cl(RegSize, RegMem) =>
1584 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b001).encode(),
1585 None,
1586 (fmt.write_fmt(core::format_args!("ror {}, cl", self.1.display(Size::from(self.0))))),
1587
1588 rcr_imm(RegSize, RegMem, u8) =>
1589 {
1590 if self.2 == 1 {
1591 Inst::new(0xd1)
1592 } else {
1593 Inst::new(0xc1).imm8(self.2)
1594 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b011).encode()
1595 },
1596 None,
1597 (fmt.write_fmt(core::format_args!("rcr {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1598
1599 popcnt(RegSize, Reg, RegMem) =>
1601 {
1602 Inst::new(0xb8)
1603 .op_rep_prefix()
1604 .op_alt()
1605 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1606 },
1607 None,
1608 (fmt.write_fmt(core::format_args!("popcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1609
1610 lzcnt(RegSize, Reg, RegMem) =>
1612 {
1613 Inst::new(0xbd)
1614 .op_rep_prefix()
1615 .op_alt()
1616 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1617 },
1618 None,
1619 (fmt.write_fmt(core::format_args!("lzcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1620
1621 tzcnt(RegSize, Reg, RegMem) =>
1623 {
1624 Inst::new(0xbc)
1625 .op_rep_prefix()
1626 .op_alt()
1627 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1628 },
1629 None,
1630 (fmt.write_fmt(core::format_args!("tzcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1631
1632 bswap(RegSize, Reg) =>
1634 {
1635 Inst::with_reg_in_op(0xc8, self.1)
1636 .op_alt()
1637 .rex_64b_if(matches!(self.0, RegSize::R64)).encode()
1638 },
1639 None,
1640 (fmt.write_fmt(core::format_args!("bswap {}", self.1.name_from(self.0)))),
1641
1642 test(Operands) =>
1644 {
1645 match self.0 {
1646 Operands::RegMem_Reg(size, regmem, reg) |
1647 Operands::Reg_RegMem(size, reg, regmem) => new_rm(0x84, size, regmem, Some(reg)).encode(),
1648 Operands::RegMem_Imm(regmem, imm) => new_rm_imm(0xf6, regmem, imm).encode(),
1649 }
1650 },
1651 None,
1652 ({
1653 let operands = match self.0 {
1654 Operands::Reg_RegMem(size, reg, regmem) => Operands::RegMem_Reg(size, regmem, reg),
1655 operands => operands
1656 };
1657
1658 display_with_operands(fmt, "test", operands)
1659 }),
1660
1661 imul(RegSize, Reg, RegMem) =>
1663 Inst::new(0xaf).op_alt().rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode(),
1664 None,
1665 (fmt.write_fmt(core::format_args!("imul {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1666
1667 imul_imm(RegSize, Reg, RegMem, i32) =>
1668 {
1669 let value = self.3;
1670 if value <= i32::from(i8::MAX) && value >= i32::from(i8::MIN) {
1671 Inst::new(0x6b).imm8(value as u8)
1672 } else {
1673 Inst::new(0x69).imm32(value as u32)
1674 }.rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1675 },
1676 None,
1677 ({
1678 struct DisplaySignExtend(RegSize, i32);
1679 impl core::fmt::Display for DisplaySignExtend {
1680 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1681 let value = match self.0 {
1682 RegSize::R64 => i64::from(self.1) as u64,
1683 RegSize::R32 => u64::from(self.1 as u32),
1684 };
1685
1686 fmt.write_fmt(core::format_args!("0x{:x}", value))
1687 }
1688
1689 }
1690
1691 if RegMem::Reg(self.1) == self.2 {
1692 fmt.write_fmt(core::format_args!("imul {}, {}", self.1.name_from(self.0), DisplaySignExtend(self.0, self.3)))
1693 } else {
1694 fmt.write_fmt(core::format_args!("imul {}, {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0)), DisplaySignExtend(self.0, self.3)))
1695 }
1696 }),
1697
1698 imul_dx_ax(RegSize, RegMem) =>
1699 Inst::new(0xf7).modrm_opext(0b101).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1700 None,
1701 (fmt.write_fmt(core::format_args!("imul {}", self.1.display(Size::from(self.0))))),
1702
1703 mul(RegSize, RegMem) =>
1705 Inst::new(0xf7).modrm_opext(0b100).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1706 None,
1707 (fmt.write_fmt(core::format_args!("mul {}", self.1.display(Size::from(self.0))))),
1708
1709 mul_dx_ax(RegSize, RegMem) =>
1710 Inst::new(0xf7).modrm_opext(0b100).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1711 None,
1712 (fmt.write_fmt(core::format_args!("mul {}", self.1.display(Size::from(self.0))))),
1713
1714 div(RegSize, RegMem) =>
1716 Inst::new(0xf7).modrm_opext(0b110).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1717 None,
1718 (fmt.write_fmt(core::format_args!("div {}", self.1.display(Size::from(self.0))))),
1719
1720 idiv(RegSize, RegMem) =>
1722 Inst::new(0xf7).modrm_opext(0b111).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1723 None,
1724 (fmt.write_fmt(core::format_args!("idiv {}", self.1.display(Size::from(self.0))))),
1725
1726 cdq() =>
1728 Inst::new(0x99).encode(),
1729 None,
1730 (fmt.write_str("cdq")),
1731
1732 cqo() =>
1733 Inst::new(0x99).rex_64b().encode(),
1734 None,
1735 (fmt.write_str("cqo")),
1736
1737 setcc(Condition, RegMem) =>
1739 {
1740 Inst::new(0x90 | self.0 as u8)
1741 .rex_if(!matches!(self.1, RegMem::Reg(Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)))
1742 .op_alt()
1743 .regmem(self.1)
1744 .encode()
1745 },
1746 None,
1747 (fmt.write_fmt(core::format_args!("set{} {}", self.0.suffix(), self.1.display_without_prefix(Size::U8)))),
1748
1749 lea(RegSize, Reg, MemOp) =>
1751 Inst::new(0x8d)
1752 .rex_64b_if(matches!(self.0, RegSize::R64))
1753 .modrm_reg(self.1)
1754 .mem(self.2).encode(),
1755 None,
1756 (fmt.write_fmt(core::format_args!("lea {}, {}", self.1.name_from(self.0), self.2))),
1757
1758 mfence() =>
1760 InstBuf::from_array([0x0f, 0xae, 0xf0]),
1761 None,
1762 (fmt.write_str("mfence")),
1763
1764 lfence() =>
1766 InstBuf::from_array([0x0f, 0xae, 0xe8]),
1767 None,
1768 (fmt.write_str("lfence")),
1769
1770 rdtscp() =>
1772 InstBuf::from_array([0x0f, 0x01, 0xf9]),
1773 None,
1774 (fmt.write_str("rdtscp")),
1775
1776 rdpmc() =>
1778 InstBuf::from_array([0x0f, 0x33]),
1779 None,
1780 (fmt.write_str("rdpmc")),
1781
1782 cpuid() =>
1784 InstBuf::from_array([0x0f, 0xa2]),
1785 None,
1786 (fmt.write_str("cpuid")),
1787
1788 call(RegMem) => {
1790 Inst::new(0xff).modrm_opext(0b010).regmem(self.0).encode()
1791 },
1792 None,
1793 ({
1794 match self.0 {
1795 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("call {}", reg)),
1796 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("call qword {}", mem)),
1797 }
1798 }),
1799
1800 call_rel32(i32) =>
1801 Inst::new(0xe8).imm32(self.0 as u32).encode(),
1802 None,
1803 (fmt.write_fmt(core::format_args!("call 0x{:x}", i64::from(self.0).wrapping_add(5)))),
1804
1805 jmp(RegMem) => {
1807 Inst::new(0xff).modrm_opext(0b100).regmem(self.0).encode()
1808 },
1809 None,
1810 ({
1811 match self.0 {
1812 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("jmp {}", reg)),
1813 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("jmp qword {}", mem)),
1814 }
1815 }),
1816
1817 jmp_rel8(i8) =>
1818 Inst::new(0xeb).imm8(self.0 as u8).encode(),
1819 None,
1820 (fmt.write_fmt(core::format_args!("jmp short 0x{:x}", i64::from(self.0).wrapping_add(2)))),
1821
1822 jmp_rel32(i32) =>
1823 Inst::new(0xe9).imm32(self.0 as u32).encode(),
1824 None,
1825 (fmt.write_fmt(core::format_args!("jmp 0x{:x}", i64::from(self.0).wrapping_add(5)))),
1826
1827 jcc_rel8(Condition, i8) =>
1829 Inst::new(0x70 | self.0 as u8).imm8(self.1 as u8).encode(),
1830 None,
1831 (fmt.write_fmt(core::format_args!("j{} short 0x{:x}", self.0.suffix(), i64::from(self.1).wrapping_add(2)))),
1832
1833 jcc_rel32(Condition, i32) =>
1834 Inst::new(0x80 | self.0 as u8).op_alt().imm32(self.1 as u32).encode(),
1835 None,
1836 (fmt.write_fmt(core::format_args!("j{} near 0x{:x}", self.0.suffix(), i64::from(self.1).wrapping_add(6)))),
1837
1838 jmp_label8(Label) =>
1840 ud2().encode(),
1841 Some((self.0, FixupKind::new_1(0xeb, 1))),
1842 (fmt.write_fmt(core::format_args!("jmp {}", self.0))),
1843
1844 jmp_label32(Label) =>
1845 InstBuf::from_array([0x0f, 0x0b, 0x90, 0x0f, 0x0b]),
1846 Some((self.0, FixupKind::new_1(0xe9, 4))),
1847 (fmt.write_fmt(core::format_args!("jmp {}", self.0))),
1848
1849 call_label32(Label) =>
1850 InstBuf::from_array([0x0f, 0x0b, 0x90, 0x0f, 0x0b]),
1851 Some((self.0, FixupKind::new_1(0xe8, 4))),
1852 (fmt.write_fmt(core::format_args!("call {}", self.0))),
1853
1854 jcc_label8(Condition, Label) =>
1855 ud2().encode(),
1856 Some((self.1, FixupKind::new_1(0x70 | self.0 as u32, 1))),
1857 (fmt.write_fmt(core::format_args!("j{} {}", self.0.suffix(), self.1))),
1858
1859 jcc_label32(Condition, Label) =>
1860 InstBuf::from_array([0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b]),
1861 Some((self.1, FixupKind::new_2([0x0f, 0x80 | self.0 as u32], 4))),
1862 (fmt.write_fmt(core::format_args!("j{} {}", self.0.suffix(), self.1))),
1863
1864 jcc_label32_default(Condition, Label, i32) =>
1865 Inst::new(0x80 | self.0 as u8).op_alt().imm32(self.2 as u32).encode(),
1866 Some((self.1, FixupKind::new_2([0x0f, 0x80 | self.0 as u32], 4))),
1867 (fmt.write_fmt(core::format_args!("j{} {} or near 0x{:x}", self.0.suffix(), self.1, i64::from(self.2).wrapping_add(6)))),
1868
1869 lea_rip_label(Reg, Label) =>
1870 InstBuf::from_array([0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b, 0x90]),
1871 {
1872 let inst = Inst::new(0x8d).rex_64b().modrm_reg(self.0).mem(MemOp::RipRelative(None, 0));
1873 Some((self.1, FixupKind::new_3([u32::from(inst.rex), u32::from(inst.opcode), u32::from(inst.modrm)], 4)))
1874 },
1875 (fmt.write_fmt(core::format_args!("lea {}, [{}]", self.0, self.1))),
1876 }
1877}
1878
1879#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1880pub enum Condition {
1881 Overflow = 0,
1882 NotOverflow = 1,
1883 Below = 2, AboveOrEqual = 3, Equal = 4,
1886 NotEqual = 5,
1887 BelowOrEqual = 6, Above = 7, Sign = 8,
1890 NotSign = 9,
1891 Parity = 10,
1892 NotParity = 11,
1893 Less = 12, GreaterOrEqual = 13, LessOrEqual = 14, Greater = 15, }
1898
1899impl Condition {
1900 const fn suffix(self) -> &'static str {
1901 use Condition::*;
1902 match self {
1903 Overflow => "o",
1904 NotOverflow => "no",
1905 Below => "b",
1906 AboveOrEqual => "ae",
1907 Equal => "e",
1908 NotEqual => "ne",
1909 BelowOrEqual => "be",
1910 Above => "a",
1911 Sign => "s",
1912 NotSign => "ns",
1913 Parity => "p",
1914 NotParity => "np",
1915 Less => "l",
1916 GreaterOrEqual => "ge",
1917 LessOrEqual => "le",
1918 Greater => "g",
1919 }
1920 }
1921}
1922
1923#[cfg(feature = "alloc")]
1924#[cfg(test)]
1925impl tests::GenerateTestValues for Condition {
1926 fn generate_test_values(cb: impl FnMut(Self)) {
1927 use Condition::*;
1928 [
1929 Overflow,
1930 NotOverflow,
1931 Below,
1932 AboveOrEqual,
1933 Equal,
1934 NotEqual,
1935 BelowOrEqual,
1936 Above,
1937 Sign,
1938 NotSign,
1939 Parity,
1940 NotParity,
1941 Less,
1942 GreaterOrEqual,
1943 LessOrEqual,
1944 Greater,
1945 ]
1946 .into_iter()
1947 .for_each(cb);
1948 }
1949}
1950
1951#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1952pub enum RegSize {
1953 R32,
1954 R64,
1955}
1956
1957#[cfg(feature = "alloc")]
1958#[cfg(test)]
1959impl tests::GenerateTestValues for RegSize {
1960 fn generate_test_values(cb: impl FnMut(Self)) {
1961 use RegSize::*;
1962 [R32, R64].into_iter().for_each(cb);
1963 }
1964}
1965
1966#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
1967pub enum LoadKind {
1968 U8,
1969 U16,
1970 U32,
1971 #[default]
1972 U64,
1973 I8,
1974 I16,
1975 I32,
1976}
1977
1978#[cfg(feature = "alloc")]
1979#[cfg(test)]
1980impl tests::GenerateTestValues for LoadKind {
1981 fn generate_test_values(cb: impl FnMut(Self)) {
1982 use LoadKind::*;
1983 [U8, U16, U32, U64, I8, I16, I32].into_iter().for_each(cb);
1984 }
1985}
1986
1987#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
1988pub enum Size {
1989 U8,
1990 U16,
1991 U32,
1992 #[default]
1993 U64,
1994}
1995
1996impl Size {
1997 fn name(self) -> &'static str {
1998 match self {
1999 Size::U8 => "byte",
2000 Size::U16 => "word",
2001 Size::U32 => "dword",
2002 Size::U64 => "qword",
2003 }
2004 }
2005}
2006
2007impl From<RegSize> for Size {
2008 #[inline]
2009 fn from(reg_size: RegSize) -> Size {
2010 match reg_size {
2011 RegSize::R32 => Size::U32,
2012 RegSize::R64 => Size::U64,
2013 }
2014 }
2015}
2016
2017#[cfg(feature = "alloc")]
2018#[cfg(test)]
2019impl tests::GenerateTestValues for Size {
2020 fn generate_test_values(cb: impl FnMut(Self)) {
2021 use Size::*;
2022 [U8, U16, U32, U64].into_iter().for_each(cb);
2023 }
2024}
2025
2026#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2027pub enum ImmKind {
2028 I8(u8),
2029 I16(u16),
2030 I32(u32),
2031 I64(i32),
2032}
2033
2034impl core::fmt::Display for ImmKind {
2035 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
2036 match *self {
2037 ImmKind::I64(value) => fmt.write_fmt(core::format_args!("0x{:x}", i64::from(value))),
2038 ImmKind::I32(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2039 ImmKind::I16(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2040 ImmKind::I8(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2041 }
2042 }
2043}
2044
2045impl ImmKind {
2046 #[inline]
2047 const fn size(self) -> Size {
2048 match self {
2049 ImmKind::I8(..) => Size::U8,
2050 ImmKind::I16(..) => Size::U16,
2051 ImmKind::I32(..) => Size::U32,
2052 ImmKind::I64(..) => Size::U64,
2053 }
2054 }
2055}
2056
2057#[cfg(feature = "alloc")]
2058#[cfg(test)]
2059impl tests::GenerateTestValues for ImmKind {
2060 fn generate_test_values(mut cb: impl FnMut(Self)) {
2061 use ImmKind::*;
2062 u8::generate_test_values(|imm| cb(I8(imm)));
2063 u16::generate_test_values(|imm| cb(I16(imm)));
2064 u32::generate_test_values(|imm| cb(I32(imm)));
2065 i32::generate_test_values(|imm| cb(I64(imm)));
2066 }
2067}
2068
2069#[cfg(feature = "alloc")]
2070#[cfg(test)]
2071mod tests {
2072 pub trait GenerateTestValues: Copy {
2073 fn generate_test_values(cb: impl FnMut(Self));
2074 }
2075
2076 impl GenerateTestValues for super::Reg {
2077 fn generate_test_values(cb: impl FnMut(Self)) {
2078 use super::Reg::*;
2079 [rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15]
2080 .into_iter()
2081 .for_each(cb);
2082 }
2083 }
2084
2085 impl GenerateTestValues for super::RegIndex {
2086 fn generate_test_values(cb: impl FnMut(Self)) {
2087 use super::RegIndex::*;
2088 [rax, rcx, rdx, rbx, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15]
2089 .into_iter()
2090 .for_each(cb);
2091 }
2092 }
2093
2094 impl GenerateTestValues for super::SegReg {
2095 fn generate_test_values(cb: impl FnMut(Self)) {
2096 use super::SegReg::*;
2097 [fs, gs].into_iter().for_each(cb);
2098 }
2099 }
2100
2101 impl GenerateTestValues for super::Scale {
2102 fn generate_test_values(cb: impl FnMut(Self)) {
2103 use super::Scale::*;
2104 [x1, x2, x4, x8].into_iter().for_each(cb);
2105 }
2106 }
2107
2108 impl GenerateTestValues for super::MemOp {
2109 fn generate_test_values(mut cb: impl FnMut(Self)) {
2110 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2111 super::RegSize::generate_test_values(|reg_size| {
2112 super::Reg::generate_test_values(|base| {
2113 i32::generate_test_values(|offset| cb(super::MemOp::BaseOffset(seg_reg, reg_size, base, offset)))
2114 })
2115 })
2116 });
2117
2118 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2119 super::RegSize::generate_test_values(|reg_size| {
2120 super::Reg::generate_test_values(|base| {
2121 super::RegIndex::generate_test_values(|index| {
2122 super::Scale::generate_test_values(|scale| {
2123 i32::generate_test_values(|offset| {
2124 cb(super::MemOp::BaseIndexScaleOffset(seg_reg, reg_size, base, index, scale, offset))
2125 })
2126 })
2127 })
2128 })
2129 })
2130 });
2131
2132 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2133 super::RegSize::generate_test_values(|reg_size| {
2134 super::RegIndex::generate_test_values(|base| {
2135 super::Scale::generate_test_values(|scale| {
2136 i32::generate_test_values(|offset| cb(super::MemOp::IndexScaleOffset(seg_reg, reg_size, base, scale, offset)))
2137 })
2138 })
2139 })
2140 });
2141
2142 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2143 super::RegSize::generate_test_values(|reg_size| {
2144 i32::generate_test_values(|offset| cb(super::MemOp::Offset(seg_reg, reg_size, offset)))
2145 })
2146 });
2147
2148 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2149 i32::generate_test_values(|offset| cb(super::MemOp::RipRelative(seg_reg, offset)))
2150 });
2151 }
2152 }
2153
2154 impl GenerateTestValues for super::RegMem {
2155 fn generate_test_values(mut cb: impl FnMut(Self)) {
2156 super::Reg::generate_test_values(|reg| cb(super::RegMem::Reg(reg)));
2157 super::MemOp::generate_test_values(|mem| cb(super::RegMem::Mem(mem)));
2158 }
2159 }
2160
2161 impl GenerateTestValues for super::Operands {
2162 fn generate_test_values(mut cb: impl FnMut(Self)) {
2163 super::RegMem::generate_test_values(|regmem| {
2164 super::Size::generate_test_values(|size| {
2165 super::Reg::generate_test_values(|reg| {
2166 cb(super::Operands::RegMem_Reg(size, regmem, reg));
2167 cb(super::Operands::Reg_RegMem(size, reg, regmem));
2168 });
2169 });
2170
2171 super::ImmKind::generate_test_values(|imm| {
2172 cb(super::Operands::RegMem_Imm(regmem, imm));
2173 });
2174 });
2175 }
2176 }
2177
2178 impl GenerateTestValues for crate::Label {
2179 fn generate_test_values(_: impl FnMut(Self)) {
2180 unimplemented!();
2181 }
2182 }
2183
2184 impl GenerateTestValues for () {
2185 fn generate_test_values(mut cb: impl FnMut(Self)) {
2186 cb(())
2187 }
2188 }
2189
2190 impl<T> GenerateTestValues for Option<T>
2191 where
2192 T: GenerateTestValues,
2193 {
2194 fn generate_test_values(mut cb: impl FnMut(Self)) {
2195 cb(None);
2196 T::generate_test_values(move |value| cb(Some(value)))
2197 }
2198 }
2199
2200 impl GenerateTestValues for u8 {
2201 fn generate_test_values(cb: impl FnMut(Self)) {
2202 [0, 1, 31, 0x7f, 0x80, 0x81, 0xfe, 0xff].into_iter().for_each(cb);
2203 }
2204 }
2205
2206 impl GenerateTestValues for i8 {
2207 fn generate_test_values(mut cb: impl FnMut(Self)) {
2208 u8::generate_test_values(|value| cb(value as i8))
2209 }
2210 }
2211
2212 impl GenerateTestValues for u16 {
2213 fn generate_test_values(cb: impl FnMut(Self)) {
2214 [
2215 0, 1, 0x7f, 0x80, 0x81, 0xfe, 0xff, 0x100, 0x101, 0x7fff, 0x8000, 0x8001, 0xfffe, 0xffff,
2216 ]
2217 .into_iter()
2218 .for_each(cb);
2219 }
2220 }
2221
2222 impl GenerateTestValues for i16 {
2223 fn generate_test_values(mut cb: impl FnMut(Self)) {
2224 u16::generate_test_values(|value| cb(value as i16))
2225 }
2226 }
2227
2228 impl GenerateTestValues for u32 {
2229 fn generate_test_values(cb: impl FnMut(Self)) {
2230 [
2231 0, 1, 0x7f, 0x80, 0x81, 0xfe, 0xff, 0x100, 0x101, 0x7fff, 0x8000, 0x8001, 0xfffe, 0xffff, 0x10000, 0x10001, 0x7fffffff,
2232 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff,
2233 ]
2234 .into_iter()
2235 .for_each(cb);
2236 }
2237 }
2238
2239 impl GenerateTestValues for i32 {
2240 fn generate_test_values(mut cb: impl FnMut(Self)) {
2241 u32::generate_test_values(|value| cb(value as i32))
2242 }
2243 }
2244
2245 impl GenerateTestValues for u64 {
2246 fn generate_test_values(cb: impl FnMut(Self)) {
2247 [
2248 0,
2249 1,
2250 0x7f,
2251 0x80,
2252 0x81,
2253 0xfe,
2254 0xff,
2255 0x100,
2256 0x101,
2257 0x7fff,
2258 0x8000,
2259 0x8001,
2260 0xfffe,
2261 0xffff,
2262 0x10000,
2263 0x10001,
2264 0x7fffffff,
2265 0x80000000,
2266 0x80000001,
2267 0xfffffffe,
2268 0xffffffff,
2269 0x100000000,
2270 0x100000001,
2271 0x7fffffffffffffff,
2272 0x8000000000000000,
2273 0x8000000000000001,
2274 0xfffffffffffffffe,
2275 0xffffffffffffffff,
2276 ]
2277 .into_iter()
2278 .for_each(cb);
2279 }
2280 }
2281
2282 use alloc::format;
2283 use alloc::string::String;
2284
2285 fn disassemble(code: &[u8]) -> String {
2286 let mut output = String::new();
2287 disassemble_into(code, &mut output);
2288 output
2289 }
2290
2291 fn disassemble_into(mut code: &[u8], output: &mut String) {
2292 use core::fmt::Write;
2293 use iced_x86::Formatter;
2294
2295 let mut formatter = iced_x86::NasmFormatter::new();
2296 formatter.options_mut().set_space_after_operand_separator(true);
2297 formatter.options_mut().set_hex_prefix("0x");
2298 formatter.options_mut().set_hex_suffix("");
2299 formatter.options_mut().set_uppercase_hex(false);
2300 formatter.options_mut().set_small_hex_numbers_in_decimal(false);
2301 formatter.options_mut().set_show_useless_prefixes(true);
2302 formatter.options_mut().set_branch_leading_zeros(false);
2303 formatter.options_mut().set_rip_relative_addresses(true);
2304 let code_origin = 0;
2305 let mut position = 0;
2306 loop {
2307 let mut decoder = iced_x86::Decoder::with_ip(64, code, code_origin, iced_x86::DecoderOptions::NONE);
2308 if !decoder.can_decode() {
2309 break;
2310 }
2311 let mut instruction = iced_x86::Instruction::default();
2312 decoder.decode_out(&mut instruction);
2313
2314 write!(output, "{:08x} ", position).unwrap();
2315 let start_index = (instruction.ip() - code_origin) as usize;
2316 let instr_bytes = &code[start_index..start_index + instruction.len()];
2317 for b in instr_bytes.iter() {
2318 write!(output, "{:02x}", b).unwrap();
2319 }
2320
2321 output.push(' ');
2322 formatter.format(&instruction, output);
2323 output.push('\n');
2324 code = &code[instruction.len()..];
2325 position += instruction.len();
2326 }
2327
2328 output.pop();
2329 }
2330
2331 struct TestAsm {
2332 asm: crate::Assembler,
2333 disassembly_1: String,
2334 disassembly_2: String,
2335 }
2336
2337 impl TestAsm {
2338 fn new() -> Self {
2339 Self {
2340 asm: crate::Assembler::new(),
2341 disassembly_1: String::new(),
2342 disassembly_2: String::new(),
2343 }
2344 }
2345
2346 fn run<T>(&mut self, inst: crate::Instruction<T>)
2347 where
2348 T: Copy + core::fmt::Display + core::fmt::Debug,
2349 {
2350 use core::fmt::Write;
2351
2352 self.asm.clear();
2353 self.disassembly_1.clear();
2354 self.disassembly_2.clear();
2355
2356 let position = self.asm.len();
2357 self.asm.push(inst);
2358 let ranges = [(inst, position..self.asm.len())];
2359
2360 let code = self.asm.finalize();
2361 let mut position = 0;
2362 for (inst, range) in ranges {
2363 write!(&mut self.disassembly_1, "{:08x} ", position).unwrap();
2364 for &b in &code[range.clone()] {
2365 write!(&mut self.disassembly_1, "{:02x}", b).unwrap();
2366 }
2367 position += range.len();
2368 writeln!(&mut self.disassembly_1, " {}", inst).unwrap();
2369 }
2370
2371 self.disassembly_1.pop();
2372 disassemble_into(&code, &mut self.disassembly_2);
2373 assert_eq!(self.disassembly_1, self.disassembly_2, "broken encoding for: {inst:?}");
2374 }
2375 }
2376
2377 macro_rules! generate_tests {
2378 ($($inst_name:ident,)+) => {
2379 $(
2380 #[test]
2381 fn $inst_name() {
2382 let mut test = TestAsm::new();
2383 <super::inst::types::$inst_name as GenerateTestValues>::generate_test_values(|instruction| {
2384 test.run(crate::Instruction {
2385 bytes: instruction.encode(),
2386 fixup: None,
2387 instruction
2388 })
2389 });
2390 }
2391 )+
2392 }
2393 }
2394
2395 generate_tests! {
2396 add,
2397 and,
2398 bts,
2399 call_rel32,
2400 call,
2401 cdq,
2402 clflushopt,
2403 cmov,
2404 cmp,
2405 cpuid,
2406 cqo,
2407 dec,
2408 div,
2409 endbr64,
2410 idiv,
2411 imul_dx_ax,
2412 imul_imm,
2413 imul,
2414 inc,
2415 jcc_rel32,
2416 jcc_rel8,
2417 jmp_rel32,
2418 jmp_rel8,
2419 jmp,
2420 lea,
2421 lfence,
2422 load,
2423 mfence,
2424 mov_imm,
2425 mov_imm64,
2426 mov,
2427 movsx_8_to_64,
2428 movsx_16_to_64,
2429 movzx_16_to_64,
2430 movsxd_32_to_64,
2431 mul,
2432 mul_dx_ax,
2433 neg,
2434 nop,
2435 nop10,
2436 nop11,
2437 nop2,
2438 nop3,
2439 nop4,
2440 nop5,
2441 nop6,
2442 nop7,
2443 nop8,
2444 nop9,
2445 not,
2446 or,
2447 pop,
2448 push,
2449 push_imm,
2450 rcr_imm,
2451 rdpmc,
2452 rdtscp,
2453 ret,
2454 ror_imm,
2455 rol_cl,
2456 ror_cl,
2457 sar_cl,
2458 sar_imm,
2459 popcnt,
2460 lzcnt,
2461 tzcnt,
2462 setcc,
2463 bswap,
2464 shl_cl,
2465 shl_imm,
2466 shr_cl,
2467 shr_imm,
2468 store,
2469 sub,
2470 syscall,
2471 test,
2472 ud2,
2473 xchg_mem,
2474 xor,
2475 }
2476
2477 #[test]
2478 fn jmp_label8_infinite_loop() {
2479 use super::inst::*;
2480 let mut asm = crate::Assembler::new();
2481 let label = asm.forward_declare_label();
2482 asm.push_with_label(label, jmp_label8(label));
2483 let disassembly = disassemble(&asm.finalize());
2484 assert_eq!(disassembly, "00000000 ebfe jmp short 0x0");
2485 }
2486
2487 #[test]
2488 fn jmp_label8_undefined() {
2489 use super::inst::*;
2490 let mut asm = crate::Assembler::new();
2491 let label = asm.forward_declare_label();
2492 asm.push(jmp_label8(label));
2493 let disassembly = disassemble(&asm.finalize());
2494 assert_eq!(disassembly, "00000000 0f0b ud2");
2495 }
2496
2497 #[test]
2498 fn jmp_label32_infinite_loop() {
2499 use super::inst::*;
2500 let mut asm = crate::Assembler::new();
2501 let label = asm.forward_declare_label();
2502 asm.push_with_label(label, jmp_label32(label));
2503 let disassembly = disassemble(&asm.finalize());
2504 assert_eq!(disassembly, "00000000 e9fbffffff jmp 0x0");
2505 }
2506
2507 #[test]
2508 fn jmp_label32_undefined() {
2509 use super::inst::*;
2510 let mut asm = crate::Assembler::new();
2511 let label = asm.forward_declare_label();
2512 asm.push(jmp_label32(label));
2513 let disassembly = disassemble(&asm.finalize());
2514 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 90 nop\n00000003 0f0b ud2");
2515 }
2516
2517 #[test]
2518 fn call_label32_infinite_loop() {
2519 use super::inst::*;
2520 let mut asm = crate::Assembler::new();
2521 let label = asm.forward_declare_label();
2522 asm.push_with_label(label, call_label32(label));
2523 let disassembly = disassemble(&asm.finalize());
2524 assert_eq!(disassembly, "00000000 e8fbffffff call 0x0");
2525 }
2526
2527 #[test]
2528 fn call_label32_undefined() {
2529 use super::inst::*;
2530 let mut asm = crate::Assembler::new();
2531 let label = asm.forward_declare_label();
2532 asm.push(call_label32(label));
2533 let disassembly = disassemble(&asm.finalize());
2534 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 90 nop\n00000003 0f0b ud2");
2535 }
2536
2537 #[test]
2538 fn jcc_label8_infinite_loop() {
2539 use super::inst::*;
2540 super::Condition::generate_test_values(|cond| {
2541 let mut asm = crate::Assembler::new();
2542 let label = asm.forward_declare_label();
2543 asm.push_with_label(label, jcc_label8(cond, label));
2544 let disassembly = disassemble(&asm.finalize());
2545 assert_eq!(
2546 disassembly,
2547 format!("00000000 {:02x}fe j{} short 0x0", 0x70 + cond as u8, cond.suffix())
2548 );
2549 });
2550 }
2551
2552 #[test]
2553 fn jcc_label8_undefined() {
2554 use super::inst::*;
2555 super::Condition::generate_test_values(|cond| {
2556 let mut asm = crate::Assembler::new();
2557 let label = asm.forward_declare_label();
2558 asm.push(jcc_label8(cond, label));
2559 let disassembly = disassemble(&asm.finalize());
2560 assert_eq!(disassembly, "00000000 0f0b ud2");
2561 });
2562 }
2563
2564 #[test]
2565 fn jcc_label8_jump_forward() {
2566 use super::inst::*;
2567 super::Condition::generate_test_values(|cond| {
2568 let mut asm = crate::Assembler::new();
2569 let label = asm.forward_declare_label();
2570 asm.push(jcc_label8(cond, label));
2571 asm.push_with_label(label, nop());
2572 let disassembly = disassemble(&asm.finalize());
2573 assert_eq!(
2574 disassembly,
2575 format!(
2576 concat!("00000000 {:02x}00 j{} short 0x2\n", "00000002 90 nop",),
2577 0x70 + cond as u8,
2578 cond.suffix()
2579 )
2580 );
2581 })
2582 }
2583
2584 #[test]
2585 fn jcc_label8_jump_backward() {
2586 use super::inst::*;
2587 super::Condition::generate_test_values(|cond| {
2588 let mut asm = crate::Assembler::new();
2589 let label = asm.forward_declare_label();
2590 asm.push_with_label(label, nop());
2591 asm.push(jcc_label8(cond, label));
2592 let disassembly = disassemble(&asm.finalize());
2593 assert_eq!(
2594 disassembly,
2595 format!(
2596 concat!("00000000 90 nop\n", "00000001 {:02x}fd j{} short 0xffffffffffffffff",),
2597 0x70 + cond as u8,
2598 cond.suffix()
2599 )
2600 );
2601 });
2602 }
2603
2604 #[test]
2605 fn jcc_label32_jump_forward() {
2606 use super::inst::*;
2607 super::Condition::generate_test_values(|cond| {
2608 let mut asm = crate::Assembler::new();
2609 let label = asm.forward_declare_label();
2610 asm.push(jcc_label32(cond, label));
2611 asm.push_with_label(label, nop());
2612 let disassembly = disassemble(&asm.finalize());
2613 assert_eq!(
2614 disassembly,
2615 format!(
2616 concat!("00000000 0f{:02x}00000000 j{} near 0x6\n", "00000006 90 nop",),
2617 0x80 + cond as u8,
2618 cond.suffix()
2619 )
2620 );
2621 });
2622 }
2623
2624 #[test]
2625 fn jcc_label32_undefined() {
2626 use super::inst::*;
2627 super::Condition::generate_test_values(|cond| {
2628 let mut asm = crate::Assembler::new();
2629 let label = asm.forward_declare_label();
2630 asm.push(jcc_label32(cond, label));
2631 let disassembly = disassemble(&asm.finalize());
2632 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 0f0b ud2\n00000004 0f0b ud2");
2633 });
2634 }
2635
2636 #[test]
2637 fn lea_rip_label_infinite_loop() {
2638 use super::inst::*;
2639 let mut asm = crate::Assembler::new();
2640 let label = asm.forward_declare_label();
2641 asm.push_with_label(label, lea_rip_label(super::Reg::rax, label));
2642 let disassembly = disassemble(&asm.finalize());
2643 assert_eq!(disassembly, "00000000 488d05f9ffffff lea rax, [rip-0x7]");
2644 }
2645
2646 #[test]
2647 fn lea_rip_label_undefined() {
2648 use super::inst::*;
2649 super::Reg::generate_test_values(|reg| {
2650 let mut asm = crate::Assembler::new();
2651 let label = asm.forward_declare_label();
2652 asm.push(lea_rip_label(reg, label));
2653 let disassembly = disassemble(&asm.finalize());
2654 assert_eq!(
2655 disassembly,
2656 "00000000 0f0b ud2\n00000002 0f0b ud2\n00000004 0f0b ud2\n00000006 90 nop"
2657 );
2658 });
2659 }
2660
2661 #[test]
2662 fn lea_rip_label_next_instruction() {
2663 use super::inst::*;
2664 let mut asm = crate::Assembler::new();
2665 let label = asm.forward_declare_label();
2666 asm.push(lea_rip_label(super::Reg::rax, label));
2667 asm.push_with_label(label, nop());
2668 let disassembly = disassemble(&asm.finalize());
2669 assert_eq!(disassembly, "00000000 488d0500000000 lea rax, [rip]\n00000007 90 nop");
2670 }
2671}