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