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 pause() =>
1242 InstBuf::from_array([0xf3, 0x90]),
1243 None,
1244 (fmt.write_str("pause")),
1245
1246 nop() =>
1248 InstBuf::from_array([0x90]),
1249 None,
1250 (fmt.write_str("nop")),
1251
1252 nop2() =>
1253 InstBuf::from_array([0x66, 0x90]),
1254 None,
1255 (fmt.write_str("xchg ax, ax")),
1256
1257 nop3() =>
1258 InstBuf::from_array([0x0f, 0x1f, 0x00]),
1259 None,
1260 (fmt.write_str("nop dword [rax]")),
1261
1262 nop4() =>
1263 InstBuf::from_array([0x0f, 0x1f, 0x40, 0x00]),
1264 None,
1265 (fmt.write_str("nop dword [rax]")),
1266
1267 nop5() =>
1268 InstBuf::from_array([0x0f, 0x1f, 0x44, 0x00, 0x00]),
1269 None,
1270 (fmt.write_str("nop dword [rax+rax]")),
1271
1272 nop6() =>
1273 InstBuf::from_array([0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00]),
1274 None,
1275 (fmt.write_str("nop word [rax+rax]")),
1276
1277 nop7() =>
1278 InstBuf::from_array([0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00]),
1279 None,
1280 (fmt.write_str("nop dword [rax]")), nop8() =>
1283 InstBuf::from_array([0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1284 None,
1285 (fmt.write_str("nop dword [rax+rax]")),
1286
1287 nop9() =>
1288 InstBuf::from_array([0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1289 None,
1290 (fmt.write_str("nop word [rax+rax]")), nop10() =>
1293 InstBuf::from_array([0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1294 None,
1295 (fmt.write_str("nop word [cs:rax+rax]")),
1296
1297 nop11() =>
1298 InstBuf::from_array([0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1299 None,
1300 (fmt.write_str("nop word [cs:rax+rax]")),
1301
1302 clflushopt(MemOp) =>
1304 Inst::new(0xae).override_op_size().op_alt().modrm_opext(0b111).mem(self.0).encode(),
1305 None,
1306 (fmt.write_fmt(core::format_args!("clflushopt {}", self.0))),
1307
1308 ret() =>
1310 InstBuf::from_array([0xc3]),
1311 None,
1312 (fmt.write_str("ret")),
1313
1314 mov(RegSize, Reg, Reg) =>
1318 Inst::new(0x89).rex_64b_if(matches!(self.0, RegSize::R64)).modrm_rm_direct(self.1).modrm_reg(self.2).encode(),
1319 None,
1320 (fmt.write_fmt(core::format_args!("mov {}, {}", self.1.name_from(self.0), self.2.name_from(self.0)))),
1321
1322 movsx_8_to_64(RegSize, Reg, Reg) =>
1323 Inst::new(0xbe).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1324 None,
1325 (fmt.write_fmt(core::format_args!("movsx {}, {}", self.1.name(), self.2.name8()))),
1326
1327 movsx_16_to_64(RegSize, Reg, Reg) =>
1328 Inst::new(0xbf).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1329 None,
1330 (fmt.write_fmt(core::format_args!("movsx {}, {}", self.1.name(), self.2.name16()))),
1331
1332 movzx_16_to_64(RegSize, Reg, Reg) =>
1333 Inst::new(0xb7).op_alt().rex_64b().modrm_rm_direct(self.2).modrm_reg(self.1).encode(),
1334 None,
1335 (fmt.write_fmt(core::format_args!("movzx {}, {}", self.1.name(), self.2.name16()))),
1336
1337 movsxd_32_to_64(Reg, Reg) =>
1338 Inst::new(0x63).rex_64b().modrm_rm_direct(self.1).modrm_reg(self.0).encode(),
1339 None,
1340 (fmt.write_fmt(core::format_args!("movsxd {}, {}", self.0.name(), self.1.name32()))),
1341
1342 mov_imm64(Reg, u64) =>
1343 {
1344 if self.1 <= 0x7fffffff {
1345 mov_imm(RegMem::Reg(self.0), ImmKind::I32(self.1 as u32)).encode()
1346 } else {
1347 let xs = self.1.to_le_bytes();
1348 InstBuf::from_array([
1349 REX_64B_OP | self.0.rex_bit(),
1350 0xb8 | self.0.modrm_rm_bits(),
1351 xs[0], xs[1], xs[2], xs[3], xs[4], xs[5], xs[6], xs[7]
1352 ])
1353 }
1354 },
1355 None,
1356 ({
1357 if self.1 <= 0x7fffffff {
1358 mov_imm(RegMem::Reg(self.0), ImmKind::I32(self.1 as u32)).fmt(fmt)
1359 } else {
1360 fmt.write_fmt(core::format_args!("mov {}, 0x{:x}", self.0, self.1))
1361 }
1362 }),
1363
1364 mov_imm(RegMem, ImmKind) =>
1365 {
1366 match self.0 {
1367 RegMem::Mem(..) => new_rm_imm(0xc6, self.0, self.1).encode(),
1368 RegMem::Reg(reg) => {
1369 match self.1 {
1370 ImmKind::I8(value) => Inst::with_reg_in_op(0xb0, reg).imm8(value).rex_if(!matches!(reg, Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)),
1371 ImmKind::I16(value) => Inst::with_reg_in_op(0xb8, reg).imm16(value).override_op_size(),
1372 ImmKind::I32(value) => Inst::with_reg_in_op(0xb8, reg).imm32(value),
1373 ImmKind::I64(..) => new_rm_imm(0xc6, self.0, self.1),
1374 }.encode()
1375 }
1376 }
1377 },
1378 None,
1379 (display_with_operands(fmt, "mov", Operands::RegMem_Imm(self.0, self.1))),
1380
1381 store(Size, MemOp, Reg) =>
1382 new_rm(0x88, self.0, RegMem::Mem(self.1), Some(self.2)).encode(),
1383 None,
1384 (fmt.write_fmt(core::format_args!("mov {}, {}", self.1, self.2.name_from_size(self.0)))),
1385
1386 load(LoadKind, Reg, MemOp) =>
1387 {
1388 let inst = match self.0 {
1389 LoadKind::U8 | LoadKind::U16 | LoadKind::I8 | LoadKind::I16 => {
1390 let op = match self.0 {
1391 LoadKind::U8 => 0xb6,
1392 LoadKind::I8 => 0xbe,
1393 LoadKind::U16 => 0xb7,
1394 LoadKind::I16 => 0xbf,
1395 | LoadKind::I32
1396 | LoadKind::U32
1397 | LoadKind::U64
1398 => unreachable!()
1399 };
1400
1401 Inst::new(op)
1402 .op_alt()
1403 .rex_64b_if(!(matches!(self.0, LoadKind::U8 | LoadKind::U16) && !self.1.needs_rex() && !self.2.needs_rex()))
1405 },
1406 LoadKind::I32 => Inst::new(0x63).rex_64b(),
1407 LoadKind::U32 => Inst::new(0x8b),
1408 LoadKind::U64 => Inst::new(0x8b).rex_64b()
1409 };
1410
1411 inst
1412 .modrm_reg(self.1)
1413 .mem(self.2)
1414 .encode()
1415 },
1416 None,
1417 ({
1418 let (name, kind, size) = match self.0 {
1419 LoadKind::U8 if !self.1.needs_rex() && !self.2.needs_rex() => (self.1.name32(), "zx", "byte "),
1420 LoadKind::U16 if !self.1.needs_rex() && !self.2.needs_rex() => (self.1.name32(), "zx", "word "),
1421 LoadKind::U8 => (self.1.name(), "zx", "byte "),
1422 LoadKind::I8 => (self.1.name(), "sx", "byte "),
1423 LoadKind::U16 => (self.1.name(), "zx", "word "),
1424 LoadKind::U32 => (self.1.name32(), "", ""),
1425 LoadKind::I16 => (self.1.name(), "sx", "word "),
1426 LoadKind::I32 => (self.1.name(), "sxd", ""),
1427 LoadKind::U64 => (self.1.name(), "", ""),
1428 };
1429
1430 fmt.write_fmt(core::format_args!("mov{} {}, {}{}", kind, name, size, self.2))
1431 }),
1432
1433 cmov(Condition, RegSize, Reg, RegMem) =>
1435 {
1436 Inst::new(0x40 | self.0 as u8)
1437 .op_alt()
1438 .rex_64b_if(matches!(self.1, RegSize::R64))
1439 .modrm_reg(self.2)
1440 .regmem(self.3)
1441 .encode()
1442 },
1443 None,
1444 (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))))),
1445
1446 xchg_mem(RegSize, Reg, MemOp) =>
1448 Inst::new(0x87).rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).mem(self.2).encode(),
1449 None,
1450 (fmt.write_fmt(core::format_args!("xchg {}, {}", self.1.name_from(self.0), self.2))),
1451
1452 add(Operands) =>
1454 alu_impl(0x00, 0x02, 0b000, self.0),
1455 None,
1456 (display_with_operands(fmt, "add", self.0)),
1457
1458 inc(Size, RegMem) =>
1460 new_rm(0xfe, self.0, self.1, None).encode(),
1461 None,
1462 (fmt.write_fmt(core::format_args!("inc {}", self.1.display(self.0)))),
1463
1464 dec(Size, RegMem) =>
1466 new_rm(0xfe, self.0, self.1, None).modrm_opext(0b001).encode(),
1467 None,
1468 (fmt.write_fmt(core::format_args!("dec {}", self.1.display(self.0)))),
1469
1470 sub(Operands) =>
1472 alu_impl(0x28, 0x2a, 0b101, self.0),
1473 None,
1474 (display_with_operands(fmt, "sub", self.0)),
1475
1476 or(Operands) =>
1478 alu_impl(0x08, 0x0a, 0b001, self.0),
1479 None,
1480 (display_with_operands(fmt, "or", self.0)),
1481
1482 and(Operands) =>
1484 alu_impl(0x20, 0x22, 0b100, self.0),
1485 None,
1486 (display_with_operands(fmt, "and", self.0)),
1487
1488 xor(Operands) =>
1490 alu_impl(0x30, 0x32, 0b110, self.0),
1491 None,
1492 (display_with_operands(fmt, "xor", self.0)),
1493
1494 bts(RegSize, RegMem, u8) =>
1496 Inst::new(0xba).op_alt().modrm_opext(0b101).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).imm8(self.2).encode(),
1497 None,
1498 ({
1499 match self.0 {
1500 RegSize::R64 => fmt.write_fmt(core::format_args!("bts {}, 0x{:x}", self.1.display(Size::from(self.0)), i64::from(self.2))),
1501 RegSize::R32 => fmt.write_fmt(core::format_args!("bts {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2)),
1502 }
1503 }),
1504
1505 neg(Size, RegMem) =>
1507 new_rm(0xf6, self.0, self.1, None).modrm_opext(0b011).encode(),
1508 None,
1509 (fmt.write_fmt(core::format_args!("neg {}", self.1.display(self.0)))),
1510
1511 not(Size, RegMem) =>
1513 new_rm(0xf6, self.0, self.1, None).modrm_opext(0b010).encode(),
1514 None,
1515 (fmt.write_fmt(core::format_args!("not {}", self.1.display(self.0)))),
1516
1517 cmp(Operands) =>
1519 alu_impl(0x38, 0x3a, 0b111, self.0),
1520 None,
1521 (display_with_operands(fmt, "cmp", self.0)),
1522
1523 sar_cl(RegSize, RegMem) =>
1525 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b111).encode(),
1526 None,
1527 (fmt.write_fmt(core::format_args!("sar {}, cl", self.1.display(Size::from(self.0))))),
1528
1529 sar_imm(RegSize, RegMem, u8) =>
1530 {
1531 if self.2 == 1 {
1532 Inst::new(0xd1)
1533 } else {
1534 Inst::new(0xc1).imm8(self.2)
1535 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b111).encode()
1536 },
1537 None,
1538 (fmt.write_fmt(core::format_args!("sar {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1539
1540 shl_cl(RegSize, RegMem) =>
1541 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b100).encode(),
1542 None,
1543 (fmt.write_fmt(core::format_args!("shl {}, cl", self.1.display(Size::from(self.0))))),
1544
1545 shl_imm(RegSize, RegMem, u8) =>
1546 {
1547 if self.2 == 1 {
1548 Inst::new(0xd1)
1549 } else {
1550 Inst::new(0xc1).imm8(self.2)
1551 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b100).encode()
1552 },
1553 None,
1554 (fmt.write_fmt(core::format_args!("shl {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1555
1556 shr_cl(RegSize, RegMem) =>
1557 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b101).encode(),
1558 None,
1559 (fmt.write_fmt(core::format_args!("shr {}, cl", self.1.display(Size::from(self.0))))),
1560
1561 shr_imm(RegSize, RegMem, u8) =>
1562 {
1563 if self.2 == 1 {
1564 Inst::new(0xd1)
1565 } else {
1566 Inst::new(0xc1).imm8(self.2)
1567 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b101).encode()
1568 },
1569 None,
1570 (fmt.write_fmt(core::format_args!("shr {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1571
1572 ror_imm(RegSize, RegMem, u8) =>
1574 {
1575 if self.2 == 1 {
1576 Inst::new(0xd1)
1577 } else {
1578 Inst::new(0xc1).imm8(self.2)
1579 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b001).encode()
1580 },
1581 None,
1582 (fmt.write_fmt(core::format_args!("ror {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1583
1584 rol_cl(RegSize, RegMem) =>
1585 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b000).encode(),
1586 None,
1587 (fmt.write_fmt(core::format_args!("rol {}, cl", self.1.display(Size::from(self.0))))),
1588
1589 ror_cl(RegSize, RegMem) =>
1590 Inst::new(0xd3).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b001).encode(),
1591 None,
1592 (fmt.write_fmt(core::format_args!("ror {}, cl", self.1.display(Size::from(self.0))))),
1593
1594 rcr_imm(RegSize, RegMem, u8) =>
1595 {
1596 if self.2 == 1 {
1597 Inst::new(0xd1)
1598 } else {
1599 Inst::new(0xc1).imm8(self.2)
1600 }.rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).modrm_opext(0b011).encode()
1601 },
1602 None,
1603 (fmt.write_fmt(core::format_args!("rcr {}, 0x{:x}", self.1.display(Size::from(self.0)), self.2))),
1604
1605 popcnt(RegSize, Reg, RegMem) =>
1607 {
1608 Inst::new(0xb8)
1609 .op_rep_prefix()
1610 .op_alt()
1611 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1612 },
1613 None,
1614 (fmt.write_fmt(core::format_args!("popcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1615
1616 lzcnt(RegSize, Reg, RegMem) =>
1618 {
1619 Inst::new(0xbd)
1620 .op_rep_prefix()
1621 .op_alt()
1622 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1623 },
1624 None,
1625 (fmt.write_fmt(core::format_args!("lzcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1626
1627 tzcnt(RegSize, Reg, RegMem) =>
1629 {
1630 Inst::new(0xbc)
1631 .op_rep_prefix()
1632 .op_alt()
1633 .rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1634 },
1635 None,
1636 (fmt.write_fmt(core::format_args!("tzcnt {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1637
1638 bswap(RegSize, Reg) =>
1640 {
1641 Inst::with_reg_in_op(0xc8, self.1)
1642 .op_alt()
1643 .rex_64b_if(matches!(self.0, RegSize::R64)).encode()
1644 },
1645 None,
1646 (fmt.write_fmt(core::format_args!("bswap {}", self.1.name_from(self.0)))),
1647
1648 test(Operands) =>
1650 {
1651 match self.0 {
1652 Operands::RegMem_Reg(size, regmem, reg) |
1653 Operands::Reg_RegMem(size, reg, regmem) => new_rm(0x84, size, regmem, Some(reg)).encode(),
1654 Operands::RegMem_Imm(regmem, imm) => new_rm_imm(0xf6, regmem, imm).encode(),
1655 }
1656 },
1657 None,
1658 ({
1659 let operands = match self.0 {
1660 Operands::Reg_RegMem(size, reg, regmem) => Operands::RegMem_Reg(size, regmem, reg),
1661 operands => operands
1662 };
1663
1664 display_with_operands(fmt, "test", operands)
1665 }),
1666
1667 imul(RegSize, Reg, RegMem) =>
1669 Inst::new(0xaf).op_alt().rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode(),
1670 None,
1671 (fmt.write_fmt(core::format_args!("imul {}, {}", self.1.name_from(self.0), self.2.display_without_prefix(Size::from(self.0))))),
1672
1673 imul_imm(RegSize, Reg, RegMem, i32) =>
1674 {
1675 let value = self.3;
1676 if value <= i32::from(i8::MAX) && value >= i32::from(i8::MIN) {
1677 Inst::new(0x6b).imm8(value as u8)
1678 } else {
1679 Inst::new(0x69).imm32(value as u32)
1680 }.rex_64b_if(matches!(self.0, RegSize::R64)).modrm_reg(self.1).regmem(self.2).encode()
1681 },
1682 None,
1683 ({
1684 struct DisplaySignExtend(RegSize, i32);
1685 impl core::fmt::Display for DisplaySignExtend {
1686 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1687 let value = match self.0 {
1688 RegSize::R64 => i64::from(self.1) as u64,
1689 RegSize::R32 => u64::from(self.1 as u32),
1690 };
1691
1692 fmt.write_fmt(core::format_args!("0x{:x}", value))
1693 }
1694
1695 }
1696
1697 if RegMem::Reg(self.1) == self.2 {
1698 fmt.write_fmt(core::format_args!("imul {}, {}", self.1.name_from(self.0), DisplaySignExtend(self.0, self.3)))
1699 } else {
1700 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)))
1701 }
1702 }),
1703
1704 imul_dx_ax(RegSize, RegMem) =>
1705 Inst::new(0xf7).modrm_opext(0b101).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1706 None,
1707 (fmt.write_fmt(core::format_args!("imul {}", self.1.display(Size::from(self.0))))),
1708
1709 mul(RegSize, RegMem) =>
1711 Inst::new(0xf7).modrm_opext(0b100).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1712 None,
1713 (fmt.write_fmt(core::format_args!("mul {}", self.1.display(Size::from(self.0))))),
1714
1715 mul_dx_ax(RegSize, RegMem) =>
1716 Inst::new(0xf7).modrm_opext(0b100).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1717 None,
1718 (fmt.write_fmt(core::format_args!("mul {}", self.1.display(Size::from(self.0))))),
1719
1720 div(RegSize, RegMem) =>
1722 Inst::new(0xf7).modrm_opext(0b110).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1723 None,
1724 (fmt.write_fmt(core::format_args!("div {}", self.1.display(Size::from(self.0))))),
1725
1726 idiv(RegSize, RegMem) =>
1728 Inst::new(0xf7).modrm_opext(0b111).rex_64b_if(matches!(self.0, RegSize::R64)).regmem(self.1).encode(),
1729 None,
1730 (fmt.write_fmt(core::format_args!("idiv {}", self.1.display(Size::from(self.0))))),
1731
1732 cdq() =>
1734 Inst::new(0x99).encode(),
1735 None,
1736 (fmt.write_str("cdq")),
1737
1738 cqo() =>
1739 Inst::new(0x99).rex_64b().encode(),
1740 None,
1741 (fmt.write_str("cqo")),
1742
1743 setcc(Condition, RegMem) =>
1745 {
1746 Inst::new(0x90 | self.0 as u8)
1747 .rex_if(!matches!(self.1, RegMem::Reg(Reg::rax | Reg::rcx | Reg::rdx | Reg::rbx)))
1748 .op_alt()
1749 .regmem(self.1)
1750 .encode()
1751 },
1752 None,
1753 (fmt.write_fmt(core::format_args!("set{} {}", self.0.suffix(), self.1.display_without_prefix(Size::U8)))),
1754
1755 lea(RegSize, Reg, MemOp) =>
1757 Inst::new(0x8d)
1758 .rex_64b_if(matches!(self.0, RegSize::R64))
1759 .modrm_reg(self.1)
1760 .mem(self.2).encode(),
1761 None,
1762 (fmt.write_fmt(core::format_args!("lea {}, {}", self.1.name_from(self.0), self.2))),
1763
1764 mfence() =>
1766 InstBuf::from_array([0x0f, 0xae, 0xf0]),
1767 None,
1768 (fmt.write_str("mfence")),
1769
1770 lfence() =>
1772 InstBuf::from_array([0x0f, 0xae, 0xe8]),
1773 None,
1774 (fmt.write_str("lfence")),
1775
1776 rdtscp() =>
1778 InstBuf::from_array([0x0f, 0x01, 0xf9]),
1779 None,
1780 (fmt.write_str("rdtscp")),
1781
1782 rdpmc() =>
1784 InstBuf::from_array([0x0f, 0x33]),
1785 None,
1786 (fmt.write_str("rdpmc")),
1787
1788 cpuid() =>
1790 InstBuf::from_array([0x0f, 0xa2]),
1791 None,
1792 (fmt.write_str("cpuid")),
1793
1794 call(RegMem) => {
1796 Inst::new(0xff).modrm_opext(0b010).regmem(self.0).encode()
1797 },
1798 None,
1799 ({
1800 match self.0 {
1801 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("call {}", reg)),
1802 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("call qword {}", mem)),
1803 }
1804 }),
1805
1806 call_rel32(i32) =>
1807 Inst::new(0xe8).imm32(self.0 as u32).encode(),
1808 None,
1809 (fmt.write_fmt(core::format_args!("call 0x{:x}", i64::from(self.0).wrapping_add(5)))),
1810
1811 jmp(RegMem) => {
1813 Inst::new(0xff).modrm_opext(0b100).regmem(self.0).encode()
1814 },
1815 None,
1816 ({
1817 match self.0 {
1818 RegMem::Reg(reg) => fmt.write_fmt(core::format_args!("jmp {}", reg)),
1819 RegMem::Mem(mem) => fmt.write_fmt(core::format_args!("jmp qword {}", mem)),
1820 }
1821 }),
1822
1823 jmp_rel8(i8) =>
1824 Inst::new(0xeb).imm8(self.0 as u8).encode(),
1825 None,
1826 (fmt.write_fmt(core::format_args!("jmp short 0x{:x}", i64::from(self.0).wrapping_add(2)))),
1827
1828 jmp_rel32(i32) =>
1829 Inst::new(0xe9).imm32(self.0 as u32).encode(),
1830 None,
1831 (fmt.write_fmt(core::format_args!("jmp 0x{:x}", i64::from(self.0).wrapping_add(5)))),
1832
1833 jcc_rel8(Condition, i8) =>
1835 Inst::new(0x70 | self.0 as u8).imm8(self.1 as u8).encode(),
1836 None,
1837 (fmt.write_fmt(core::format_args!("j{} short 0x{:x}", self.0.suffix(), i64::from(self.1).wrapping_add(2)))),
1838
1839 jcc_rel32(Condition, i32) =>
1840 Inst::new(0x80 | self.0 as u8).op_alt().imm32(self.1 as u32).encode(),
1841 None,
1842 (fmt.write_fmt(core::format_args!("j{} near 0x{:x}", self.0.suffix(), i64::from(self.1).wrapping_add(6)))),
1843
1844 jmp_label8(Label) =>
1846 ud2().encode(),
1847 Some((self.0, FixupKind::new_1(0xeb, 1))),
1848 (fmt.write_fmt(core::format_args!("jmp {}", self.0))),
1849
1850 jmp_label32(Label) =>
1851 InstBuf::from_array([0x0f, 0x0b, 0x90, 0x0f, 0x0b]),
1852 Some((self.0, FixupKind::new_1(0xe9, 4))),
1853 (fmt.write_fmt(core::format_args!("jmp {}", self.0))),
1854
1855 call_label32(Label) =>
1856 InstBuf::from_array([0x0f, 0x0b, 0x90, 0x0f, 0x0b]),
1857 Some((self.0, FixupKind::new_1(0xe8, 4))),
1858 (fmt.write_fmt(core::format_args!("call {}", self.0))),
1859
1860 jcc_label8(Condition, Label) =>
1861 ud2().encode(),
1862 Some((self.1, FixupKind::new_1(0x70 | self.0 as u32, 1))),
1863 (fmt.write_fmt(core::format_args!("j{} {}", self.0.suffix(), self.1))),
1864
1865 jcc_label32(Condition, Label) =>
1866 InstBuf::from_array([0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b]),
1867 Some((self.1, FixupKind::new_2([0x0f, 0x80 | self.0 as u32], 4))),
1868 (fmt.write_fmt(core::format_args!("j{} {}", self.0.suffix(), self.1))),
1869
1870 jcc_label32_default(Condition, Label, i32) =>
1871 Inst::new(0x80 | self.0 as u8).op_alt().imm32(self.2 as u32).encode(),
1872 Some((self.1, FixupKind::new_2([0x0f, 0x80 | self.0 as u32], 4))),
1873 (fmt.write_fmt(core::format_args!("j{} {} or near 0x{:x}", self.0.suffix(), self.1, i64::from(self.2).wrapping_add(6)))),
1874
1875 lea_rip_label(Reg, Label) =>
1876 InstBuf::from_array([0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b, 0x90]),
1877 {
1878 let inst = Inst::new(0x8d).rex_64b().modrm_reg(self.0).mem(MemOp::RipRelative(None, 0));
1879 Some((self.1, FixupKind::new_3([u32::from(inst.rex), u32::from(inst.opcode), u32::from(inst.modrm)], 4)))
1880 },
1881 (fmt.write_fmt(core::format_args!("lea {}, [{}]", self.0, self.1))),
1882 }
1883}
1884
1885#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1886pub enum Condition {
1887 Overflow = 0,
1888 NotOverflow = 1,
1889 Below = 2, AboveOrEqual = 3, Equal = 4,
1892 NotEqual = 5,
1893 BelowOrEqual = 6, Above = 7, Sign = 8,
1896 NotSign = 9,
1897 Parity = 10,
1898 NotParity = 11,
1899 Less = 12, GreaterOrEqual = 13, LessOrEqual = 14, Greater = 15, }
1904
1905impl Condition {
1906 const fn suffix(self) -> &'static str {
1907 use Condition::*;
1908 match self {
1909 Overflow => "o",
1910 NotOverflow => "no",
1911 Below => "b",
1912 AboveOrEqual => "ae",
1913 Equal => "e",
1914 NotEqual => "ne",
1915 BelowOrEqual => "be",
1916 Above => "a",
1917 Sign => "s",
1918 NotSign => "ns",
1919 Parity => "p",
1920 NotParity => "np",
1921 Less => "l",
1922 GreaterOrEqual => "ge",
1923 LessOrEqual => "le",
1924 Greater => "g",
1925 }
1926 }
1927}
1928
1929#[cfg(feature = "alloc")]
1930#[cfg(test)]
1931impl tests::GenerateTestValues for Condition {
1932 fn generate_test_values(cb: impl FnMut(Self)) {
1933 use Condition::*;
1934 [
1935 Overflow,
1936 NotOverflow,
1937 Below,
1938 AboveOrEqual,
1939 Equal,
1940 NotEqual,
1941 BelowOrEqual,
1942 Above,
1943 Sign,
1944 NotSign,
1945 Parity,
1946 NotParity,
1947 Less,
1948 GreaterOrEqual,
1949 LessOrEqual,
1950 Greater,
1951 ]
1952 .into_iter()
1953 .for_each(cb);
1954 }
1955}
1956
1957#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1958pub enum RegSize {
1959 R32,
1960 R64,
1961}
1962
1963#[cfg(feature = "alloc")]
1964#[cfg(test)]
1965impl tests::GenerateTestValues for RegSize {
1966 fn generate_test_values(cb: impl FnMut(Self)) {
1967 use RegSize::*;
1968 [R32, R64].into_iter().for_each(cb);
1969 }
1970}
1971
1972#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
1973pub enum LoadKind {
1974 U8,
1975 U16,
1976 U32,
1977 #[default]
1978 U64,
1979 I8,
1980 I16,
1981 I32,
1982}
1983
1984#[cfg(feature = "alloc")]
1985#[cfg(test)]
1986impl tests::GenerateTestValues for LoadKind {
1987 fn generate_test_values(cb: impl FnMut(Self)) {
1988 use LoadKind::*;
1989 [U8, U16, U32, U64, I8, I16, I32].into_iter().for_each(cb);
1990 }
1991}
1992
1993#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
1994pub enum Size {
1995 U8,
1996 U16,
1997 U32,
1998 #[default]
1999 U64,
2000}
2001
2002impl Size {
2003 fn name(self) -> &'static str {
2004 match self {
2005 Size::U8 => "byte",
2006 Size::U16 => "word",
2007 Size::U32 => "dword",
2008 Size::U64 => "qword",
2009 }
2010 }
2011}
2012
2013impl From<RegSize> for Size {
2014 #[inline]
2015 fn from(reg_size: RegSize) -> Size {
2016 match reg_size {
2017 RegSize::R32 => Size::U32,
2018 RegSize::R64 => Size::U64,
2019 }
2020 }
2021}
2022
2023#[cfg(feature = "alloc")]
2024#[cfg(test)]
2025impl tests::GenerateTestValues for Size {
2026 fn generate_test_values(cb: impl FnMut(Self)) {
2027 use Size::*;
2028 [U8, U16, U32, U64].into_iter().for_each(cb);
2029 }
2030}
2031
2032#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2033pub enum ImmKind {
2034 I8(u8),
2035 I16(u16),
2036 I32(u32),
2037 I64(i32),
2038}
2039
2040impl core::fmt::Display for ImmKind {
2041 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
2042 match *self {
2043 ImmKind::I64(value) => fmt.write_fmt(core::format_args!("0x{:x}", i64::from(value))),
2044 ImmKind::I32(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2045 ImmKind::I16(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2046 ImmKind::I8(value) => fmt.write_fmt(core::format_args!("0x{:x}", value)),
2047 }
2048 }
2049}
2050
2051impl ImmKind {
2052 #[inline]
2053 const fn size(self) -> Size {
2054 match self {
2055 ImmKind::I8(..) => Size::U8,
2056 ImmKind::I16(..) => Size::U16,
2057 ImmKind::I32(..) => Size::U32,
2058 ImmKind::I64(..) => Size::U64,
2059 }
2060 }
2061}
2062
2063#[cfg(feature = "alloc")]
2064#[cfg(test)]
2065impl tests::GenerateTestValues for ImmKind {
2066 fn generate_test_values(mut cb: impl FnMut(Self)) {
2067 use ImmKind::*;
2068 u8::generate_test_values(|imm| cb(I8(imm)));
2069 u16::generate_test_values(|imm| cb(I16(imm)));
2070 u32::generate_test_values(|imm| cb(I32(imm)));
2071 i32::generate_test_values(|imm| cb(I64(imm)));
2072 }
2073}
2074
2075#[cfg(feature = "alloc")]
2076#[cfg(test)]
2077mod tests {
2078 pub trait GenerateTestValues: Copy {
2079 fn generate_test_values(cb: impl FnMut(Self));
2080 }
2081
2082 impl GenerateTestValues for super::Reg {
2083 fn generate_test_values(cb: impl FnMut(Self)) {
2084 use super::Reg::*;
2085 [rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15]
2086 .into_iter()
2087 .for_each(cb);
2088 }
2089 }
2090
2091 impl GenerateTestValues for super::RegIndex {
2092 fn generate_test_values(cb: impl FnMut(Self)) {
2093 use super::RegIndex::*;
2094 [rax, rcx, rdx, rbx, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15]
2095 .into_iter()
2096 .for_each(cb);
2097 }
2098 }
2099
2100 impl GenerateTestValues for super::SegReg {
2101 fn generate_test_values(cb: impl FnMut(Self)) {
2102 use super::SegReg::*;
2103 [fs, gs].into_iter().for_each(cb);
2104 }
2105 }
2106
2107 impl GenerateTestValues for super::Scale {
2108 fn generate_test_values(cb: impl FnMut(Self)) {
2109 use super::Scale::*;
2110 [x1, x2, x4, x8].into_iter().for_each(cb);
2111 }
2112 }
2113
2114 impl GenerateTestValues for super::MemOp {
2115 fn generate_test_values(mut cb: impl FnMut(Self)) {
2116 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2117 super::RegSize::generate_test_values(|reg_size| {
2118 super::Reg::generate_test_values(|base| {
2119 i32::generate_test_values(|offset| cb(super::MemOp::BaseOffset(seg_reg, reg_size, base, offset)))
2120 })
2121 })
2122 });
2123
2124 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2125 super::RegSize::generate_test_values(|reg_size| {
2126 super::Reg::generate_test_values(|base| {
2127 super::RegIndex::generate_test_values(|index| {
2128 super::Scale::generate_test_values(|scale| {
2129 i32::generate_test_values(|offset| {
2130 cb(super::MemOp::BaseIndexScaleOffset(seg_reg, reg_size, base, index, scale, offset))
2131 })
2132 })
2133 })
2134 })
2135 })
2136 });
2137
2138 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2139 super::RegSize::generate_test_values(|reg_size| {
2140 super::RegIndex::generate_test_values(|base| {
2141 super::Scale::generate_test_values(|scale| {
2142 i32::generate_test_values(|offset| cb(super::MemOp::IndexScaleOffset(seg_reg, reg_size, base, scale, offset)))
2143 })
2144 })
2145 })
2146 });
2147
2148 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2149 super::RegSize::generate_test_values(|reg_size| {
2150 i32::generate_test_values(|offset| cb(super::MemOp::Offset(seg_reg, reg_size, offset)))
2151 })
2152 });
2153
2154 Option::<super::SegReg>::generate_test_values(|seg_reg| {
2155 i32::generate_test_values(|offset| cb(super::MemOp::RipRelative(seg_reg, offset)))
2156 });
2157 }
2158 }
2159
2160 impl GenerateTestValues for super::RegMem {
2161 fn generate_test_values(mut cb: impl FnMut(Self)) {
2162 super::Reg::generate_test_values(|reg| cb(super::RegMem::Reg(reg)));
2163 super::MemOp::generate_test_values(|mem| cb(super::RegMem::Mem(mem)));
2164 }
2165 }
2166
2167 impl GenerateTestValues for super::Operands {
2168 fn generate_test_values(mut cb: impl FnMut(Self)) {
2169 super::RegMem::generate_test_values(|regmem| {
2170 super::Size::generate_test_values(|size| {
2171 super::Reg::generate_test_values(|reg| {
2172 cb(super::Operands::RegMem_Reg(size, regmem, reg));
2173 cb(super::Operands::Reg_RegMem(size, reg, regmem));
2174 });
2175 });
2176
2177 super::ImmKind::generate_test_values(|imm| {
2178 cb(super::Operands::RegMem_Imm(regmem, imm));
2179 });
2180 });
2181 }
2182 }
2183
2184 impl GenerateTestValues for crate::Label {
2185 fn generate_test_values(_: impl FnMut(Self)) {
2186 unimplemented!();
2187 }
2188 }
2189
2190 impl GenerateTestValues for () {
2191 fn generate_test_values(mut cb: impl FnMut(Self)) {
2192 cb(())
2193 }
2194 }
2195
2196 impl<T> GenerateTestValues for Option<T>
2197 where
2198 T: GenerateTestValues,
2199 {
2200 fn generate_test_values(mut cb: impl FnMut(Self)) {
2201 cb(None);
2202 T::generate_test_values(move |value| cb(Some(value)))
2203 }
2204 }
2205
2206 impl GenerateTestValues for u8 {
2207 fn generate_test_values(cb: impl FnMut(Self)) {
2208 [0, 1, 31, 0x7f, 0x80, 0x81, 0xfe, 0xff].into_iter().for_each(cb);
2209 }
2210 }
2211
2212 impl GenerateTestValues for i8 {
2213 fn generate_test_values(mut cb: impl FnMut(Self)) {
2214 u8::generate_test_values(|value| cb(value as i8))
2215 }
2216 }
2217
2218 impl GenerateTestValues for u16 {
2219 fn generate_test_values(cb: impl FnMut(Self)) {
2220 [
2221 0, 1, 0x7f, 0x80, 0x81, 0xfe, 0xff, 0x100, 0x101, 0x7fff, 0x8000, 0x8001, 0xfffe, 0xffff,
2222 ]
2223 .into_iter()
2224 .for_each(cb);
2225 }
2226 }
2227
2228 impl GenerateTestValues for i16 {
2229 fn generate_test_values(mut cb: impl FnMut(Self)) {
2230 u16::generate_test_values(|value| cb(value as i16))
2231 }
2232 }
2233
2234 impl GenerateTestValues for u32 {
2235 fn generate_test_values(cb: impl FnMut(Self)) {
2236 [
2237 0, 1, 0x7f, 0x80, 0x81, 0xfe, 0xff, 0x100, 0x101, 0x7fff, 0x8000, 0x8001, 0xfffe, 0xffff, 0x10000, 0x10001, 0x7fffffff,
2238 0x80000000, 0x80000001, 0xfffffffe, 0xffffffff,
2239 ]
2240 .into_iter()
2241 .for_each(cb);
2242 }
2243 }
2244
2245 impl GenerateTestValues for i32 {
2246 fn generate_test_values(mut cb: impl FnMut(Self)) {
2247 u32::generate_test_values(|value| cb(value as i32))
2248 }
2249 }
2250
2251 impl GenerateTestValues for u64 {
2252 fn generate_test_values(cb: impl FnMut(Self)) {
2253 [
2254 0,
2255 1,
2256 0x7f,
2257 0x80,
2258 0x81,
2259 0xfe,
2260 0xff,
2261 0x100,
2262 0x101,
2263 0x7fff,
2264 0x8000,
2265 0x8001,
2266 0xfffe,
2267 0xffff,
2268 0x10000,
2269 0x10001,
2270 0x7fffffff,
2271 0x80000000,
2272 0x80000001,
2273 0xfffffffe,
2274 0xffffffff,
2275 0x100000000,
2276 0x100000001,
2277 0x7fffffffffffffff,
2278 0x8000000000000000,
2279 0x8000000000000001,
2280 0xfffffffffffffffe,
2281 0xffffffffffffffff,
2282 ]
2283 .into_iter()
2284 .for_each(cb);
2285 }
2286 }
2287
2288 use alloc::format;
2289 use alloc::string::String;
2290
2291 fn disassemble(code: &[u8]) -> String {
2292 let mut output = String::new();
2293 disassemble_into(code, &mut output);
2294 output
2295 }
2296
2297 fn disassemble_into(mut code: &[u8], output: &mut String) {
2298 use core::fmt::Write;
2299 use iced_x86::Formatter;
2300
2301 let mut formatter = iced_x86::NasmFormatter::new();
2302 formatter.options_mut().set_space_after_operand_separator(true);
2303 formatter.options_mut().set_hex_prefix("0x");
2304 formatter.options_mut().set_hex_suffix("");
2305 formatter.options_mut().set_uppercase_hex(false);
2306 formatter.options_mut().set_small_hex_numbers_in_decimal(false);
2307 formatter.options_mut().set_show_useless_prefixes(true);
2308 formatter.options_mut().set_branch_leading_zeros(false);
2309 formatter.options_mut().set_rip_relative_addresses(true);
2310 let code_origin = 0;
2311 let mut position = 0;
2312 loop {
2313 let mut decoder = iced_x86::Decoder::with_ip(64, code, code_origin, iced_x86::DecoderOptions::NONE);
2314 if !decoder.can_decode() {
2315 break;
2316 }
2317 let mut instruction = iced_x86::Instruction::default();
2318 decoder.decode_out(&mut instruction);
2319
2320 write!(output, "{:08x} ", position).unwrap();
2321 let start_index = (instruction.ip() - code_origin) as usize;
2322 let instr_bytes = &code[start_index..start_index + instruction.len()];
2323 for b in instr_bytes.iter() {
2324 write!(output, "{:02x}", b).unwrap();
2325 }
2326
2327 output.push(' ');
2328 formatter.format(&instruction, output);
2329 output.push('\n');
2330 code = &code[instruction.len()..];
2331 position += instruction.len();
2332 }
2333
2334 output.pop();
2335 }
2336
2337 struct TestAsm {
2338 asm: crate::Assembler,
2339 disassembly_1: String,
2340 disassembly_2: String,
2341 }
2342
2343 impl TestAsm {
2344 fn new() -> Self {
2345 Self {
2346 asm: crate::Assembler::new(),
2347 disassembly_1: String::new(),
2348 disassembly_2: String::new(),
2349 }
2350 }
2351
2352 fn run<T>(&mut self, inst: crate::Instruction<T>)
2353 where
2354 T: Copy + core::fmt::Display + core::fmt::Debug,
2355 {
2356 use core::fmt::Write;
2357
2358 self.asm.clear();
2359 self.disassembly_1.clear();
2360 self.disassembly_2.clear();
2361
2362 let position = self.asm.len();
2363 self.asm.push(inst);
2364 let ranges = [(inst, position..self.asm.len())];
2365
2366 let code = self.asm.finalize();
2367 let mut position = 0;
2368 for (inst, range) in ranges {
2369 write!(&mut self.disassembly_1, "{:08x} ", position).unwrap();
2370 for &b in &code[range.clone()] {
2371 write!(&mut self.disassembly_1, "{:02x}", b).unwrap();
2372 }
2373 position += range.len();
2374 writeln!(&mut self.disassembly_1, " {}", inst).unwrap();
2375 }
2376
2377 self.disassembly_1.pop();
2378 disassemble_into(&code, &mut self.disassembly_2);
2379 assert_eq!(self.disassembly_1, self.disassembly_2, "broken encoding for: {inst:?}");
2380 }
2381 }
2382
2383 macro_rules! generate_tests {
2384 ($($inst_name:ident,)+) => {
2385 $(
2386 #[test]
2387 fn $inst_name() {
2388 let mut test = TestAsm::new();
2389 <super::inst::types::$inst_name as GenerateTestValues>::generate_test_values(|instruction| {
2390 test.run(crate::Instruction {
2391 bytes: instruction.encode(),
2392 fixup: None,
2393 instruction
2394 })
2395 });
2396 }
2397 )+
2398 }
2399 }
2400
2401 generate_tests! {
2402 add,
2403 and,
2404 bts,
2405 call_rel32,
2406 call,
2407 cdq,
2408 clflushopt,
2409 cmov,
2410 cmp,
2411 cpuid,
2412 cqo,
2413 dec,
2414 div,
2415 endbr64,
2416 idiv,
2417 imul_dx_ax,
2418 imul_imm,
2419 imul,
2420 inc,
2421 jcc_rel32,
2422 jcc_rel8,
2423 jmp_rel32,
2424 jmp_rel8,
2425 jmp,
2426 lea,
2427 lfence,
2428 load,
2429 mfence,
2430 mov_imm,
2431 mov_imm64,
2432 mov,
2433 movsx_8_to_64,
2434 movsx_16_to_64,
2435 movzx_16_to_64,
2436 movsxd_32_to_64,
2437 mul,
2438 mul_dx_ax,
2439 neg,
2440 nop,
2441 nop10,
2442 nop11,
2443 nop2,
2444 nop3,
2445 nop4,
2446 nop5,
2447 nop6,
2448 nop7,
2449 nop8,
2450 nop9,
2451 not,
2452 or,
2453 pause,
2454 pop,
2455 push,
2456 push_imm,
2457 rcr_imm,
2458 rdpmc,
2459 rdtscp,
2460 ret,
2461 ror_imm,
2462 rol_cl,
2463 ror_cl,
2464 sar_cl,
2465 sar_imm,
2466 popcnt,
2467 lzcnt,
2468 tzcnt,
2469 setcc,
2470 bswap,
2471 shl_cl,
2472 shl_imm,
2473 shr_cl,
2474 shr_imm,
2475 store,
2476 sub,
2477 syscall,
2478 test,
2479 ud2,
2480 xchg_mem,
2481 xor,
2482 }
2483
2484 #[test]
2485 fn jmp_label8_infinite_loop() {
2486 use super::inst::*;
2487 let mut asm = crate::Assembler::new();
2488 let label = asm.forward_declare_label();
2489 asm.push_with_label(label, jmp_label8(label));
2490 let disassembly = disassemble(&asm.finalize());
2491 assert_eq!(disassembly, "00000000 ebfe jmp short 0x0");
2492 }
2493
2494 #[test]
2495 fn jmp_label8_undefined() {
2496 use super::inst::*;
2497 let mut asm = crate::Assembler::new();
2498 let label = asm.forward_declare_label();
2499 asm.push(jmp_label8(label));
2500 let disassembly = disassemble(&asm.finalize());
2501 assert_eq!(disassembly, "00000000 0f0b ud2");
2502 }
2503
2504 #[test]
2505 fn jmp_label32_infinite_loop() {
2506 use super::inst::*;
2507 let mut asm = crate::Assembler::new();
2508 let label = asm.forward_declare_label();
2509 asm.push_with_label(label, jmp_label32(label));
2510 let disassembly = disassemble(&asm.finalize());
2511 assert_eq!(disassembly, "00000000 e9fbffffff jmp 0x0");
2512 }
2513
2514 #[test]
2515 fn jmp_label32_undefined() {
2516 use super::inst::*;
2517 let mut asm = crate::Assembler::new();
2518 let label = asm.forward_declare_label();
2519 asm.push(jmp_label32(label));
2520 let disassembly = disassemble(&asm.finalize());
2521 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 90 nop\n00000003 0f0b ud2");
2522 }
2523
2524 #[test]
2525 fn call_label32_infinite_loop() {
2526 use super::inst::*;
2527 let mut asm = crate::Assembler::new();
2528 let label = asm.forward_declare_label();
2529 asm.push_with_label(label, call_label32(label));
2530 let disassembly = disassemble(&asm.finalize());
2531 assert_eq!(disassembly, "00000000 e8fbffffff call 0x0");
2532 }
2533
2534 #[test]
2535 fn call_label32_undefined() {
2536 use super::inst::*;
2537 let mut asm = crate::Assembler::new();
2538 let label = asm.forward_declare_label();
2539 asm.push(call_label32(label));
2540 let disassembly = disassemble(&asm.finalize());
2541 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 90 nop\n00000003 0f0b ud2");
2542 }
2543
2544 #[test]
2545 fn jcc_label8_infinite_loop() {
2546 use super::inst::*;
2547 super::Condition::generate_test_values(|cond| {
2548 let mut asm = crate::Assembler::new();
2549 let label = asm.forward_declare_label();
2550 asm.push_with_label(label, jcc_label8(cond, label));
2551 let disassembly = disassemble(&asm.finalize());
2552 assert_eq!(
2553 disassembly,
2554 format!("00000000 {:02x}fe j{} short 0x0", 0x70 + cond as u8, cond.suffix())
2555 );
2556 });
2557 }
2558
2559 #[test]
2560 fn jcc_label8_undefined() {
2561 use super::inst::*;
2562 super::Condition::generate_test_values(|cond| {
2563 let mut asm = crate::Assembler::new();
2564 let label = asm.forward_declare_label();
2565 asm.push(jcc_label8(cond, label));
2566 let disassembly = disassemble(&asm.finalize());
2567 assert_eq!(disassembly, "00000000 0f0b ud2");
2568 });
2569 }
2570
2571 #[test]
2572 fn jcc_label8_jump_forward() {
2573 use super::inst::*;
2574 super::Condition::generate_test_values(|cond| {
2575 let mut asm = crate::Assembler::new();
2576 let label = asm.forward_declare_label();
2577 asm.push(jcc_label8(cond, label));
2578 asm.push_with_label(label, nop());
2579 let disassembly = disassemble(&asm.finalize());
2580 assert_eq!(
2581 disassembly,
2582 format!(
2583 concat!("00000000 {:02x}00 j{} short 0x2\n", "00000002 90 nop",),
2584 0x70 + cond as u8,
2585 cond.suffix()
2586 )
2587 );
2588 })
2589 }
2590
2591 #[test]
2592 fn jcc_label8_jump_backward() {
2593 use super::inst::*;
2594 super::Condition::generate_test_values(|cond| {
2595 let mut asm = crate::Assembler::new();
2596 let label = asm.forward_declare_label();
2597 asm.push_with_label(label, nop());
2598 asm.push(jcc_label8(cond, label));
2599 let disassembly = disassemble(&asm.finalize());
2600 assert_eq!(
2601 disassembly,
2602 format!(
2603 concat!("00000000 90 nop\n", "00000001 {:02x}fd j{} short 0xffffffffffffffff",),
2604 0x70 + cond as u8,
2605 cond.suffix()
2606 )
2607 );
2608 });
2609 }
2610
2611 #[test]
2612 fn jcc_label32_jump_forward() {
2613 use super::inst::*;
2614 super::Condition::generate_test_values(|cond| {
2615 let mut asm = crate::Assembler::new();
2616 let label = asm.forward_declare_label();
2617 asm.push(jcc_label32(cond, label));
2618 asm.push_with_label(label, nop());
2619 let disassembly = disassemble(&asm.finalize());
2620 assert_eq!(
2621 disassembly,
2622 format!(
2623 concat!("00000000 0f{:02x}00000000 j{} near 0x6\n", "00000006 90 nop",),
2624 0x80 + cond as u8,
2625 cond.suffix()
2626 )
2627 );
2628 });
2629 }
2630
2631 #[test]
2632 fn jcc_label32_undefined() {
2633 use super::inst::*;
2634 super::Condition::generate_test_values(|cond| {
2635 let mut asm = crate::Assembler::new();
2636 let label = asm.forward_declare_label();
2637 asm.push(jcc_label32(cond, label));
2638 let disassembly = disassemble(&asm.finalize());
2639 assert_eq!(disassembly, "00000000 0f0b ud2\n00000002 0f0b ud2\n00000004 0f0b ud2");
2640 });
2641 }
2642
2643 #[test]
2644 fn lea_rip_label_infinite_loop() {
2645 use super::inst::*;
2646 let mut asm = crate::Assembler::new();
2647 let label = asm.forward_declare_label();
2648 asm.push_with_label(label, lea_rip_label(super::Reg::rax, label));
2649 let disassembly = disassemble(&asm.finalize());
2650 assert_eq!(disassembly, "00000000 488d05f9ffffff lea rax, [rip-0x7]");
2651 }
2652
2653 #[test]
2654 fn lea_rip_label_undefined() {
2655 use super::inst::*;
2656 super::Reg::generate_test_values(|reg| {
2657 let mut asm = crate::Assembler::new();
2658 let label = asm.forward_declare_label();
2659 asm.push(lea_rip_label(reg, label));
2660 let disassembly = disassemble(&asm.finalize());
2661 assert_eq!(
2662 disassembly,
2663 "00000000 0f0b ud2\n00000002 0f0b ud2\n00000004 0f0b ud2\n00000006 90 nop"
2664 );
2665 });
2666 }
2667
2668 #[test]
2669 fn lea_rip_label_next_instruction() {
2670 use super::inst::*;
2671 let mut asm = crate::Assembler::new();
2672 let label = asm.forward_declare_label();
2673 asm.push(lea_rip_label(super::Reg::rax, label));
2674 asm.push_with_label(label, nop());
2675 let disassembly = disassemble(&asm.finalize());
2676 assert_eq!(disassembly, "00000000 488d0500000000 lea rax, [rip]\n00000007 90 nop");
2677 }
2678}