1#![allow(clippy::too_many_arguments)]
11
12#[allow(unused_imports)]
13use alloc::string::String;
14#[allow(unused_imports)]
15use alloc::string::ToString;
16#[allow(unused_imports)]
17use alloc::vec;
18use alloc::vec::Vec;
19
20use crate::error::AsmError;
21#[allow(unused_imports)]
22use crate::error::Span;
23use crate::ir::*;
24
25#[derive(Clone)]
37pub struct InstrBytes {
38 data: [u8; 32],
39 len: u8,
40}
41
42impl InstrBytes {
43 #[inline]
45 pub const fn new() -> Self {
46 Self {
47 data: [0; 32],
48 len: 0,
49 }
50 }
51
52 #[inline]
54 pub fn from_slice(src: &[u8]) -> Self {
55 let mut buf = Self::new();
56 buf.extend_from_slice(src);
57 buf
58 }
59
60 #[inline]
69 pub fn push(&mut self, byte: u8) {
70 assert!(
71 (self.len as usize) < 32,
72 "InstrBytes overflow: cannot push beyond 32 bytes"
73 );
74 self.data[self.len as usize] = byte;
75 self.len += 1;
76 }
77
78 #[inline]
85 pub fn extend_from_slice(&mut self, bytes: &[u8]) {
86 let start = self.len as usize;
87 let end = start + bytes.len();
88 assert!(
89 end <= 32,
90 "InstrBytes overflow: {} + {} exceeds 32-byte capacity",
91 start,
92 bytes.len()
93 );
94 self.data[start..end].copy_from_slice(bytes);
95 self.len = end as u8;
96 }
97
98 #[inline]
104 pub fn insert(&mut self, pos: usize, byte: u8) {
105 let len = self.len as usize;
106 assert!(
107 pos <= len && len < 32,
108 "InstrBytes insert: pos={} len={} out of bounds",
109 pos,
110 len
111 );
112 let mut i = len;
114 while i > pos {
115 self.data[i] = self.data[i - 1];
116 i -= 1;
117 }
118 self.data[pos] = byte;
119 self.len += 1;
120 }
121
122 #[inline]
128 pub fn remove(&mut self, pos: usize) {
129 let len = self.len as usize;
130 assert!(
131 pos < len,
132 "InstrBytes remove: pos={} out of bounds (len={})",
133 pos,
134 len
135 );
136 let mut i = pos;
137 while i + 1 < len {
138 self.data[i] = self.data[i + 1];
139 i += 1;
140 }
141 self.data[len - 1] = 0;
142 self.len -= 1;
143 }
144
145 #[inline]
147 pub fn len(&self) -> usize {
148 self.len as usize
149 }
150
151 #[inline]
153 pub fn is_empty(&self) -> bool {
154 self.len == 0
155 }
156
157 #[inline]
159 pub fn to_vec(&self) -> Vec<u8> {
160 self.as_ref().to_vec()
161 }
162}
163
164impl Default for InstrBytes {
165 #[inline]
166 fn default() -> Self {
167 Self::new()
168 }
169}
170
171impl core::ops::Deref for InstrBytes {
172 type Target = [u8];
173 #[inline]
174 fn deref(&self) -> &[u8] {
175 &self.data[..self.len as usize]
176 }
177}
178
179impl core::ops::DerefMut for InstrBytes {
180 #[inline]
181 fn deref_mut(&mut self) -> &mut [u8] {
182 &mut self.data[..self.len as usize]
183 }
184}
185
186impl AsRef<[u8]> for InstrBytes {
187 #[inline]
188 fn as_ref(&self) -> &[u8] {
189 self
190 }
191}
192
193impl AsMut<[u8]> for InstrBytes {
194 #[inline]
195 fn as_mut(&mut self) -> &mut [u8] {
196 self
197 }
198}
199
200impl core::fmt::Debug for InstrBytes {
201 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
202 f.debug_list().entries(self.iter()).finish()
203 }
204}
205
206impl PartialEq for InstrBytes {
207 fn eq(&self, other: &Self) -> bool {
208 **self == **other
209 }
210}
211
212impl Eq for InstrBytes {}
213
214impl PartialEq<[u8]> for InstrBytes {
215 fn eq(&self, other: &[u8]) -> bool {
216 **self == *other
217 }
218}
219
220impl PartialEq<Vec<u8>> for InstrBytes {
221 fn eq(&self, other: &Vec<u8>) -> bool {
222 **self == **other
223 }
224}
225
226#[derive(Debug, Clone)]
230pub struct EncodedInstr {
231 pub bytes: InstrBytes,
233 pub relocation: Option<Relocation>,
235 pub relax: Option<RelaxInfo>,
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq)]
241#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
242pub enum RelocKind {
243 X86Relative,
246 Absolute,
248 #[cfg(feature = "arm")]
250 ArmBranch24,
251 #[cfg(feature = "arm")]
253 ArmLdrLit,
254 #[cfg(feature = "arm")]
257 ArmAdr,
258 #[cfg(feature = "arm")]
261 ThumbBranch8,
262 #[cfg(feature = "arm")]
265 ThumbBranch11,
266 #[cfg(feature = "arm")]
268 ThumbBl,
269 #[cfg(feature = "arm")]
271 ThumbBranchW,
272 #[cfg(feature = "arm")]
274 ThumbCondBranchW,
275 #[cfg(feature = "arm")]
278 ThumbLdrLit8,
279 #[cfg(feature = "aarch64")]
281 Aarch64Jump26,
282 #[cfg(feature = "aarch64")]
284 Aarch64Branch19,
285 #[cfg(feature = "aarch64")]
287 Aarch64Branch14,
288 #[cfg(feature = "aarch64")]
290 Aarch64LdrLit19,
291 #[cfg(feature = "aarch64")]
293 Aarch64Adr21,
294 #[cfg(feature = "aarch64")]
296 Aarch64Adrp,
297 #[cfg(feature = "aarch64")]
301 Aarch64AdrpAddPair,
302 #[cfg(feature = "riscv")]
304 RvJal20,
305 #[cfg(feature = "riscv")]
307 RvBranch12,
308 #[cfg(feature = "riscv")]
310 RvAuipc20,
311 #[cfg(feature = "riscv")]
313 RvCBranch8,
314 #[cfg(feature = "riscv")]
316 RvCJump11,
317}
318
319#[derive(Debug, Clone)]
321#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
322pub struct Relocation {
323 pub offset: usize,
325 pub size: u8,
327 pub label: alloc::rc::Rc<str>,
331 pub kind: RelocKind,
333 pub addend: i64,
335 pub trailing_bytes: u8,
341}
342
343#[derive(Debug, Clone)]
349pub struct RelaxInfo {
350 pub short_bytes: InstrBytes,
352 pub short_reloc_offset: usize,
354 pub short_relocation: Option<Relocation>,
359}
360
361#[inline]
370#[cfg(any(feature = "x86", feature = "x86_64", feature = "riscv"))]
371pub(crate) fn extract_label(op: &Operand) -> Option<(&str, i64)> {
372 match op {
373 Operand::Label(name) => Some((name.as_str(), 0)),
374 Operand::Expression(expr) => expr.label_addend(),
375 _ => None,
376 }
377}
378
379#[inline]
385pub fn encode_instruction(instr: &Instruction, arch: Arch) -> Result<EncodedInstr, AsmError> {
386 #[allow(unreachable_patterns)]
387 match arch {
388 #[cfg(feature = "x86_64")]
389 Arch::X86_64 => encode_x86_64(instr),
390 #[cfg(feature = "x86")]
391 Arch::X86 => encode_x86_32(instr),
392 #[cfg(feature = "arm")]
393 Arch::Arm | Arch::Thumb => crate::arm::encode_arm(instr, arch),
394 #[cfg(feature = "aarch64")]
395 Arch::Aarch64 => crate::aarch64::encode_aarch64(instr),
396 #[cfg(feature = "riscv")]
397 Arch::Rv32 | Arch::Rv64 => crate::riscv::encode_riscv(instr, arch),
398 _ => Err(AsmError::Syntax {
399 msg: alloc::format!(
400 "encoder not implemented for {} (enable the feature flag)",
401 arch
402 ),
403 span: instr.span,
404 }),
405 }
406}
407
408#[cfg(any(feature = "x86", feature = "x86_64"))]
414fn emit_x86_prefixes(buf: &mut InstrBytes, instr: &Instruction, ops: &OperandList) -> usize {
415 for pfx in &instr.prefixes {
416 match pfx {
417 Prefix::Lock => buf.push(0xF0),
418 Prefix::Rep => buf.push(0xF3),
419 Prefix::Repne => buf.push(0xF2),
420 Prefix::SegFs => buf.push(0x64),
421 Prefix::SegGs => buf.push(0x65),
422 }
423 }
424
425 let has_seg_prefix = instr
428 .prefixes
429 .iter()
430 .any(|p| matches!(p, Prefix::SegFs | Prefix::SegGs));
431 if !has_seg_prefix {
432 for op in ops {
433 if let Operand::Memory(mem) = op {
434 if let Some(seg) = mem.segment {
435 let seg_byte = match seg {
436 Register::Cs => Some(0x2E_u8),
437 Register::Ds => Some(0x3E),
438 Register::Es => Some(0x26),
439 Register::Fs => Some(0x64),
440 Register::Gs => Some(0x65),
441 Register::Ss => Some(0x36),
442 _ => None,
443 };
444 if let Some(b) = seg_byte {
445 buf.push(b);
446 }
447 }
448 }
449 }
450 }
451
452 buf.len()
453}
454
455#[cfg(feature = "x86_64")]
463fn needs_addr_size_override(ops: &OperandList) -> bool {
464 for op in ops {
465 if let Operand::Memory(mem) = op {
466 if let Some(base) = mem.base {
467 if base == Register::Rip {
469 continue;
470 }
471 if base.size_bits() == 32 {
472 return true;
473 }
474 }
475 if let Some(idx) = mem.index {
476 if idx.size_bits() == 32 {
477 return true;
478 }
479 }
480 }
481 }
482 false
483}
484
485#[cfg(any(feature = "x86", feature = "x86_64"))]
487fn validate_lock_prefix(instr: &Instruction, ops: &OperandList) -> Result<(), AsmError> {
488 if instr.prefixes.contains(&Prefix::Lock) {
489 let has_memory_dst = matches!(ops.first(), Some(Operand::Memory(_)));
490 if !has_memory_dst {
491 return Err(AsmError::InvalidOperands {
492 detail: String::from("LOCK prefix requires a memory destination operand"),
493 span: instr.span,
494 });
495 }
496 }
497 Ok(())
498}
499
500#[cfg(any(feature = "x86", feature = "x86_64"))]
505fn propagate_disp_label_reloc(
506 buf: &[u8],
507 ops: &OperandList,
508 prefix_len: usize,
509 reloc: &mut Option<Relocation>,
510) {
511 if reloc.is_some() {
512 return;
513 }
514
515 for op in ops {
516 if let Operand::Memory(mem) = op {
517 if let Some(ref label) = mem.disp_label {
518 if let Some(off) = find_disp_offset_structural(buf, prefix_len) {
523 let kind = if mem.base == Some(Register::Rip) {
524 RelocKind::X86Relative
525 } else {
526 RelocKind::Absolute
527 };
528 *reloc = Some(Relocation {
529 offset: off,
530 size: 4,
531 label: alloc::rc::Rc::from(&**label),
532 kind,
533 addend: mem.disp,
534 trailing_bytes: 0,
535 });
536 }
537 break; }
539 }
540 }
541
542 if let Some(ref mut r) = reloc {
544 if r.kind == RelocKind::X86Relative {
545 let end_of_reloc = r.offset + r.size as usize;
546 r.trailing_bytes = (buf.len() - end_of_reloc) as u8;
547 }
548 }
549}
550
551#[inline]
555#[cfg(any(feature = "x86", feature = "x86_64"))]
556fn is_post_prefix_legacy_byte(b: u8) -> bool {
557 matches!(b, 0x66 | 0x67 | 0xF2 | 0xF3)
558}
559
560#[cfg(any(feature = "x86", feature = "x86_64"))]
570fn find_disp_offset_structural(buf: &[u8], prefix_len: usize) -> Option<usize> {
571 if buf.len() <= prefix_len {
572 return None;
573 }
574
575 let mut pos = prefix_len;
576
577 while pos < buf.len() && is_post_prefix_legacy_byte(buf[pos]) {
581 pos += 1;
582 }
583
584 if pos >= buf.len() {
585 return None;
586 }
587
588 let modrm_pos = if buf[pos] == 0xC5 {
596 pos + 3 } else if buf[pos] == 0xC4 {
598 pos + 4 } else if buf[pos] == 0x62 {
600 pos + 5 } else {
602 if (buf[pos] & 0xF0) == 0x40 {
607 pos += 1;
608 }
609 if pos >= buf.len() {
610 return None;
611 }
612
613 if buf[pos] == 0x0F {
619 pos += 1;
620 if pos >= buf.len() {
621 return None;
622 }
623 if buf[pos] == 0x38 || buf[pos] == 0x3A {
624 pos += 2; } else {
626 pos += 1; }
628 } else {
629 pos += 1; }
631
632 pos
633 };
634
635 if modrm_pos >= buf.len() {
637 return None;
638 }
639
640 let modrm = buf[modrm_pos];
641 let mod_bits = (modrm >> 6) & 0x03;
642 let rm = modrm & 0x07;
643
644 if mod_bits == 0x03 {
646 return None;
647 }
648
649 let mut disp_pos = modrm_pos + 1;
650
651 if rm == 0x04 {
653 if disp_pos >= buf.len() {
654 return None;
655 }
656 let sib_base = buf[disp_pos] & 0x07;
657 disp_pos += 1; match mod_bits {
660 0b00 if sib_base == 0x05 => Some(disp_pos), 0b00 => None, 0b01 | 0b10 => Some(disp_pos), _ => None,
664 }
665 } else {
666 match mod_bits {
667 0b00 if rm == 0x05 => Some(disp_pos), 0b00 => None, 0b01 | 0b10 => Some(disp_pos), _ => None,
671 }
672 }
673}
674
675#[cfg(feature = "x86_64")]
679fn fixup_rip_trailing_bytes(buf: &[u8], reloc: &mut Option<Relocation>) {
680 if let Some(ref mut r) = reloc {
681 if r.kind == RelocKind::X86Relative {
682 let end_of_reloc = r.offset + r.size as usize;
683 r.trailing_bytes = (buf.len() - end_of_reloc) as u8;
684 }
685 }
686}
687
688#[cfg(feature = "x86_64")]
689fn encode_x86_64(instr: &Instruction) -> Result<EncodedInstr, AsmError> {
690 let mut buf = InstrBytes::new();
691 let mut reloc: Option<Relocation> = None;
692 let mut relax_info: Option<RelaxInfo> = None;
693
694 let ops = &instr.operands;
695 let prefix_len = emit_x86_prefixes(&mut buf, instr, ops);
696
697 if needs_addr_size_override(ops) {
700 buf.push(0x67);
701 }
702
703 let mnemonic = instr.mnemonic.as_str();
704
705 match crate::x86::dispatch_x86_64(mnemonic, &mut buf, ops, instr, &mut reloc, &mut relax_info) {
706 Some(Ok(())) => {}
707 Some(Err(e)) => return Err(e),
708 None => {
709 return Err(AsmError::UnknownMnemonic {
710 mnemonic: String::from(mnemonic),
711 arch: crate::error::ArchName::X86_64,
712 span: instr.span,
713 });
714 }
715 }
716
717 validate_lock_prefix(instr, ops)?;
718 propagate_disp_label_reloc(&buf, ops, prefix_len, &mut reloc);
719
720 fixup_rip_trailing_bytes(&buf, &mut reloc);
724
725 Ok(EncodedInstr {
726 bytes: buf,
727 relocation: reloc,
728 relax: relax_info,
729 })
730}
731
732#[cfg(feature = "x86")]
736fn validate_x86_32(instr: &Instruction) -> Result<(), AsmError> {
737 for op in &instr.operands {
738 match op {
739 Operand::Register(reg) => {
740 if reg.size_bits() == 64 {
741 return Err(AsmError::InvalidOperands {
742 detail: String::from("64-bit registers are not available in 32-bit mode"),
743 span: instr.span,
744 });
745 }
746 if reg.is_extended() {
747 return Err(AsmError::InvalidOperands {
748 detail: String::from(
749 "extended registers (R8-R15) are not available in 32-bit mode",
750 ),
751 span: instr.span,
752 });
753 }
754 if reg.requires_rex_for_byte() {
755 return Err(AsmError::InvalidOperands {
756 detail: String::from(
757 "SPL/BPL/SIL/DIL are not available in 32-bit mode (require REX)",
758 ),
759 span: instr.span,
760 });
761 }
762 if matches!(reg, Register::Rip) {
763 return Err(AsmError::InvalidOperands {
764 detail: String::from(
765 "RIP-relative addressing is not available in 32-bit mode",
766 ),
767 span: instr.span,
768 });
769 }
770 }
771 Operand::Memory(mem) => {
772 if let Some(base) = mem.base {
773 if base == Register::Rip {
774 return Err(AsmError::InvalidOperands {
775 detail: String::from(
776 "RIP-relative addressing is not available in 32-bit mode",
777 ),
778 span: instr.span,
779 });
780 }
781 if base.size_bits() == 64 || base.is_extended() {
782 return Err(AsmError::InvalidOperands {
783 detail: String::from(
784 "64-bit/extended registers cannot be used as memory base in 32-bit mode",
785 ),
786 span: instr.span,
787 });
788 }
789 }
790 if let Some(idx) = mem.index {
791 if idx.size_bits() == 64 || idx.is_extended() {
792 return Err(AsmError::InvalidOperands {
793 detail: String::from(
794 "64-bit/extended registers cannot be used as memory index in 32-bit mode",
795 ),
796 span: instr.span,
797 });
798 }
799 }
800 }
801 _ => {}
802 }
803 }
804
805 if instr.mnemonic == "movsxd" {
806 return Err(AsmError::UnknownMnemonic {
807 mnemonic: String::from("movsxd"),
808 arch: crate::error::ArchName::X86,
809 span: instr.span,
810 });
811 }
812
813 Ok(())
814}
815
816#[cfg(feature = "x86")]
823fn encode_x86_32(instr: &Instruction) -> Result<EncodedInstr, AsmError> {
824 validate_x86_32(instr)?;
825
826 let mut buf = InstrBytes::new();
827 let mut reloc: Option<Relocation> = None;
828 let mut relax_info: Option<RelaxInfo> = None;
829
830 let ops = &instr.operands;
831 let prefix_len = emit_x86_prefixes(&mut buf, instr, ops);
832 let mnemonic = instr.mnemonic.as_str();
833
834 match mnemonic {
836 "push" => {
837 encode_push_32(&mut buf, ops, instr, &mut reloc)?;
838 return Ok(EncodedInstr {
839 bytes: buf,
840 relocation: reloc,
841 relax: relax_info,
842 });
843 }
844 "pop" => {
845 encode_pop_32(&mut buf, ops, instr)?;
846 return Ok(EncodedInstr {
847 bytes: buf,
848 relocation: reloc,
849 relax: relax_info,
850 });
851 }
852 "inc" | "dec" => {
853 if let [Operand::Register(reg)] = ops.as_slice() {
859 let size = reg_size(*reg);
860 if size == 16 || size == 32 {
861 if size == 16 {
862 buf.push(0x66);
863 }
864 let base = if mnemonic == "inc" { 0x40 } else { 0x48 };
865 buf.push(base + reg.base_code());
866 return Ok(EncodedInstr {
867 bytes: buf,
868 relocation: reloc,
869 relax: relax_info,
870 });
871 }
872 }
873 }
875 _ => {}
876 }
877
878 match crate::x86::dispatch_x86_64(mnemonic, &mut buf, ops, instr, &mut reloc, &mut relax_info) {
883 Some(Ok(())) => {}
884 Some(Err(e)) => return Err(e),
885 None => {
886 return Err(AsmError::UnknownMnemonic {
887 mnemonic: String::from(mnemonic),
888 arch: crate::error::ArchName::X86,
889 span: instr.span,
890 });
891 }
892 }
893
894 validate_lock_prefix(instr, ops)?;
895 propagate_disp_label_reloc(&buf, ops, prefix_len, &mut reloc);
896
897 Ok(EncodedInstr {
898 bytes: buf,
899 relocation: reloc,
900 relax: relax_info,
901 })
902}
903
904#[cfg(feature = "x86")]
919pub fn encode_instruction_16(instr: &Instruction) -> Result<EncodedInstr, AsmError> {
920 let mut result = encode_x86_32(instr)?;
923
924 toggle_operand_size_prefix_16(&mut result.bytes, &instr.operands, &mut result.relocation);
929
930 Ok(result)
931}
932
933#[cfg(feature = "x86")]
938fn toggle_operand_size_prefix_16(
939 buf: &mut InstrBytes,
940 ops: &OperandList,
941 reloc: &mut Option<Relocation>,
942) {
943 let mut found_66_at = None;
945 for i in 0..buf.len() {
946 let b = buf[i];
947 if b == 0x66 {
948 found_66_at = Some(i);
949 break;
950 }
951 if !is_legacy_prefix(b) && b != 0x67 {
953 break;
954 }
955 }
956
957 if let Some(pos) = found_66_at {
958 buf.remove(pos);
960 if let Some(ref mut r) = reloc {
961 if r.offset > pos {
962 r.offset -= 1;
963 }
964 }
965 } else {
966 let has_32bit_gpr = ops.iter().any(|op| {
969 if let Operand::Register(r) = op {
970 r.size_bits() == 32 && !matches!(r, Register::Eip)
971 } else {
972 false
973 }
974 });
975
976 let has_dword_mem = ops.iter().any(
978 |op| matches!(op, Operand::Memory(m) if m.size == Some(crate::ir::OperandSize::Dword)),
979 );
980
981 if has_32bit_gpr || has_dword_mem {
982 let mut insert_pos = 0;
984 for i in 0..buf.len() {
985 let b = buf[i];
986 if is_legacy_prefix(b) || b == 0x67 {
987 insert_pos = i + 1;
988 } else {
989 break;
990 }
991 }
992 buf.insert(insert_pos, 0x66);
993 if let Some(ref mut r) = reloc {
994 if r.offset >= insert_pos {
995 r.offset += 1;
996 }
997 }
998 }
999 }
1000}
1001
1002#[cfg(feature = "x86")]
1004#[inline]
1005fn is_legacy_prefix(b: u8) -> bool {
1006 matches!(
1007 b,
1008 0xF0 | 0xF2 | 0xF3 | 0x26 | 0x2E | 0x36 | 0x3E | 0x64 | 0x65 | 0x66 | 0x67
1009 )
1010}
1011#[cfg(feature = "x86")]
1012fn encode_push_32(
1013 buf: &mut InstrBytes,
1014 ops: &OperandList,
1015 instr: &Instruction,
1016 reloc: &mut Option<Relocation>,
1017) -> Result<(), AsmError> {
1018 if ops.len() != 1 {
1019 return Err(invalid_operands("push", "expected 1 operand", instr.span));
1020 }
1021 match &ops[0] {
1022 Operand::Register(reg) => {
1023 let size = reg.size_bits();
1024 match reg {
1026 Register::Es => {
1027 buf.push(0x06);
1028 return Ok(());
1029 }
1030 Register::Cs => {
1031 buf.push(0x0E);
1032 return Ok(());
1033 }
1034 Register::Ss => {
1035 buf.push(0x16);
1036 return Ok(());
1037 }
1038 Register::Ds => {
1039 buf.push(0x1E);
1040 return Ok(());
1041 }
1042 Register::Fs => {
1043 buf.push(0x0F);
1044 buf.push(0xA0);
1045 return Ok(());
1046 }
1047 Register::Gs => {
1048 buf.push(0x0F);
1049 buf.push(0xA8);
1050 return Ok(());
1051 }
1052 _ => {}
1053 }
1054 if size == 8 {
1055 return Err(invalid_operands(
1056 "push",
1057 "push does not accept 8-bit registers",
1058 instr.span,
1059 ));
1060 }
1061 if size == 16 {
1062 buf.push(0x66); }
1064 buf.push(0x50 + reg.base_code());
1065 }
1066 Operand::Immediate(imm) => {
1067 if *imm >= i8::MIN as i128 && *imm <= i8::MAX as i128 {
1068 buf.push(0x6A);
1069 buf.push(*imm as i8 as u8);
1070 } else if *imm >= i32::MIN as i128 && *imm <= u32::MAX as i128 {
1071 buf.push(0x68);
1072 buf.extend_from_slice(&(*imm as i32).to_le_bytes());
1073 } else {
1074 return Err(invalid_operands(
1075 "push",
1076 "immediate value out of range for push (must fit in 32 bits)",
1077 instr.span,
1078 ));
1079 }
1080 }
1081 Operand::Memory(mem) => {
1082 let msize = mem.size.map(|s| s.bits()).unwrap_or(32);
1083 if msize == 16 {
1084 buf.push(0x66);
1085 }
1086 buf.push(0xFF);
1087 emit_mem_modrm(buf, 6, mem);
1088 }
1089 op @ (Operand::Label(_) | Operand::Expression(_)) => {
1090 let Some((label, addend)) = extract_label(op) else {
1091 return Err(invalid_operands("push", "unsupported operand", instr.span));
1092 };
1093 buf.push(0x68);
1094 let reloc_off = buf.len();
1095 buf.extend_from_slice(&0i32.to_le_bytes());
1096 *reloc = Some(Relocation {
1097 offset: reloc_off,
1098 size: 4,
1099 label: alloc::rc::Rc::from(label),
1100 kind: RelocKind::Absolute,
1101 addend,
1102 trailing_bytes: 0,
1103 });
1104 }
1105 _ => return Err(invalid_operands("push", "unsupported operand", instr.span)),
1106 }
1107 Ok(())
1108}
1109
1110#[cfg(feature = "x86")]
1112fn encode_pop_32(
1113 buf: &mut InstrBytes,
1114 ops: &OperandList,
1115 instr: &Instruction,
1116) -> Result<(), AsmError> {
1117 if ops.len() != 1 {
1118 return Err(invalid_operands("pop", "expected 1 operand", instr.span));
1119 }
1120 match &ops[0] {
1121 Operand::Register(reg) => {
1122 let size = reg.size_bits();
1123 match reg {
1124 Register::Es => {
1125 buf.push(0x07);
1126 return Ok(());
1127 }
1128 Register::Ss => {
1129 buf.push(0x17);
1130 return Ok(());
1131 }
1132 Register::Ds => {
1133 buf.push(0x1F);
1134 return Ok(());
1135 }
1136 Register::Fs => {
1137 buf.push(0x0F);
1138 buf.push(0xA1);
1139 return Ok(());
1140 }
1141 Register::Gs => {
1142 buf.push(0x0F);
1143 buf.push(0xA9);
1144 return Ok(());
1145 }
1146 Register::Cs => {
1147 return Err(invalid_operands("pop", "cannot pop into CS", instr.span));
1148 }
1149 _ => {}
1150 }
1151 if size == 8 {
1152 return Err(invalid_operands(
1153 "pop",
1154 "pop does not accept 8-bit registers",
1155 instr.span,
1156 ));
1157 }
1158 if size == 16 {
1159 buf.push(0x66);
1160 }
1161 buf.push(0x58 + reg.base_code());
1162 }
1163 Operand::Memory(mem) => {
1164 let msize = mem.size.map(|s| s.bits()).unwrap_or(32);
1165 if msize == 16 {
1166 buf.push(0x66);
1167 }
1168 buf.push(0x8F);
1169 emit_mem_modrm(buf, 0, mem);
1170 }
1171 _ => return Err(invalid_operands("pop", "unsupported operand", instr.span)),
1172 }
1173 Ok(())
1174}
1175
1176#[inline]
1180#[cfg(any(feature = "x86", feature = "x86_64"))]
1181pub(crate) fn rex(w: bool, r: bool, x: bool, b: bool) -> u8 {
1182 let mut val: u8 = 0x40;
1183 if w {
1184 val |= 0x08;
1185 }
1186 if r {
1187 val |= 0x04;
1188 }
1189 if x {
1190 val |= 0x02;
1191 }
1192 if b {
1193 val |= 0x01;
1194 }
1195 val
1196}
1197
1198#[inline]
1200#[cfg(any(feature = "x86", feature = "x86_64"))]
1201pub(crate) fn needs_rex(w: bool, r: bool, x: bool, b: bool) -> bool {
1202 w || r || x || b
1203}
1204
1205#[inline]
1207#[cfg(any(feature = "x86", feature = "x86_64"))]
1208pub(crate) fn modrm(mod_: u8, reg: u8, rm: u8) -> u8 {
1209 (mod_ << 6) | ((reg & 7) << 3) | (rm & 7)
1210}
1211
1212#[inline]
1214#[cfg(any(feature = "x86", feature = "x86_64"))]
1215fn sib(scale: u8, index: u8, base: u8) -> u8 {
1216 let ss = match scale {
1217 1 => 0,
1218 2 => 1,
1219 4 => 2,
1220 8 => 3,
1221 _ => 0,
1222 };
1223 (ss << 6) | ((index & 7) << 3) | (base & 7)
1224}
1225
1226#[inline]
1228#[cfg(any(feature = "x86", feature = "x86_64"))]
1229pub(crate) fn reg_size(reg: Register) -> u8 {
1230 let s = reg.size_bits();
1231 debug_assert!(s <= 128, "reg_size() used on vector register wider than u8");
1232 s as u8
1233}
1234
1235#[cfg(any(feature = "x86", feature = "x86_64"))]
1240pub(crate) fn check_high_byte_rex_conflict(
1241 regs: &[Register],
1242 span: crate::error::Span,
1243) -> Result<(), AsmError> {
1244 let has_high = regs.iter().any(|r| r.is_high_byte());
1245 let needs_rex = regs
1246 .iter()
1247 .any(|r| r.is_extended() || r.requires_rex_for_byte() || r.size_bits() == 64);
1248 if has_high && needs_rex {
1249 return Err(AsmError::InvalidOperands {
1250 detail: String::from(
1251 "high-byte registers (AH, BH, CH, DH) cannot be used with REX-requiring operands (64-bit regs, extended regs R8-R15, SPL/BPL/SIL/DIL)"
1252 ),
1253 span,
1254 });
1255 }
1256 Ok(())
1257}
1258
1259#[inline]
1261#[cfg(any(feature = "x86", feature = "x86_64"))]
1262fn emit_rr(
1263 buf: &mut InstrBytes,
1264 opcode: &[u8],
1265 dst: Register,
1266 src: Register,
1267 span: crate::error::Span,
1268) -> Result<(), AsmError> {
1269 let size = reg_size(dst);
1270 let w = size == 64;
1271 let r = src.is_extended();
1272 let b = dst.is_extended();
1273
1274 if size == 8 {
1276 check_high_byte_rex_conflict(&[dst, src], span)?;
1277 }
1278
1279 if size == 16 {
1281 buf.push(0x66);
1282 }
1283
1284 let need_rex =
1286 needs_rex(w, r, false, b) || dst.requires_rex_for_byte() || src.requires_rex_for_byte();
1287 if need_rex {
1288 buf.push(rex(w, r, false, b));
1289 }
1290
1291 buf.extend_from_slice(opcode);
1292 buf.push(modrm(0b11, src.base_code(), dst.base_code()));
1293 Ok(())
1294}
1295
1296#[inline]
1298#[cfg(any(feature = "x86", feature = "x86_64"))]
1299pub(crate) fn set_mem_reloc(
1300 reloc: &mut Option<Relocation>,
1301 mem: &MemoryOperand,
1302 disp_offset: Option<usize>,
1303 buf_len: usize,
1304) {
1305 if let Some(ref label) = mem.disp_label {
1306 *reloc = Some(Relocation {
1307 offset: disp_offset.unwrap_or(buf_len),
1308 size: 4,
1309 label: alloc::rc::Rc::from(&**label),
1310 kind: if mem.base == Some(Register::Rip) {
1311 RelocKind::X86Relative
1312 } else {
1313 RelocKind::Absolute
1314 },
1315 addend: mem.disp,
1316 trailing_bytes: 0, });
1318 }
1319}
1320
1321#[cfg(any(feature = "x86", feature = "x86_64"))]
1324pub(crate) fn emit_mem_modrm(
1325 buf: &mut InstrBytes,
1326 reg_field: u8,
1327 mem: &MemoryOperand,
1328) -> Option<usize> {
1329 let base = mem.base;
1333 let index = mem.index;
1334 let disp = mem.disp;
1335
1336 if base == Some(Register::Rip) && index.is_none() {
1338 buf.push(modrm(0b00, reg_field, 0b101));
1339 let reloc_offset = buf.len();
1340 buf.extend_from_slice(&(disp as i32).to_le_bytes());
1341 return Some(reloc_offset);
1342 }
1343
1344 if base.is_none() && index.is_none() {
1346 buf.push(modrm(0b00, reg_field, 0b100));
1348 buf.push(sib(1, 0b100, 0b101));
1349 let reloc_offset = buf.len();
1350 buf.extend_from_slice(&(disp as i32).to_le_bytes());
1351 return Some(reloc_offset);
1352 }
1353
1354 if let (None, Some(idx_reg)) = (base, index) {
1357 buf.push(modrm(0b00, reg_field, 0b100));
1358 buf.push(sib(mem.scale, idx_reg.base_code(), 0b101));
1359 let reloc_offset = buf.len();
1360 buf.extend_from_slice(&(disp as i32).to_le_bytes());
1361 return Some(reloc_offset);
1362 }
1363
1364 let base = base?;
1368
1369 let need_sib = index.is_some() || base.base_code() == 4; let (mod_bits, disp_size) = if disp == 0 && base.base_code() != 5 {
1373 (0b00, 0)
1375 } else if (-128..=127).contains(&disp) {
1376 (0b01, 1)
1377 } else {
1378 (0b10, 4)
1379 };
1380
1381 if need_sib {
1382 let idx_reg = index.unwrap_or(Register::Rsp); buf.push(modrm(mod_bits, reg_field, 0b100));
1385 buf.push(sib(mem.scale, idx_reg.base_code(), base.base_code()));
1386 } else {
1387 buf.push(modrm(mod_bits, reg_field, base.base_code()));
1388 }
1389
1390 let reloc_offset = if disp_size > 0 { Some(buf.len()) } else { None };
1391
1392 match disp_size {
1393 1 => buf.push(disp as i8 as u8),
1394 4 => buf.extend_from_slice(&(disp as i32).to_le_bytes()),
1395 _ => {}
1396 }
1397
1398 reloc_offset
1399}
1400
1401#[inline]
1403#[cfg(any(feature = "x86", feature = "x86_64"))]
1404pub(crate) fn emit_rex_for_reg_mem(
1405 buf: &mut InstrBytes,
1406 reg: Register,
1407 mem: &MemoryOperand,
1408) -> Result<(), AsmError> {
1409 let w = reg.size_bits() == 64;
1410 let r = reg.is_extended();
1411 let x = mem.index.is_some_and(|r| r.is_extended());
1412 let b = mem.base.is_some_and(|r| r.is_extended());
1413
1414 if reg.size_bits() == 16 {
1415 buf.push(0x66);
1416 }
1417
1418 if reg.size_bits() == 8 && reg.is_high_byte() {
1420 let mem_needs_rex = x || b;
1421 if mem_needs_rex {
1422 return Err(AsmError::InvalidOperands {
1423 detail: String::from(
1424 "high-byte registers (AH, BH, CH, DH) cannot be used with memory operands requiring REX prefix (R8-R15 base/index)"
1425 ),
1426 span: crate::error::Span { line: 0, col: 0, offset: 0, len: 0 },
1427 });
1428 }
1429 }
1430
1431 let need = needs_rex(w, r, x, b) || reg.requires_rex_for_byte();
1432 if need {
1433 buf.push(rex(w, r, x, b));
1434 }
1435 Ok(())
1436}
1437
1438#[inline]
1440#[cfg(any(feature = "x86", feature = "x86_64"))]
1441pub(crate) fn emit_rex_for_digit_mem(buf: &mut InstrBytes, size: u8, mem: &MemoryOperand) {
1442 let w = size == 64;
1443 let x = mem.index.is_some_and(|r| r.is_extended());
1444 let b = mem.base.is_some_and(|r| r.is_extended());
1445
1446 if size == 16 {
1447 buf.push(0x66);
1448 }
1449 if needs_rex(w, false, x, b) {
1450 buf.push(rex(w, false, x, b));
1451 }
1452}
1453
1454#[cfg(any(feature = "x86", feature = "x86_64"))]
1457pub(crate) fn encode_nop(
1458 buf: &mut InstrBytes,
1459 ops: &OperandList,
1460 instr: &Instruction,
1461) -> Result<(), AsmError> {
1462 if ops.is_empty() {
1463 buf.push(0x90);
1464 Ok(())
1465 } else {
1466 Err(AsmError::InvalidOperands {
1467 detail: String::from("nop takes no operands"),
1468 span: instr.span,
1469 })
1470 }
1471}
1472
1473#[cfg(any(feature = "x86", feature = "x86_64"))]
1474pub(crate) fn encode_multibyte_nop(buf: &mut InstrBytes, mnemonic: &str) -> Result<(), AsmError> {
1475 let n: usize = mnemonic[3..].parse().unwrap_or(1);
1476 match n {
1478 2 => buf.extend_from_slice(&[0x66, 0x90]),
1479 3 => buf.extend_from_slice(&[0x0F, 0x1F, 0x00]),
1480 4 => buf.extend_from_slice(&[0x0F, 0x1F, 0x40, 0x00]),
1481 5 => buf.extend_from_slice(&[0x0F, 0x1F, 0x44, 0x00, 0x00]),
1482 6 => buf.extend_from_slice(&[0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00]),
1483 7 => buf.extend_from_slice(&[0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00]),
1484 8 => buf.extend_from_slice(&[0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1485 9 => buf.extend_from_slice(&[0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]),
1486 _ => buf.push(0x90),
1487 }
1488 Ok(())
1489}
1490
1491#[cfg(any(feature = "x86", feature = "x86_64"))]
1492pub(crate) fn encode_int(
1493 buf: &mut InstrBytes,
1494 ops: &OperandList,
1495 instr: &Instruction,
1496) -> Result<(), AsmError> {
1497 if ops.len() != 1 {
1498 return Err(invalid_operands(
1499 "int",
1500 "expected one immediate operand",
1501 instr.span,
1502 ));
1503 }
1504 match &ops[0] {
1505 Operand::Immediate(3) => buf.push(0xCC), Operand::Immediate(n) if *n >= 0 && *n <= 255 => {
1507 buf.push(0xCD);
1508 buf.push(*n as u8);
1509 }
1510 _ => {
1511 return Err(invalid_operands(
1512 "int",
1513 "expected immediate 0-255",
1514 instr.span,
1515 ))
1516 }
1517 }
1518 Ok(())
1519}
1520
1521#[cfg(any(feature = "x86", feature = "x86_64"))]
1522pub(crate) fn encode_ret(
1523 buf: &mut InstrBytes,
1524 ops: &OperandList,
1525 instr: &Instruction,
1526) -> Result<(), AsmError> {
1527 if ops.is_empty() {
1528 buf.push(0xC3); } else if ops.len() == 1 {
1530 match &ops[0] {
1531 Operand::Immediate(n) if *n >= 0 && *n <= 65535 => {
1532 buf.push(0xC2); buf.extend_from_slice(&(*n as u16).to_le_bytes());
1534 }
1535 _ => {
1536 return Err(invalid_operands(
1537 "ret",
1538 "expected immediate 0-65535",
1539 instr.span,
1540 ))
1541 }
1542 }
1543 } else {
1544 return Err(invalid_operands(
1545 "ret",
1546 "expected 0 or 1 operands",
1547 instr.span,
1548 ));
1549 }
1550 Ok(())
1551}
1552
1553#[cfg(any(feature = "x86", feature = "x86_64"))]
1554pub(crate) fn encode_retf(
1555 buf: &mut InstrBytes,
1556 ops: &OperandList,
1557 instr: &Instruction,
1558) -> Result<(), AsmError> {
1559 if ops.is_empty() {
1560 buf.push(0xCB); } else if ops.len() == 1 {
1562 match &ops[0] {
1563 Operand::Immediate(n) if *n >= 0 && *n <= 65535 => {
1564 buf.push(0xCA); buf.extend_from_slice(&(*n as u16).to_le_bytes());
1566 }
1567 _ => {
1568 return Err(invalid_operands(
1569 "retf",
1570 "expected immediate 0-65535",
1571 instr.span,
1572 ))
1573 }
1574 }
1575 } else {
1576 return Err(invalid_operands(
1577 "retf",
1578 "expected 0 or 1 operands",
1579 instr.span,
1580 ));
1581 }
1582 Ok(())
1583}
1584
1585#[cfg(any(feature = "x86", feature = "x86_64"))]
1586pub(crate) fn encode_mov(
1587 buf: &mut InstrBytes,
1588 ops: &OperandList,
1589 instr: &Instruction,
1590 reloc: &mut Option<Relocation>,
1591) -> Result<(), AsmError> {
1592 if ops.len() != 2 {
1593 return Err(invalid_operands("mov", "expected 2 operands", instr.span));
1594 }
1595
1596 match (&ops[0], &ops[1]) {
1597 (Operand::Register(dst), Operand::Register(src)) => {
1599 let size = reg_size(*dst);
1600 if size != reg_size(*src) {
1601 return Err(invalid_operands("mov", "operand size mismatch", instr.span));
1602 }
1603 let opcode = if size == 8 {
1604 &[0x88u8] as &[u8]
1605 } else {
1606 &[0x89u8]
1607 };
1608 emit_rr(buf, opcode, *dst, *src, instr.span)?;
1609 }
1610
1611 (Operand::Register(dst), Operand::Immediate(imm)) => {
1613 encode_mov_reg_imm(buf, *dst, *imm, instr.span)?;
1614 }
1615
1616 (Operand::Register(dst), op @ (Operand::Label(_) | Operand::Expression(_))) => {
1618 let Some((label, addend)) = extract_label(op) else {
1619 return Err(invalid_operands(
1620 "mov",
1621 "expected label expression",
1622 instr.span,
1623 ));
1624 };
1625 let size = reg_size(*dst);
1627 if size == 64 {
1628 let w = true;
1629 let b = dst.is_extended();
1630 buf.push(rex(w, false, false, b));
1631 buf.push(0xB8 + dst.base_code());
1632 let reloc_off = buf.len();
1633 buf.extend_from_slice(&0u64.to_le_bytes());
1634 *reloc = Some(Relocation {
1635 offset: reloc_off,
1636 size: 8,
1637 label: alloc::rc::Rc::from(label),
1638 kind: RelocKind::Absolute,
1639 addend,
1640 trailing_bytes: 0,
1641 });
1642 } else {
1643 return Err(invalid_operands(
1644 "mov",
1645 "label operand requires 64-bit register",
1646 instr.span,
1647 ));
1648 }
1649 }
1650
1651 (Operand::Register(dst), Operand::Memory(mem)) => {
1653 let size = reg_size(*dst);
1654 let opcode: u8 = if size == 8 { 0x8A } else { 0x8B };
1655 emit_rex_for_reg_mem(buf, *dst, mem)?;
1656 buf.push(opcode);
1657 let reloc_off = emit_mem_modrm(buf, dst.base_code(), mem);
1658 if let Some(ref label) = mem.disp_label {
1659 *reloc = Some(Relocation {
1660 offset: reloc_off.unwrap_or(buf.len()),
1661 size: 4,
1662 label: alloc::rc::Rc::from(&**label),
1663 kind: if mem.base == Some(Register::Rip) {
1664 RelocKind::X86Relative
1665 } else {
1666 RelocKind::Absolute
1667 },
1668 addend: mem.disp,
1669 trailing_bytes: 0,
1670 });
1671 }
1672 }
1673
1674 (Operand::Memory(mem), Operand::Register(src)) => {
1676 let size = reg_size(*src);
1677 let opcode: u8 = if size == 8 { 0x88 } else { 0x89 };
1678 emit_rex_for_reg_mem(buf, *src, mem)?;
1679 buf.push(opcode);
1680 let disp_off = emit_mem_modrm(buf, src.base_code(), mem);
1681 set_mem_reloc(reloc, mem, disp_off, buf.len());
1682 }
1683
1684 (Operand::Memory(mem), Operand::Immediate(imm)) => {
1686 let size = instr
1687 .size_hint
1688 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
1689 s.bits() as u8
1690 });
1691 if size == 64 {
1693 let v = *imm;
1694 if v > i64::from(i32::MAX) as i128 || v < i64::from(i32::MIN) as i128 {
1695 return Err(invalid_operands(
1696 "mov",
1697 "immediate too large for mov [mem], imm (max sign-extended imm32); use mov reg, imm64 + mov [mem], reg",
1698 instr.span,
1699 ));
1700 }
1701 }
1702 let opcode: u8 = if size == 8 { 0xC6 } else { 0xC7 };
1703 emit_rex_for_digit_mem(buf, size, mem);
1704 buf.push(opcode);
1705 let disp_off = emit_mem_modrm(buf, 0, mem); set_mem_reloc(reloc, mem, disp_off, buf.len());
1707 emit_imm(buf, *imm, if size > 32 { 32 } else { size }); }
1709
1710 _ => {
1711 return Err(invalid_operands(
1712 "mov",
1713 "unsupported operand combination",
1714 instr.span,
1715 ))
1716 }
1717 }
1718 Ok(())
1719}
1720
1721#[cfg(any(feature = "x86", feature = "x86_64"))]
1722pub(crate) fn encode_mov_reg_imm(
1723 buf: &mut InstrBytes,
1724 dst: Register,
1725 imm: i128,
1726 span: Span,
1727) -> Result<(), AsmError> {
1728 let size = reg_size(dst);
1729
1730 match size {
1731 8 => {
1732 let b = dst.is_extended();
1733 let need = b || dst.requires_rex_for_byte();
1734 if need {
1735 buf.push(rex(false, false, false, b));
1736 }
1737 buf.push(0xB0 + dst.base_code());
1738 buf.push(imm as u8);
1739 }
1740 16 => {
1741 buf.push(0x66);
1742 let b = dst.is_extended();
1743 if b {
1744 buf.push(rex(false, false, false, b));
1745 }
1746 buf.push(0xB8 + dst.base_code());
1747 buf.extend_from_slice(&(imm as u16).to_le_bytes());
1748 }
1749 32 => {
1750 let b = dst.is_extended();
1751 if b {
1752 buf.push(rex(false, false, false, b));
1753 }
1754 buf.push(0xB8 + dst.base_code());
1755 buf.extend_from_slice(&(imm as u32).to_le_bytes());
1756 }
1757 64 => {
1758 let b = dst.is_extended();
1760 if imm >= 0 && imm <= u32::MAX as i128 {
1761 if b {
1763 buf.push(rex(false, false, false, true));
1764 }
1765 buf.push(0xB8 + dst.base_code());
1766 buf.extend_from_slice(&(imm as u32).to_le_bytes());
1767 } else if imm >= i32::MIN as i128 && imm <= i32::MAX as i128 {
1768 buf.push(rex(true, false, false, b));
1770 buf.push(0xC7);
1771 buf.push(modrm(0b11, 0, dst.base_code()));
1772 buf.extend_from_slice(&(imm as i32).to_le_bytes());
1773 } else {
1774 buf.push(rex(true, false, false, b));
1776 buf.push(0xB8 + dst.base_code());
1777 buf.extend_from_slice(&(imm as u64).to_le_bytes());
1778 }
1779 }
1780 _ => {
1781 return Err(AsmError::InvalidOperands {
1782 detail: String::from("unsupported register size for mov immediate"),
1783 span,
1784 });
1785 }
1786 }
1787 Ok(())
1788}
1789
1790#[cfg(any(feature = "x86", feature = "x86_64"))]
1791pub(crate) fn encode_lea(
1792 buf: &mut InstrBytes,
1793 ops: &OperandList,
1794 instr: &Instruction,
1795 reloc: &mut Option<Relocation>,
1796) -> Result<(), AsmError> {
1797 if ops.len() != 2 {
1798 return Err(invalid_operands("lea", "expected 2 operands", instr.span));
1799 }
1800 match (&ops[0], &ops[1]) {
1801 (Operand::Register(dst), Operand::Memory(mem)) => {
1802 emit_rex_for_reg_mem(buf, *dst, mem)?;
1803 buf.push(0x8D);
1804 let reloc_off = emit_mem_modrm(buf, dst.base_code(), mem);
1805 if let Some(ref label) = mem.disp_label {
1806 *reloc = Some(Relocation {
1807 offset: reloc_off.unwrap_or(buf.len()),
1808 size: 4,
1809 label: alloc::rc::Rc::from(&**label),
1810 kind: if mem.base == Some(Register::Rip) {
1811 RelocKind::X86Relative
1812 } else {
1813 RelocKind::Absolute
1814 },
1815 addend: mem.disp,
1816 trailing_bytes: 0,
1817 });
1818 }
1819 }
1820 _ => return Err(invalid_operands("lea", "expected reg, [mem]", instr.span)),
1821 }
1822 Ok(())
1823}
1824
1825#[cfg(any(feature = "x86", feature = "x86_64"))]
1826pub(crate) fn encode_push(
1827 buf: &mut InstrBytes,
1828 ops: &OperandList,
1829 instr: &Instruction,
1830 reloc: &mut Option<Relocation>,
1831) -> Result<(), AsmError> {
1832 if ops.len() != 1 {
1833 return Err(invalid_operands("push", "expected 1 operand", instr.span));
1834 }
1835 match &ops[0] {
1836 Operand::Register(reg) => {
1837 let size = reg.size_bits();
1838 match reg {
1840 Register::Fs => {
1841 buf.push(0x0F);
1842 buf.push(0xA0);
1843 return Ok(());
1844 }
1845 Register::Gs => {
1846 buf.push(0x0F);
1847 buf.push(0xA8);
1848 return Ok(());
1849 }
1850 Register::Cs | Register::Ds | Register::Es | Register::Ss => {
1851 return Err(invalid_operands(
1852 "push",
1853 "CS/DS/ES/SS push not valid in 64-bit mode",
1854 instr.span,
1855 ));
1856 }
1857 _ => {}
1858 }
1859 if size == 8 || size == 32 {
1860 return Err(invalid_operands(
1861 "push",
1862 "push requires 64-bit or 16-bit register in 64-bit mode",
1863 instr.span,
1864 ));
1865 }
1866 let b = reg.is_extended();
1867 if size == 16 {
1868 buf.push(0x66);
1869 }
1870 if b {
1871 buf.push(rex(false, false, false, true));
1872 }
1873 buf.push(0x50 + reg.base_code());
1874 }
1875 Operand::Immediate(imm) => {
1876 if *imm >= i8::MIN as i128 && *imm <= i8::MAX as i128 {
1877 buf.push(0x6A);
1878 buf.push(*imm as i8 as u8);
1879 } else if *imm >= i32::MIN as i128 && *imm <= u32::MAX as i128 {
1880 buf.push(0x68);
1881 buf.extend_from_slice(&(*imm as i32).to_le_bytes());
1882 } else {
1883 return Err(invalid_operands(
1884 "push",
1885 "immediate value out of range for push (must fit in 32 bits)",
1886 instr.span,
1887 ));
1888 }
1889 }
1890 Operand::Memory(mem) => {
1891 emit_rex_for_digit_mem(buf, 0, mem);
1894 buf.push(0xFF);
1895 emit_mem_modrm(buf, 6, mem); }
1897 op @ (Operand::Label(_) | Operand::Expression(_)) => {
1898 let Some((label, addend)) = extract_label(op) else {
1899 return Err(invalid_operands("push", "unsupported operand", instr.span));
1900 };
1901 buf.push(0x68);
1903 let reloc_off = buf.len();
1904 buf.extend_from_slice(&0i32.to_le_bytes());
1905 *reloc = Some(Relocation {
1906 offset: reloc_off,
1907 size: 4,
1908 label: alloc::rc::Rc::from(label),
1909 kind: RelocKind::Absolute,
1910 addend,
1911 trailing_bytes: 0,
1912 });
1913 }
1914 _ => return Err(invalid_operands("push", "unsupported operand", instr.span)),
1915 }
1916 Ok(())
1917}
1918
1919#[cfg(any(feature = "x86", feature = "x86_64"))]
1920pub(crate) fn encode_pop(
1921 buf: &mut InstrBytes,
1922 ops: &OperandList,
1923 instr: &Instruction,
1924) -> Result<(), AsmError> {
1925 if ops.len() != 1 {
1926 return Err(invalid_operands("pop", "expected 1 operand", instr.span));
1927 }
1928 match &ops[0] {
1929 Operand::Register(reg) => {
1930 let size = reg.size_bits();
1931 match reg {
1933 Register::Fs => {
1934 buf.push(0x0F);
1935 buf.push(0xA1);
1936 return Ok(());
1937 }
1938 Register::Gs => {
1939 buf.push(0x0F);
1940 buf.push(0xA9);
1941 return Ok(());
1942 }
1943 Register::Cs | Register::Ds | Register::Es | Register::Ss => {
1944 return Err(invalid_operands(
1945 "pop",
1946 "CS/DS/ES/SS pop not valid in 64-bit mode",
1947 instr.span,
1948 ));
1949 }
1950 _ => {}
1951 }
1952 if size == 8 || size == 32 {
1953 return Err(invalid_operands(
1954 "pop",
1955 "pop requires 64-bit or 16-bit register in 64-bit mode",
1956 instr.span,
1957 ));
1958 }
1959 let b = reg.is_extended();
1960 if size == 16 {
1961 buf.push(0x66);
1962 }
1963 if b {
1964 buf.push(rex(false, false, false, true));
1965 }
1966 buf.push(0x58 + reg.base_code());
1967 }
1968 Operand::Memory(mem) => {
1969 emit_rex_for_digit_mem(buf, 0, mem);
1971 buf.push(0x8F);
1972 emit_mem_modrm(buf, 0, mem);
1973 }
1974 _ => return Err(invalid_operands("pop", "unsupported operand", instr.span)),
1975 }
1976 Ok(())
1977}
1978
1979#[cfg(any(feature = "x86", feature = "x86_64"))]
1982pub(crate) fn encode_alu(
1983 buf: &mut InstrBytes,
1984 ops: &OperandList,
1985 instr: &Instruction,
1986 alu_num: u8,
1987 reloc: &mut Option<Relocation>,
1988) -> Result<(), AsmError> {
1989 if ops.len() != 2 {
1990 return Err(invalid_operands(
1991 &instr.mnemonic,
1992 "expected 2 operands",
1993 instr.span,
1994 ));
1995 }
1996
1997 match (&ops[0], &ops[1]) {
1998 (Operand::Register(dst), Operand::Register(src)) => {
2000 let size = reg_size(*dst);
2001 let base_opcode = if size == 8 {
2002 alu_num * 8
2003 } else {
2004 alu_num * 8 + 1
2005 };
2006 emit_rr(buf, &[base_opcode], *dst, *src, instr.span)?;
2007 }
2008
2009 (Operand::Register(dst), Operand::Immediate(imm)) => {
2011 encode_alu_reg_imm(buf, *dst, *imm, alu_num)?;
2012 }
2013
2014 (Operand::Register(dst), Operand::Memory(mem)) => {
2016 let size = reg_size(*dst);
2017 let opcode: u8 = if size == 8 {
2018 alu_num * 8 + 2
2019 } else {
2020 alu_num * 8 + 3
2021 };
2022 emit_rex_for_reg_mem(buf, *dst, mem)?;
2023 buf.push(opcode);
2024 let disp_off = emit_mem_modrm(buf, dst.base_code(), mem);
2025 set_mem_reloc(reloc, mem, disp_off, buf.len());
2026 }
2027
2028 (Operand::Memory(mem), Operand::Register(src)) => {
2030 let size = reg_size(*src);
2031 let opcode: u8 = if size == 8 {
2032 alu_num * 8
2033 } else {
2034 alu_num * 8 + 1
2035 };
2036 emit_rex_for_reg_mem(buf, *src, mem)?;
2037 buf.push(opcode);
2038 let disp_off = emit_mem_modrm(buf, src.base_code(), mem);
2039 set_mem_reloc(reloc, mem, disp_off, buf.len());
2040 }
2041
2042 (Operand::Memory(mem), Operand::Immediate(imm)) => {
2044 let size = instr
2045 .size_hint
2046 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2047 s.bits() as u8
2048 });
2049 let disp_off = encode_alu_mem_imm(buf, mem, *imm, alu_num, size)?;
2050 set_mem_reloc(reloc, mem, disp_off, buf.len());
2051 }
2052
2053 _ => {
2055 return Err(invalid_operands(
2056 &instr.mnemonic,
2057 "unsupported operand combination",
2058 instr.span,
2059 ));
2060 }
2061 }
2062 Ok(())
2063}
2064
2065#[cfg(any(feature = "x86", feature = "x86_64"))]
2066pub(crate) fn encode_alu_reg_imm(
2067 buf: &mut InstrBytes,
2068 dst: Register,
2069 imm: i128,
2070 alu_num: u8,
2071) -> Result<(), AsmError> {
2072 let size = reg_size(dst);
2073
2074 if dst.base_code() == 0 && !dst.is_extended() && size == 8 {
2076 buf.push(alu_num * 8 + 4);
2077 buf.push(imm as u8);
2078 return Ok(());
2079 }
2080
2081 if size == 8 {
2082 let b = dst.is_extended();
2083 let need = b || dst.requires_rex_for_byte();
2084 if need {
2085 buf.push(rex(false, false, false, b));
2086 }
2087 buf.push(0x80);
2088 buf.push(modrm(0b11, alu_num, dst.base_code()));
2089 buf.push(imm as u8);
2090 } else if imm >= i8::MIN as i128 && imm <= i8::MAX as i128 {
2091 let w = size == 64;
2093 let b = dst.is_extended();
2094 if size == 16 {
2095 buf.push(0x66);
2096 }
2097 if needs_rex(w, false, false, b) {
2098 buf.push(rex(w, false, false, b));
2099 }
2100 buf.push(0x83);
2101 buf.push(modrm(0b11, alu_num, dst.base_code()));
2102 buf.push(imm as i8 as u8);
2103 } else {
2104 let w = size == 64;
2106 let b = dst.is_extended();
2107 if size == 16 {
2108 buf.push(0x66);
2109 }
2110 if needs_rex(w, false, false, b) {
2111 buf.push(rex(w, false, false, b));
2112 }
2113
2114 if dst.base_code() == 0 && !dst.is_extended() {
2116 buf.push(alu_num * 8 + 5);
2117 } else {
2118 buf.push(0x81);
2119 buf.push(modrm(0b11, alu_num, dst.base_code()));
2120 }
2121 let imm_size = if size > 32 { 32 } else { size };
2122 emit_imm(buf, imm, imm_size);
2123 }
2124 Ok(())
2125}
2126
2127#[cfg(any(feature = "x86", feature = "x86_64"))]
2128pub(crate) fn encode_alu_mem_imm(
2129 buf: &mut InstrBytes,
2130 mem: &MemoryOperand,
2131 imm: i128,
2132 alu_num: u8,
2133 size: u8,
2134) -> Result<Option<usize>, AsmError> {
2135 if size == 8 {
2136 emit_rex_for_digit_mem(buf, size, mem);
2137 buf.push(0x80);
2138 let disp_off = emit_mem_modrm(buf, alu_num, mem);
2139 buf.push(imm as u8);
2140 Ok(disp_off)
2141 } else if imm >= i8::MIN as i128 && imm <= i8::MAX as i128 {
2142 emit_rex_for_digit_mem(buf, size, mem);
2143 buf.push(0x83);
2144 let disp_off = emit_mem_modrm(buf, alu_num, mem);
2145 buf.push(imm as i8 as u8);
2146 Ok(disp_off)
2147 } else {
2148 emit_rex_for_digit_mem(buf, size, mem);
2149 buf.push(0x81);
2150 let disp_off = emit_mem_modrm(buf, alu_num, mem);
2151 let imm_size = if size > 32 { 32 } else { size };
2152 emit_imm(buf, imm, imm_size);
2153 Ok(disp_off)
2154 }
2155}
2156
2157#[cfg(any(feature = "x86", feature = "x86_64"))]
2158pub(crate) fn encode_test(
2159 buf: &mut InstrBytes,
2160 ops: &OperandList,
2161 instr: &Instruction,
2162 reloc: &mut Option<Relocation>,
2163) -> Result<(), AsmError> {
2164 if ops.len() != 2 {
2165 return Err(invalid_operands("test", "expected 2 operands", instr.span));
2166 }
2167 match (&ops[0], &ops[1]) {
2168 (Operand::Register(dst), Operand::Register(src)) => {
2169 let size = reg_size(*dst);
2170 let opcode = if size == 8 { 0x84u8 } else { 0x85u8 };
2171 emit_rr(buf, &[opcode], *dst, *src, instr.span)?;
2172 }
2173 (Operand::Register(dst), Operand::Immediate(imm)) => {
2174 let size = reg_size(*dst);
2175 if dst.base_code() == 0 && !dst.is_extended() && size == 8 {
2177 buf.push(0xA8);
2178 buf.push(*imm as u8);
2179 } else if dst.base_code() == 0 && !dst.is_extended() && size > 8 {
2180 let w = size == 64;
2181 if size == 16 {
2182 buf.push(0x66);
2183 }
2184 if w {
2185 buf.push(rex(true, false, false, false));
2186 }
2187 buf.push(0xA9);
2188 let imm_size = if size > 32 { 32 } else { size };
2189 emit_imm(buf, *imm, imm_size);
2190 } else {
2191 let w = size == 64;
2192 let b = dst.is_extended();
2193 if size == 16 {
2194 buf.push(0x66);
2195 }
2196 let need = needs_rex(w, false, false, b) || dst.requires_rex_for_byte();
2197 if need {
2198 buf.push(rex(w, false, false, b));
2199 }
2200 buf.push(if size == 8 { 0xF6 } else { 0xF7 });
2201 buf.push(modrm(0b11, 0, dst.base_code()));
2202 let imm_size = if size == 8 {
2203 8
2204 } else if size > 32 {
2205 32
2206 } else {
2207 size
2208 };
2209 emit_imm(buf, *imm, imm_size);
2210 }
2211 }
2212 (Operand::Memory(mem), Operand::Register(src)) => {
2213 let size = reg_size(*src);
2214 let opcode = if size == 8 { 0x84u8 } else { 0x85u8 };
2215 emit_rex_for_reg_mem(buf, *src, mem)?;
2216 buf.push(opcode);
2217 let disp_off = emit_mem_modrm(buf, src.base_code(), mem);
2218 set_mem_reloc(reloc, mem, disp_off, buf.len());
2219 }
2220 (Operand::Memory(mem), Operand::Immediate(imm)) => {
2221 let size = instr
2222 .size_hint
2223 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2224 s.bits() as u8
2225 });
2226 let opcode = if size == 8 { 0xF6u8 } else { 0xF7u8 };
2227 emit_rex_for_digit_mem(buf, size, mem);
2228 buf.push(opcode);
2229 let disp_off = emit_mem_modrm(buf, 0, mem); let imm_size = if size == 8 {
2231 8
2232 } else if size > 32 {
2233 32
2234 } else {
2235 size
2236 };
2237 emit_imm(buf, *imm, imm_size);
2238 set_mem_reloc(reloc, mem, disp_off, buf.len());
2239 }
2240 _ => {
2241 return Err(invalid_operands(
2242 "test",
2243 "unsupported operand combination",
2244 instr.span,
2245 ))
2246 }
2247 }
2248 Ok(())
2249}
2250
2251#[cfg(any(feature = "x86", feature = "x86_64"))]
2253pub(crate) fn encode_unary(
2254 buf: &mut InstrBytes,
2255 ops: &OperandList,
2256 instr: &Instruction,
2257 digit: u8,
2258) -> Result<(), AsmError> {
2259 if ops.len() != 1 {
2260 return Err(invalid_operands(
2261 &instr.mnemonic,
2262 "expected 1 operand",
2263 instr.span,
2264 ));
2265 }
2266 match &ops[0] {
2267 Operand::Register(reg) => {
2268 let size = reg_size(*reg);
2269 let w = size == 64;
2270 let b = reg.is_extended();
2271 if size == 16 {
2272 buf.push(0x66);
2273 }
2274 let need = needs_rex(w, false, false, b) || reg.requires_rex_for_byte();
2275 if need {
2276 buf.push(rex(w, false, false, b));
2277 }
2278 buf.push(if size == 8 { 0xF6 } else { 0xF7 });
2279 buf.push(modrm(0b11, digit, reg.base_code()));
2280 }
2281 Operand::Memory(mem) => {
2282 let size = instr
2283 .size_hint
2284 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2285 s.bits() as u8
2286 });
2287 emit_rex_for_digit_mem(buf, size, mem);
2288 buf.push(if size == 8 { 0xF6 } else { 0xF7 });
2289 emit_mem_modrm(buf, digit, mem);
2290 }
2291 _ => {
2292 return Err(invalid_operands(
2293 &instr.mnemonic,
2294 "expected register or memory operand",
2295 instr.span,
2296 ))
2297 }
2298 }
2299 Ok(())
2300}
2301
2302#[cfg(any(feature = "x86", feature = "x86_64"))]
2303pub(crate) fn encode_imul(
2304 buf: &mut InstrBytes,
2305 ops: &OperandList,
2306 instr: &Instruction,
2307) -> Result<(), AsmError> {
2308 match ops.len() {
2309 1 => {
2310 encode_unary(buf, ops, instr, 5)
2312 }
2313 2 => {
2314 match (&ops[0], &ops[1]) {
2316 (Operand::Register(dst), Operand::Register(src)) => {
2317 let size = reg_size(*dst);
2318 if size == 8 {
2319 return Err(invalid_operands(
2320 "imul",
2321 "8-bit operands not supported for 2/3-operand IMUL",
2322 instr.span,
2323 ));
2324 }
2325 let w = size == 64;
2326 let r = dst.is_extended();
2327 let b = src.is_extended();
2328 if size == 16 {
2329 buf.push(0x66);
2330 }
2331 if needs_rex(w, r, false, b) {
2332 buf.push(rex(w, r, false, b));
2333 }
2334 buf.push(0x0F);
2335 buf.push(0xAF);
2336 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
2337 }
2338 (Operand::Register(dst), Operand::Memory(mem)) => {
2339 if reg_size(*dst) == 8 {
2340 return Err(invalid_operands(
2341 "imul",
2342 "8-bit operands not supported for 2/3-operand IMUL",
2343 instr.span,
2344 ));
2345 }
2346 emit_rex_for_reg_mem(buf, *dst, mem)?;
2347 buf.push(0x0F);
2348 buf.push(0xAF);
2349 emit_mem_modrm(buf, dst.base_code(), mem);
2350 }
2351 _ => {
2352 return Err(invalid_operands(
2353 "imul",
2354 "unsupported operand combination",
2355 instr.span,
2356 ))
2357 }
2358 }
2359 Ok(())
2360 }
2361 3 => {
2362 match (&ops[0], &ops[1], &ops[2]) {
2364 (Operand::Register(dst), Operand::Register(src), Operand::Immediate(imm)) => {
2365 let size = reg_size(*dst);
2366 if size == 8 {
2367 return Err(invalid_operands(
2368 "imul",
2369 "8-bit operands not supported for 2/3-operand IMUL",
2370 instr.span,
2371 ));
2372 }
2373 let w = size == 64;
2374 let r = dst.is_extended();
2375 let b = src.is_extended();
2376 if size == 16 {
2377 buf.push(0x66);
2378 }
2379 if needs_rex(w, r, false, b) {
2380 buf.push(rex(w, r, false, b));
2381 }
2382
2383 if *imm >= i8::MIN as i128 && *imm <= i8::MAX as i128 {
2384 buf.push(0x6B);
2385 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
2386 buf.push(*imm as i8 as u8);
2387 } else {
2388 buf.push(0x69);
2389 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
2390 let imm_size = if size > 32 { 32 } else { size };
2391 emit_imm(buf, *imm, imm_size);
2392 }
2393 }
2394 (Operand::Register(dst), Operand::Memory(mem), Operand::Immediate(imm)) => {
2395 let size = reg_size(*dst);
2396 if size == 8 {
2397 return Err(invalid_operands(
2398 "imul",
2399 "8-bit operands not supported for 2/3-operand IMUL",
2400 instr.span,
2401 ));
2402 }
2403 emit_rex_for_reg_mem(buf, *dst, mem)?;
2404
2405 if *imm >= i8::MIN as i128 && *imm <= i8::MAX as i128 {
2406 buf.push(0x6B);
2407 emit_mem_modrm(buf, dst.base_code(), mem);
2408 buf.push(*imm as i8 as u8);
2409 } else {
2410 buf.push(0x69);
2411 emit_mem_modrm(buf, dst.base_code(), mem);
2412 let imm_size = if size > 32 { 32 } else { size };
2413 emit_imm(buf, *imm, imm_size);
2414 }
2415 }
2416 _ => {
2417 return Err(invalid_operands(
2418 "imul",
2419 "expected reg, r/m, imm",
2420 instr.span,
2421 ))
2422 }
2423 }
2424 Ok(())
2425 }
2426 _ => Err(invalid_operands(
2427 "imul",
2428 "expected 1-3 operands",
2429 instr.span,
2430 )),
2431 }
2432}
2433
2434#[cfg(any(feature = "x86", feature = "x86_64"))]
2435pub(crate) fn encode_inc_dec(
2436 buf: &mut InstrBytes,
2437 ops: &OperandList,
2438 instr: &Instruction,
2439 digit: u8,
2440) -> Result<(), AsmError> {
2441 if ops.len() != 1 {
2442 return Err(invalid_operands(
2443 &instr.mnemonic,
2444 "expected 1 operand",
2445 instr.span,
2446 ));
2447 }
2448 match &ops[0] {
2449 Operand::Register(reg) => {
2450 let size = reg_size(*reg);
2451 let w = size == 64;
2452 let b = reg.is_extended();
2453 if size == 16 {
2454 buf.push(0x66);
2455 }
2456 let need = needs_rex(w, false, false, b) || reg.requires_rex_for_byte();
2457 if need {
2458 buf.push(rex(w, false, false, b));
2459 }
2460 buf.push(if size == 8 { 0xFE } else { 0xFF });
2461 buf.push(modrm(0b11, digit, reg.base_code()));
2462 }
2463 Operand::Memory(mem) => {
2464 let size = instr
2465 .size_hint
2466 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2467 s.bits() as u8
2468 });
2469 emit_rex_for_digit_mem(buf, size, mem);
2470 buf.push(if size == 8 { 0xFE } else { 0xFF });
2471 emit_mem_modrm(buf, digit, mem);
2472 }
2473 _ => {
2474 return Err(invalid_operands(
2475 &instr.mnemonic,
2476 "expected register or memory",
2477 instr.span,
2478 ))
2479 }
2480 }
2481 Ok(())
2482}
2483
2484#[cfg(any(feature = "x86", feature = "x86_64"))]
2485pub(crate) fn encode_shift(
2486 buf: &mut InstrBytes,
2487 ops: &OperandList,
2488 instr: &Instruction,
2489 digit: u8,
2490) -> Result<(), AsmError> {
2491 if ops.len() != 2 {
2492 return Err(invalid_operands(
2493 &instr.mnemonic,
2494 "expected 2 operands",
2495 instr.span,
2496 ));
2497 }
2498 match (&ops[0], &ops[1]) {
2499 (Operand::Register(dst), Operand::Immediate(1)) => {
2500 let size = reg_size(*dst);
2501 let w = size == 64;
2502 let b = dst.is_extended();
2503 if size == 16 {
2504 buf.push(0x66);
2505 }
2506 let need = needs_rex(w, false, false, b) || dst.requires_rex_for_byte();
2507 if need {
2508 buf.push(rex(w, false, false, b));
2509 }
2510 buf.push(if size == 8 { 0xD0 } else { 0xD1 });
2511 buf.push(modrm(0b11, digit, dst.base_code()));
2512 }
2513 (Operand::Register(dst), Operand::Immediate(imm)) => {
2514 let size = reg_size(*dst);
2515 let w = size == 64;
2516 let b = dst.is_extended();
2517 if size == 16 {
2518 buf.push(0x66);
2519 }
2520 let need = needs_rex(w, false, false, b) || dst.requires_rex_for_byte();
2521 if need {
2522 buf.push(rex(w, false, false, b));
2523 }
2524 buf.push(if size == 8 { 0xC0 } else { 0xC1 });
2525 buf.push(modrm(0b11, digit, dst.base_code()));
2526 buf.push(*imm as u8);
2527 }
2528 (Operand::Register(dst), Operand::Register(Register::Cl)) => {
2529 let size = reg_size(*dst);
2530 let w = size == 64;
2531 let b = dst.is_extended();
2532 if size == 16 {
2533 buf.push(0x66);
2534 }
2535 let need = needs_rex(w, false, false, b) || dst.requires_rex_for_byte();
2536 if need {
2537 buf.push(rex(w, false, false, b));
2538 }
2539 buf.push(if size == 8 { 0xD2 } else { 0xD3 });
2540 buf.push(modrm(0b11, digit, dst.base_code()));
2541 }
2542 (Operand::Memory(mem), Operand::Immediate(1)) => {
2543 let size = instr
2544 .size_hint
2545 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2546 s.bits() as u8
2547 });
2548 let w = size == 64;
2549 let x = mem.index.is_some_and(|r| r.is_extended());
2550 let b = mem.base.is_some_and(|r| r.is_extended());
2551 if size == 16 {
2552 buf.push(0x66);
2553 }
2554 if needs_rex(w, false, x, b) {
2555 buf.push(rex(w, false, x, b));
2556 }
2557 buf.push(if size == 8 { 0xD0 } else { 0xD1 });
2558 emit_mem_modrm(buf, digit, mem);
2559 }
2560 (Operand::Memory(mem), Operand::Immediate(imm)) => {
2561 let size = instr
2562 .size_hint
2563 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2564 s.bits() as u8
2565 });
2566 let w = size == 64;
2567 let x = mem.index.is_some_and(|r| r.is_extended());
2568 let b = mem.base.is_some_and(|r| r.is_extended());
2569 if size == 16 {
2570 buf.push(0x66);
2571 }
2572 if needs_rex(w, false, x, b) {
2573 buf.push(rex(w, false, x, b));
2574 }
2575 buf.push(if size == 8 { 0xC0 } else { 0xC1 });
2576 emit_mem_modrm(buf, digit, mem);
2577 buf.push(*imm as u8);
2578 }
2579 (Operand::Memory(mem), Operand::Register(Register::Cl)) => {
2580 let size = instr
2581 .size_hint
2582 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
2583 s.bits() as u8
2584 });
2585 let w = size == 64;
2586 let x = mem.index.is_some_and(|r| r.is_extended());
2587 let b = mem.base.is_some_and(|r| r.is_extended());
2588 if size == 16 {
2589 buf.push(0x66);
2590 }
2591 if needs_rex(w, false, x, b) {
2592 buf.push(rex(w, false, x, b));
2593 }
2594 buf.push(if size == 8 { 0xD2 } else { 0xD3 });
2595 emit_mem_modrm(buf, digit, mem);
2596 }
2597 _ => {
2598 return Err(invalid_operands(
2599 &instr.mnemonic,
2600 "expected r/m, imm or r/m, cl",
2601 instr.span,
2602 ))
2603 }
2604 }
2605 Ok(())
2606}
2607
2608#[cfg(any(feature = "x86", feature = "x86_64"))]
2609pub(crate) fn encode_jmp(
2610 buf: &mut InstrBytes,
2611 ops: &OperandList,
2612 instr: &Instruction,
2613 reloc: &mut Option<Relocation>,
2614 relax: &mut Option<RelaxInfo>,
2615) -> Result<(), AsmError> {
2616 if ops.len() != 1 {
2617 return Err(invalid_operands("jmp", "expected 1 operand", instr.span));
2618 }
2619 match &ops[0] {
2620 op @ (Operand::Label(_) | Operand::Expression(_)) => {
2621 let Some((label, addend)) = extract_label(op) else {
2622 return Err(invalid_operands("jmp", "expected label", instr.span));
2623 };
2624 buf.push(0xE9);
2626 let reloc_off = buf.len();
2627 buf.extend_from_slice(&0i32.to_le_bytes());
2628 *reloc = Some(Relocation {
2629 offset: reloc_off,
2630 size: 4,
2631 label: alloc::rc::Rc::from(label),
2632 kind: RelocKind::X86Relative,
2633 addend,
2634 trailing_bytes: 0,
2635 });
2636 *relax = Some(RelaxInfo {
2639 short_bytes: InstrBytes::from_slice(&[0xEB, 0x00]),
2640 short_reloc_offset: 1,
2641 short_relocation: None,
2642 });
2643 }
2644 Operand::Immediate(target) => {
2645 buf.push(0xE9);
2647 buf.extend_from_slice(&(*target as i32).to_le_bytes());
2648 }
2649 Operand::Register(reg) => {
2650 let b = reg.is_extended();
2651 if b {
2652 buf.push(rex(false, false, false, true));
2653 }
2654 buf.push(0xFF);
2655 buf.push(modrm(0b11, 4, reg.base_code()));
2656 }
2657 Operand::Memory(mem) => {
2658 emit_rex_for_digit_mem(buf, 0, mem);
2660 buf.push(0xFF);
2661 emit_mem_modrm(buf, 4, mem);
2662 }
2663 _ => return Err(invalid_operands("jmp", "unsupported operand", instr.span)),
2664 }
2665 Ok(())
2666}
2667
2668#[cfg(any(feature = "x86", feature = "x86_64"))]
2669pub(crate) fn encode_call(
2670 buf: &mut InstrBytes,
2671 ops: &OperandList,
2672 instr: &Instruction,
2673 reloc: &mut Option<Relocation>,
2674) -> Result<(), AsmError> {
2675 if ops.len() != 1 {
2676 return Err(invalid_operands("call", "expected 1 operand", instr.span));
2677 }
2678 match &ops[0] {
2679 op @ (Operand::Label(_) | Operand::Expression(_)) => {
2680 let Some((label, addend)) = extract_label(op) else {
2681 return Err(invalid_operands("call", "expected label", instr.span));
2682 };
2683 buf.push(0xE8);
2684 let reloc_off = buf.len();
2685 buf.extend_from_slice(&0i32.to_le_bytes());
2686 *reloc = Some(Relocation {
2687 offset: reloc_off,
2688 size: 4,
2689 label: alloc::rc::Rc::from(label),
2690 kind: RelocKind::X86Relative,
2691 addend,
2692 trailing_bytes: 0,
2693 });
2694 }
2695 Operand::Register(reg) => {
2696 let b = reg.is_extended();
2697 if b {
2698 buf.push(rex(false, false, false, true));
2699 }
2700 buf.push(0xFF);
2701 buf.push(modrm(0b11, 2, reg.base_code()));
2702 }
2703 Operand::Memory(mem) => {
2704 emit_rex_for_digit_mem(buf, 0, mem);
2706 buf.push(0xFF);
2707 emit_mem_modrm(buf, 2, mem);
2708 }
2709 _ => return Err(invalid_operands("call", "unsupported operand", instr.span)),
2710 }
2711 Ok(())
2712}
2713
2714#[cfg(any(feature = "x86", feature = "x86_64"))]
2715pub(crate) fn encode_jcc(
2716 buf: &mut InstrBytes,
2717 ops: &OperandList,
2718 instr: &Instruction,
2719 cc: u8,
2720 reloc: &mut Option<Relocation>,
2721 relax: &mut Option<RelaxInfo>,
2722) -> Result<(), AsmError> {
2723 if ops.len() != 1 {
2724 return Err(invalid_operands(
2725 &instr.mnemonic,
2726 "expected 1 operand",
2727 instr.span,
2728 ));
2729 }
2730 match &ops[0] {
2731 op @ (Operand::Label(_) | Operand::Expression(_)) => {
2732 let Some((label, addend)) = extract_label(op) else {
2733 return Err(invalid_operands(
2734 &instr.mnemonic,
2735 "expected label or offset",
2736 instr.span,
2737 ));
2738 };
2739 buf.push(0x0F);
2741 buf.push(0x80 + cc);
2742 let reloc_off = buf.len();
2743 buf.extend_from_slice(&0i32.to_le_bytes());
2744 *reloc = Some(Relocation {
2745 offset: reloc_off,
2746 size: 4,
2747 label: alloc::rc::Rc::from(label),
2748 kind: RelocKind::X86Relative,
2749 addend,
2750 trailing_bytes: 0,
2751 });
2752 *relax = Some(RelaxInfo {
2754 short_bytes: InstrBytes::from_slice(&[0x70 + cc, 0x00]),
2755 short_reloc_offset: 1,
2756 short_relocation: None,
2757 });
2758 }
2759 Operand::Immediate(off) => {
2760 buf.push(0x0F);
2762 buf.push(0x80 + cc);
2763 buf.extend_from_slice(&(*off as i32).to_le_bytes());
2764 }
2765 _ => {
2766 return Err(invalid_operands(
2767 &instr.mnemonic,
2768 "expected label or offset",
2769 instr.span,
2770 ))
2771 }
2772 }
2773 Ok(())
2774}
2775
2776#[cfg(any(feature = "x86", feature = "x86_64"))]
2777pub(crate) fn encode_loop(
2778 buf: &mut InstrBytes,
2779 ops: &OperandList,
2780 instr: &Instruction,
2781 opcode: u8,
2782 reloc: &mut Option<Relocation>,
2783 relax: &mut Option<RelaxInfo>,
2784) -> Result<(), AsmError> {
2785 if ops.len() != 1 {
2786 return Err(invalid_operands(
2787 &instr.mnemonic,
2788 "expected 1 operand",
2789 instr.span,
2790 ));
2791 }
2792 match &ops[0] {
2793 op @ (Operand::Label(_) | Operand::Expression(_)) => {
2794 let Some((label, addend)) = extract_label(op) else {
2795 return Err(invalid_operands(
2796 &instr.mnemonic,
2797 "expected label",
2798 instr.span,
2799 ));
2800 };
2801 buf.push(opcode);
2814 buf.push(0x02);
2815 buf.push(0xEB);
2816 buf.push(0x05);
2817 buf.push(0xE9);
2818 let reloc_off = buf.len();
2819 buf.extend_from_slice(&0i32.to_le_bytes());
2820 *reloc = Some(Relocation {
2821 offset: reloc_off,
2822 size: 4,
2823 label: alloc::rc::Rc::from(label),
2824 kind: RelocKind::X86Relative,
2825 addend,
2826 trailing_bytes: 0,
2827 });
2828 *relax = Some(RelaxInfo {
2830 short_bytes: InstrBytes::from_slice(&[opcode, 0x00]),
2831 short_reloc_offset: 1,
2832 short_relocation: None,
2833 });
2834 }
2835 _ => {
2836 return Err(invalid_operands(
2837 &instr.mnemonic,
2838 "expected label",
2839 instr.span,
2840 ))
2841 }
2842 }
2843 Ok(())
2844}
2845
2846#[cfg(any(feature = "x86", feature = "x86_64"))]
2847pub(crate) fn encode_setcc(
2848 buf: &mut InstrBytes,
2849 ops: &OperandList,
2850 instr: &Instruction,
2851 cc: u8,
2852) -> Result<(), AsmError> {
2853 if ops.len() != 1 {
2854 return Err(invalid_operands(
2855 &instr.mnemonic,
2856 "expected 1 operand",
2857 instr.span,
2858 ));
2859 }
2860 match &ops[0] {
2861 Operand::Register(reg) => {
2862 if reg.size_bits() != 8 {
2863 return Err(invalid_operands(
2864 &instr.mnemonic,
2865 "SETcc requires an 8-bit register operand",
2866 instr.span,
2867 ));
2868 }
2869 let b = reg.is_extended();
2870 let need = b || reg.requires_rex_for_byte();
2871 if need {
2872 buf.push(rex(false, false, false, b));
2873 }
2874 buf.push(0x0F);
2875 buf.push(0x90 + cc);
2876 buf.push(modrm(0b11, 0, reg.base_code()));
2877 }
2878 Operand::Memory(mem) => {
2879 emit_rex_for_digit_mem(buf, 8, mem);
2880 buf.push(0x0F);
2881 buf.push(0x90 + cc);
2882 emit_mem_modrm(buf, 0, mem);
2883 }
2884 _ => {
2885 return Err(invalid_operands(
2886 &instr.mnemonic,
2887 "expected register or memory",
2888 instr.span,
2889 ))
2890 }
2891 }
2892 Ok(())
2893}
2894
2895#[cfg(any(feature = "x86", feature = "x86_64"))]
2896pub(crate) fn encode_cmovcc(
2897 buf: &mut InstrBytes,
2898 ops: &OperandList,
2899 instr: &Instruction,
2900 cc: u8,
2901) -> Result<(), AsmError> {
2902 if ops.len() != 2 {
2903 return Err(invalid_operands(
2904 &instr.mnemonic,
2905 "expected 2 operands",
2906 instr.span,
2907 ));
2908 }
2909 match (&ops[0], &ops[1]) {
2910 (Operand::Register(dst), Operand::Register(src)) => {
2911 let size = reg_size(*dst);
2912 if size == 8 {
2913 return Err(invalid_operands(
2914 &instr.mnemonic,
2915 "CMOVcc requires 16/32/64-bit operands",
2916 instr.span,
2917 ));
2918 }
2919 let w = size == 64;
2920 let r = dst.is_extended();
2921 let b = src.is_extended();
2922 if size == 16 {
2923 buf.push(0x66);
2924 }
2925 if needs_rex(w, r, false, b) {
2926 buf.push(rex(w, r, false, b));
2927 }
2928 buf.push(0x0F);
2929 buf.push(0x40 + cc);
2930 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
2931 }
2932 (Operand::Register(dst), Operand::Memory(mem)) => {
2933 if reg_size(*dst) == 8 {
2934 return Err(invalid_operands(
2935 &instr.mnemonic,
2936 "CMOVcc requires 16/32/64-bit operands",
2937 instr.span,
2938 ));
2939 }
2940 emit_rex_for_reg_mem(buf, *dst, mem)?;
2941 buf.push(0x0F);
2942 buf.push(0x40 + cc);
2943 emit_mem_modrm(buf, dst.base_code(), mem);
2944 }
2945 _ => {
2946 return Err(invalid_operands(
2947 &instr.mnemonic,
2948 "expected reg, r/m",
2949 instr.span,
2950 ))
2951 }
2952 }
2953 Ok(())
2954}
2955
2956#[cfg(any(feature = "x86", feature = "x86_64"))]
2957pub(crate) fn encode_movzx(
2958 buf: &mut InstrBytes,
2959 ops: &OperandList,
2960 instr: &Instruction,
2961) -> Result<(), AsmError> {
2962 if ops.len() != 2 {
2963 return Err(invalid_operands("movzx", "expected 2 operands", instr.span));
2964 }
2965 match (&ops[0], &ops[1]) {
2966 (Operand::Register(dst), Operand::Register(src)) => {
2967 let dst_size = reg_size(*dst);
2968 let src_size = reg_size(*src);
2969 let w = dst_size == 64;
2970 let r = dst.is_extended();
2971 let b = src.is_extended();
2972 if dst_size == 16 {
2973 buf.push(0x66);
2974 }
2975 let need = needs_rex(w, r, false, b) || src.requires_rex_for_byte();
2976 if need {
2977 buf.push(rex(w, r, false, b));
2978 }
2979 buf.push(0x0F);
2980 buf.push(if src_size == 8 { 0xB6 } else { 0xB7 }); buf.push(modrm(0b11, dst.base_code(), src.base_code()));
2982 }
2983 (Operand::Register(dst), Operand::Memory(mem)) => {
2984 let src_size = instr
2985 .size_hint
2986 .map_or(mem.size.map_or(8u8, |s| s.bits() as u8), |s| s.bits() as u8);
2987 emit_rex_for_reg_mem(buf, *dst, mem)?;
2988 buf.push(0x0F);
2989 buf.push(if src_size == 8 { 0xB6 } else { 0xB7 });
2990 emit_mem_modrm(buf, dst.base_code(), mem);
2991 }
2992 _ => return Err(invalid_operands("movzx", "expected reg, r/m", instr.span)),
2993 }
2994 Ok(())
2995}
2996
2997#[cfg(any(feature = "x86", feature = "x86_64"))]
2998pub(crate) fn encode_movsx(
2999 buf: &mut InstrBytes,
3000 ops: &OperandList,
3001 instr: &Instruction,
3002) -> Result<(), AsmError> {
3003 if ops.len() != 2 {
3004 return Err(invalid_operands("movsx", "expected 2 operands", instr.span));
3005 }
3006 match (&ops[0], &ops[1]) {
3007 (Operand::Register(dst), Operand::Register(src)) => {
3008 let dst_size = reg_size(*dst);
3009 let src_size = reg_size(*src);
3010 let w = dst_size == 64;
3011 let r = dst.is_extended();
3012 let b = src.is_extended();
3013 if dst_size == 16 {
3014 buf.push(0x66);
3015 }
3016 let need = needs_rex(w, r, false, b) || src.requires_rex_for_byte();
3017 if need {
3018 buf.push(rex(w, r, false, b));
3019 }
3020 if src_size == 32 {
3021 buf.push(0x63);
3023 } else {
3024 buf.push(0x0F);
3025 buf.push(if src_size == 8 { 0xBE } else { 0xBF });
3026 }
3027 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
3028 }
3029 (Operand::Register(dst), Operand::Memory(mem)) => {
3030 let src_size = instr
3031 .size_hint
3032 .map_or(mem.size.map_or(8u8, |s| s.bits() as u8), |s| s.bits() as u8);
3033 let dst_size = reg_size(*dst);
3034 if src_size == 32 {
3035 let w = dst_size == 64;
3037 let r = dst.is_extended();
3038 let x = mem.index.is_some_and(|r| r.is_extended());
3039 let b = mem.base.is_some_and(|r| r.is_extended());
3040 if dst_size == 16 {
3041 buf.push(0x66);
3042 }
3043 if needs_rex(w, r, x, b) {
3044 buf.push(rex(w, r, x, b));
3045 }
3046 buf.push(0x63);
3047 } else {
3048 emit_rex_for_reg_mem(buf, *dst, mem)?;
3049 buf.push(0x0F);
3050 buf.push(if src_size == 8 { 0xBE } else { 0xBF });
3051 }
3052 emit_mem_modrm(buf, dst.base_code(), mem);
3053 }
3054 _ => return Err(invalid_operands("movsx", "expected reg, r/m", instr.span)),
3055 }
3056 Ok(())
3057}
3058
3059#[cfg(any(feature = "x86", feature = "x86_64"))]
3060pub(crate) fn encode_xchg(
3061 buf: &mut InstrBytes,
3062 ops: &OperandList,
3063 instr: &Instruction,
3064) -> Result<(), AsmError> {
3065 if ops.len() != 2 {
3066 return Err(invalid_operands("xchg", "expected 2 operands", instr.span));
3067 }
3068 match (&ops[0], &ops[1]) {
3069 (Operand::Register(dst), Operand::Register(src)) => {
3070 let size = reg_size(*dst);
3071 if size == 16
3073 && ((dst.base_code() == 0 && !dst.is_extended())
3074 || (src.base_code() == 0 && !src.is_extended()))
3075 {
3076 let other = if dst.base_code() == 0 && !dst.is_extended() {
3077 *src
3078 } else {
3079 *dst
3080 };
3081 let b = other.is_extended();
3082 buf.push(0x66);
3083 if b {
3084 buf.push(rex(false, false, false, b));
3085 }
3086 buf.push(0x90 + other.base_code());
3087 return Ok(());
3088 }
3089 if size >= 32
3091 && ((dst.base_code() == 0 && !dst.is_extended())
3092 || (src.base_code() == 0 && !src.is_extended()))
3093 {
3094 let other = if dst.base_code() == 0 && !dst.is_extended() {
3095 *src
3096 } else {
3097 *dst
3098 };
3099 let w = size == 64;
3100 let b = other.is_extended();
3101 if needs_rex(w, false, false, b) {
3102 buf.push(rex(w, false, false, b));
3103 }
3104 buf.push(0x90 + other.base_code());
3105 return Ok(());
3106 }
3107 let opcode = if size == 8 { 0x86u8 } else { 0x87u8 };
3108 emit_rr(buf, &[opcode], *dst, *src, instr.span)?;
3109 }
3110 (Operand::Register(reg), Operand::Memory(mem)) => {
3112 let size = reg_size(*reg);
3113 let opcode = if size == 8 { 0x86u8 } else { 0x87u8 };
3114 emit_rex_for_reg_mem(buf, *reg, mem)?;
3115 buf.push(opcode);
3116 emit_mem_modrm(buf, reg.base_code(), mem);
3117 }
3118 (Operand::Memory(mem), Operand::Register(reg)) => {
3120 let size = reg_size(*reg);
3121 let opcode = if size == 8 { 0x86u8 } else { 0x87u8 };
3122 emit_rex_for_reg_mem(buf, *reg, mem)?;
3123 buf.push(opcode);
3124 emit_mem_modrm(buf, reg.base_code(), mem);
3125 }
3126 _ => {
3127 return Err(invalid_operands(
3128 "xchg",
3129 "unsupported operand combination",
3130 instr.span,
3131 ))
3132 }
3133 }
3134 Ok(())
3135}
3136
3137#[cfg(any(feature = "x86", feature = "x86_64"))]
3138pub(crate) fn encode_bt(
3139 buf: &mut InstrBytes,
3140 ops: &OperandList,
3141 instr: &Instruction,
3142 digit: u8,
3143) -> Result<(), AsmError> {
3144 if ops.len() != 2 {
3145 return Err(invalid_operands(
3146 &instr.mnemonic,
3147 "expected 2 operands",
3148 instr.span,
3149 ));
3150 }
3151 if let Operand::Register(r) = &ops[0] {
3153 if reg_size(*r) == 8 {
3154 return Err(invalid_operands(
3155 &instr.mnemonic,
3156 "8-bit operands not supported",
3157 instr.span,
3158 ));
3159 }
3160 }
3161 match (&ops[0], &ops[1]) {
3162 (Operand::Register(dst), Operand::Immediate(imm)) => {
3163 let size = reg_size(*dst);
3164 let w = size == 64;
3165 let b = dst.is_extended();
3166 if size == 16 {
3167 buf.push(0x66);
3168 }
3169 if needs_rex(w, false, false, b) {
3170 buf.push(rex(w, false, false, b));
3171 }
3172 buf.push(0x0F);
3173 buf.push(0xBA);
3174 buf.push(modrm(0b11, digit, dst.base_code()));
3175 buf.push(*imm as u8);
3176 }
3177 (Operand::Register(dst), Operand::Register(src)) => {
3178 let size = reg_size(*dst);
3179 let w = size == 64;
3180 let r = src.is_extended();
3181 let b = dst.is_extended();
3182 if size == 16 {
3183 buf.push(0x66);
3184 }
3185 if needs_rex(w, r, false, b) {
3186 buf.push(rex(w, r, false, b));
3187 }
3188 buf.push(0x0F);
3189 let base = match digit {
3190 4 => 0xA3, 5 => 0xAB, 6 => 0xB3, 7 => 0xBB, _ => 0xA3,
3195 };
3196 buf.push(base);
3197 buf.push(modrm(0b11, src.base_code(), dst.base_code()));
3198 }
3199 (Operand::Memory(mem), Operand::Register(src)) => {
3200 let size = mem.size.map_or(reg_size(*src), |s| s.bits() as u8);
3201 let w = size == 64;
3202 let r = src.is_extended();
3203 let x = mem.index.is_some_and(|r| r.is_extended());
3204 let b = mem.base.is_some_and(|r| r.is_extended());
3205 if size == 16 {
3206 buf.push(0x66);
3207 }
3208 if needs_rex(w, r, x, b) {
3209 buf.push(rex(w, r, x, b));
3210 }
3211 buf.push(0x0F);
3212 let base = match digit {
3213 4 => 0xA3,
3214 5 => 0xAB,
3215 6 => 0xB3,
3216 7 => 0xBB,
3217 _ => 0xA3,
3218 };
3219 buf.push(base);
3220 emit_mem_modrm(buf, src.base_code(), mem);
3221 }
3222 (Operand::Memory(mem), Operand::Immediate(imm)) => {
3223 let size = instr
3224 .size_hint
3225 .map_or(mem.size.map_or(32u8, |s| s.bits() as u8), |s| {
3226 s.bits() as u8
3227 });
3228 let w = size == 64;
3229 let x = mem.index.is_some_and(|r| r.is_extended());
3230 let b = mem.base.is_some_and(|r| r.is_extended());
3231 if size == 16 {
3232 buf.push(0x66);
3233 }
3234 if needs_rex(w, false, x, b) {
3235 buf.push(rex(w, false, x, b));
3236 }
3237 buf.push(0x0F);
3238 buf.push(0xBA);
3239 emit_mem_modrm(buf, digit, mem);
3240 buf.push(*imm as u8);
3241 }
3242 _ => {
3243 return Err(invalid_operands(
3244 &instr.mnemonic,
3245 "unsupported operand combination",
3246 instr.span,
3247 ))
3248 }
3249 }
3250 Ok(())
3251}
3252
3253#[cfg(any(feature = "x86", feature = "x86_64"))]
3254pub(crate) fn encode_bsf_bsr(
3255 buf: &mut InstrBytes,
3256 ops: &OperandList,
3257 instr: &Instruction,
3258 opcode2: u8,
3259) -> Result<(), AsmError> {
3260 if ops.len() != 2 {
3261 return Err(invalid_operands(
3262 &instr.mnemonic,
3263 "expected 2 operands",
3264 instr.span,
3265 ));
3266 }
3267 if let Operand::Register(r) = &ops[0] {
3269 if reg_size(*r) == 8 {
3270 return Err(invalid_operands(
3271 &instr.mnemonic,
3272 "8-bit operands not supported",
3273 instr.span,
3274 ));
3275 }
3276 }
3277 match (&ops[0], &ops[1]) {
3278 (Operand::Register(dst), Operand::Register(src)) => {
3279 let size = reg_size(*dst);
3280 let w = size == 64;
3281 let r = dst.is_extended();
3282 let b = src.is_extended();
3283 if size == 16 {
3284 buf.push(0x66);
3285 }
3286 if needs_rex(w, r, false, b) {
3287 buf.push(rex(w, r, false, b));
3288 }
3289 buf.push(0x0F);
3290 buf.push(opcode2);
3291 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
3292 }
3293 (Operand::Register(dst), Operand::Memory(mem)) => {
3294 emit_rex_for_reg_mem(buf, *dst, mem)?;
3295 buf.push(0x0F);
3296 buf.push(opcode2);
3297 emit_mem_modrm(buf, dst.base_code(), mem);
3298 }
3299 _ => {
3300 return Err(invalid_operands(
3301 &instr.mnemonic,
3302 "expected reg, r/m",
3303 instr.span,
3304 ))
3305 }
3306 }
3307 Ok(())
3308}
3309
3310#[inline]
3312#[cfg(any(feature = "x86", feature = "x86_64"))]
3313fn encode_f3_0f_rm(
3314 buf: &mut InstrBytes,
3315 ops: &OperandList,
3316 mnemonic: &str,
3317 opcode: u8,
3318 span: Span,
3319) -> Result<(), AsmError> {
3320 if ops.len() != 2 {
3321 return Err(invalid_operands(mnemonic, "expected 2 operands", span));
3322 }
3323 if let Operand::Register(r) = &ops[0] {
3324 if reg_size(*r) == 8 {
3325 return Err(invalid_operands(
3326 mnemonic,
3327 "8-bit operands not supported",
3328 span,
3329 ));
3330 }
3331 }
3332 match (&ops[0], &ops[1]) {
3333 (Operand::Register(dst), Operand::Register(src)) => {
3334 let size = reg_size(*dst);
3335 let w = size == 64;
3336 let r = dst.is_extended();
3337 let b = src.is_extended();
3338 buf.push(0xF3);
3339 if size == 16 {
3340 buf.push(0x66);
3341 }
3342 if needs_rex(w, r, false, b) {
3343 buf.push(rex(w, r, false, b));
3344 }
3345 buf.push(0x0F);
3346 buf.push(opcode);
3347 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
3348 }
3349 (Operand::Register(dst), Operand::Memory(mem)) => {
3350 buf.push(0xF3);
3351 emit_rex_for_reg_mem(buf, *dst, mem)?;
3352 buf.push(0x0F);
3353 buf.push(opcode);
3354 emit_mem_modrm(buf, dst.base_code(), mem);
3355 }
3356 _ => return Err(invalid_operands(mnemonic, "expected reg, r/m", span)),
3357 }
3358 Ok(())
3359}
3360
3361#[cfg(any(feature = "x86", feature = "x86_64"))]
3362pub(crate) fn encode_popcnt(
3363 buf: &mut InstrBytes,
3364 ops: &OperandList,
3365 instr: &Instruction,
3366) -> Result<(), AsmError> {
3367 encode_f3_0f_rm(buf, ops, "popcnt", 0xB8, instr.span)
3368}
3369
3370#[cfg(any(feature = "x86", feature = "x86_64"))]
3371pub(crate) fn encode_lzcnt(
3372 buf: &mut InstrBytes,
3373 ops: &OperandList,
3374 instr: &Instruction,
3375) -> Result<(), AsmError> {
3376 encode_f3_0f_rm(buf, ops, "lzcnt", 0xBD, instr.span)
3377}
3378
3379#[cfg(any(feature = "x86", feature = "x86_64"))]
3380pub(crate) fn encode_tzcnt(
3381 buf: &mut InstrBytes,
3382 ops: &OperandList,
3383 instr: &Instruction,
3384) -> Result<(), AsmError> {
3385 encode_f3_0f_rm(buf, ops, "tzcnt", 0xBC, instr.span)
3386}
3387
3388#[cfg(any(feature = "x86", feature = "x86_64"))]
3389pub(crate) fn encode_bswap(
3390 buf: &mut InstrBytes,
3391 ops: &OperandList,
3392 instr: &Instruction,
3393) -> Result<(), AsmError> {
3394 if ops.len() != 1 {
3395 return Err(invalid_operands("bswap", "expected 1 operand", instr.span));
3396 }
3397 match &ops[0] {
3398 Operand::Register(reg) => {
3399 let size = reg_size(*reg);
3400 if size == 8 {
3401 return Err(invalid_operands(
3402 "bswap",
3403 "8-bit operands not supported",
3404 instr.span,
3405 ));
3406 }
3407 if size == 16 {
3408 return Err(invalid_operands(
3409 "bswap",
3410 "16-bit bswap has undefined behavior; use xchg or rol instead",
3411 instr.span,
3412 ));
3413 }
3414 let w = size == 64;
3415 let b = reg.is_extended();
3416 if needs_rex(w, false, false, b) {
3417 buf.push(rex(w, false, false, b));
3418 }
3419 buf.push(0x0F);
3420 buf.push(0xC8 + reg.base_code());
3421 }
3422 _ => return Err(invalid_operands("bswap", "expected register", instr.span)),
3423 }
3424 Ok(())
3425}
3426
3427#[cfg(any(feature = "x86", feature = "x86_64"))]
3435pub(crate) fn emit_imm(buf: &mut InstrBytes, imm: i128, size: u8) {
3436 debug_assert!(
3437 matches!(size, 8 | 16 | 32 | 64),
3438 "emit_imm: unsupported immediate size {size} (expected 8, 16, 32, or 64)"
3439 );
3440 match size {
3441 0..=8 => buf.push(imm as u8),
3442 9..=16 => buf.extend_from_slice(&(imm as u16).to_le_bytes()),
3443 17..=32 => buf.extend_from_slice(&(imm as u32).to_le_bytes()),
3444 _ => buf.extend_from_slice(&(imm as u64).to_le_bytes()),
3445 }
3446}
3447
3448#[inline]
3449#[cfg(any(feature = "x86", feature = "x86_64"))]
3450pub(crate) fn invalid_operands(_mnemonic: &str, detail: &str, span: Span) -> AsmError {
3451 AsmError::InvalidOperands {
3452 detail: String::from(detail),
3453 span,
3454 }
3455}
3456
3457#[cfg(any(feature = "x86", feature = "x86_64"))]
3462fn emit_rex_sse_rr(buf: &mut InstrBytes, w: bool, reg: Register, rm: Register) {
3463 let r = reg.is_extended();
3464 let b = rm.is_extended();
3465 if needs_rex(w, r, false, b) {
3466 buf.push(rex(w, r, false, b));
3467 }
3468}
3469
3470#[cfg(any(feature = "x86", feature = "x86_64"))]
3473fn emit_rex_sse_rm(buf: &mut InstrBytes, w: bool, reg: Register, mem: &MemoryOperand) {
3474 let r = reg.is_extended();
3475 let x = mem.index.is_some_and(|r| r.is_extended());
3476 let b = mem.base.is_some_and(|r| r.is_extended());
3477 if needs_rex(w, r, x, b) {
3478 buf.push(rex(w, r, x, b));
3479 }
3480}
3481
3482#[cfg(any(feature = "x86", feature = "x86_64"))]
3490pub(crate) fn encode_sse_rr(
3491 buf: &mut InstrBytes,
3492 mandatory_prefix: u8,
3493 opcode: &[u8],
3494 dst: Register,
3495 src: Register,
3496 rex_w: bool,
3497) {
3498 if mandatory_prefix != 0 {
3499 buf.push(mandatory_prefix);
3500 }
3501 emit_rex_sse_rr(buf, rex_w, dst, src);
3502 buf.extend_from_slice(opcode);
3503 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
3504}
3505
3506#[cfg(any(feature = "x86", feature = "x86_64"))]
3508pub(crate) fn encode_sse_rm(
3509 buf: &mut InstrBytes,
3510 mandatory_prefix: u8,
3511 opcode: &[u8],
3512 reg: Register,
3513 mem: &MemoryOperand,
3514 reloc: &mut Option<Relocation>,
3515 rex_w: bool,
3516) {
3517 if mandatory_prefix != 0 {
3518 buf.push(mandatory_prefix);
3519 }
3520 emit_rex_sse_rm(buf, rex_w, reg, mem);
3521 buf.extend_from_slice(opcode);
3522 let disp_off = emit_mem_modrm(buf, reg.base_code(), mem);
3523 set_mem_reloc(reloc, mem, disp_off, buf.len());
3524}
3525
3526#[cfg(any(feature = "x86", feature = "x86_64"))]
3529pub(crate) fn encode_sse_mr(
3530 buf: &mut InstrBytes,
3531 mandatory_prefix: u8,
3532 opcode: &[u8],
3533 mem: &MemoryOperand,
3534 reg: Register,
3535 reloc: &mut Option<Relocation>,
3536 rex_w: bool,
3537) {
3538 encode_sse_rm(buf, mandatory_prefix, opcode, reg, mem, reloc, rex_w);
3540}
3541
3542#[cfg(any(feature = "x86", feature = "x86_64"))]
3547pub(crate) fn encode_sse_op(
3548 buf: &mut InstrBytes,
3549 ops: &OperandList,
3550 instr: &Instruction,
3551 mandatory_prefix: u8,
3552 load_opcode: &[u8],
3553 store_opcode: Option<&[u8]>,
3554 reloc: &mut Option<Relocation>,
3555) -> Result<(), AsmError> {
3556 match (ops.first(), ops.get(1)) {
3557 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3559 if dst.is_xmm() && src.is_xmm() =>
3560 {
3561 encode_sse_rr(buf, mandatory_prefix, load_opcode, *dst, *src, false);
3562 Ok(())
3563 }
3564 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) if dst.is_xmm() => {
3566 encode_sse_rm(buf, mandatory_prefix, load_opcode, *dst, mem, reloc, false);
3567 Ok(())
3568 }
3569 (Some(Operand::Memory(mem)), Some(Operand::Register(src))) if src.is_xmm() => {
3571 let opcode = store_opcode.unwrap_or(load_opcode);
3572 encode_sse_mr(buf, mandatory_prefix, opcode, mem, *src, reloc, false);
3573 Ok(())
3574 }
3575 _ => Err(invalid_operands(
3576 instr.mnemonic.as_str(),
3577 "expected xmm,xmm/m or m,xmm operands",
3578 instr.span,
3579 )),
3580 }
3581}
3582
3583#[cfg(any(feature = "x86", feature = "x86_64"))]
3585pub(crate) fn encode_sse_imm(
3586 buf: &mut InstrBytes,
3587 ops: &OperandList,
3588 instr: &Instruction,
3589 mandatory_prefix: u8,
3590 opcode: &[u8],
3591 reloc: &mut Option<Relocation>,
3592) -> Result<(), AsmError> {
3593 let imm = match ops.get(2) {
3594 Some(Operand::Immediate(v)) => *v,
3595 _ => {
3596 return Err(invalid_operands(
3597 instr.mnemonic.as_str(),
3598 "expected xmm, xmm/m, imm8",
3599 instr.span,
3600 ));
3601 }
3602 };
3603 match (ops.first(), ops.get(1)) {
3604 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3605 if dst.is_xmm() && src.is_xmm() =>
3606 {
3607 encode_sse_rr(buf, mandatory_prefix, opcode, *dst, *src, false);
3608 }
3609 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) if dst.is_xmm() => {
3610 encode_sse_rm(buf, mandatory_prefix, opcode, *dst, mem, reloc, false);
3611 }
3612 _ => {
3613 return Err(invalid_operands(
3614 instr.mnemonic.as_str(),
3615 "expected xmm, xmm/m, imm8",
3616 instr.span,
3617 ));
3618 }
3619 }
3620 buf.push(imm as u8);
3621 Ok(())
3622}
3623
3624#[cfg(any(feature = "x86", feature = "x86_64"))]
3626pub(crate) fn encode_movd_movq(
3627 buf: &mut InstrBytes,
3628 ops: &OperandList,
3629 instr: &Instruction,
3630 reloc: &mut Option<Relocation>,
3631 is_movq: bool,
3632) -> Result<(), AsmError> {
3633 match (ops.first(), ops.get(1)) {
3634 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3636 if dst.is_xmm() && !src.is_xmm() =>
3637 {
3638 let w = is_movq || src.size_bits() == 64;
3639 encode_sse_rr(buf, 0x66, &[0x0F, 0x6E], *dst, *src, w);
3640 Ok(())
3641 }
3642 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) if dst.is_xmm() => {
3643 let w = is_movq;
3644 encode_sse_rm(buf, 0x66, &[0x0F, 0x6E], *dst, mem, reloc, w);
3645 Ok(())
3646 }
3647 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3649 if !dst.is_xmm() && src.is_xmm() =>
3650 {
3651 let w = is_movq || dst.size_bits() == 64;
3652 encode_sse_rr(buf, 0x66, &[0x0F, 0x7E], *src, *dst, w);
3654 Ok(())
3655 }
3656 (Some(Operand::Memory(mem)), Some(Operand::Register(src))) if src.is_xmm() => {
3657 let w = is_movq;
3658 encode_sse_mr(buf, 0x66, &[0x0F, 0x7E], mem, *src, reloc, w);
3659 Ok(())
3660 }
3661 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3663 if dst.is_xmm() && src.is_xmm() =>
3664 {
3665 encode_sse_rr(buf, 0xF3, &[0x0F, 0x7E], *dst, *src, false);
3666 Ok(())
3667 }
3668 _ => Err(invalid_operands(
3669 instr.mnemonic.as_str(),
3670 "expected xmm,r/m or r/m,xmm operands",
3671 instr.span,
3672 )),
3673 }
3674}
3675
3676#[cfg(any(feature = "x86", feature = "x86_64"))]
3678pub(crate) fn encode_cvtsi2(
3679 buf: &mut InstrBytes,
3680 ops: &OperandList,
3681 instr: &Instruction,
3682 mandatory_prefix: u8,
3683 reloc: &mut Option<Relocation>,
3684) -> Result<(), AsmError> {
3685 match (ops.first(), ops.get(1)) {
3686 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3687 if dst.is_xmm() && !src.is_xmm() =>
3688 {
3689 let w = src.size_bits() == 64;
3690 encode_sse_rr(buf, mandatory_prefix, &[0x0F, 0x2A], *dst, *src, w);
3691 Ok(())
3692 }
3693 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) if dst.is_xmm() => {
3694 let w = mem.size == Some(OperandSize::Qword);
3695 encode_sse_rm(buf, mandatory_prefix, &[0x0F, 0x2A], *dst, mem, reloc, w);
3696 Ok(())
3697 }
3698 _ => Err(invalid_operands(
3699 instr.mnemonic.as_str(),
3700 "expected xmm, r/m32 or xmm, r/m64",
3701 instr.span,
3702 )),
3703 }
3704}
3705
3706#[cfg(any(feature = "x86", feature = "x86_64"))]
3708pub(crate) fn encode_cvt2si(
3709 buf: &mut InstrBytes,
3710 ops: &OperandList,
3711 instr: &Instruction,
3712 mandatory_prefix: u8,
3713 opcode2: u8,
3714 reloc: &mut Option<Relocation>,
3715) -> Result<(), AsmError> {
3716 match (ops.first(), ops.get(1)) {
3717 (Some(Operand::Register(dst)), Some(Operand::Register(src)))
3718 if !dst.is_xmm() && src.is_xmm() =>
3719 {
3720 let w = dst.size_bits() == 64;
3721 encode_sse_rr(buf, mandatory_prefix, &[0x0F, opcode2], *dst, *src, w);
3722 Ok(())
3723 }
3724 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) if !dst.is_xmm() => {
3725 let w = dst.size_bits() == 64;
3726 encode_sse_rm(buf, mandatory_prefix, &[0x0F, opcode2], *dst, mem, reloc, w);
3727 Ok(())
3728 }
3729 _ => Err(invalid_operands(
3730 instr.mnemonic.as_str(),
3731 "expected r32/r64, xmm/m operands",
3732 instr.span,
3733 )),
3734 }
3735}
3736
3737#[cfg(any(feature = "x86", feature = "x86_64"))]
3739pub(crate) fn encode_prefetch(
3740 buf: &mut InstrBytes,
3741 ops: &OperandList,
3742 instr: &Instruction,
3743 digit: u8,
3744) -> Result<(), AsmError> {
3745 match ops.first() {
3746 Some(Operand::Memory(mem)) => {
3747 let x = mem.index.is_some_and(|r| r.is_extended());
3749 let b = mem.base.is_some_and(|r| r.is_extended());
3750 if needs_rex(false, false, x, b) {
3751 buf.push(rex(false, false, x, b));
3752 }
3753 buf.extend_from_slice(&[0x0F, 0x18]);
3754 emit_mem_modrm(buf, digit, mem);
3755 Ok(())
3756 }
3757 _ => Err(invalid_operands(
3758 instr.mnemonic.as_str(),
3759 "expected memory operand",
3760 instr.span,
3761 )),
3762 }
3763}
3764
3765#[cfg(any(feature = "x86", feature = "x86_64"))]
3767pub(crate) fn encode_clflush(
3768 buf: &mut InstrBytes,
3769 ops: &OperandList,
3770 instr: &Instruction,
3771) -> Result<(), AsmError> {
3772 match ops.first() {
3773 Some(Operand::Memory(mem)) => {
3774 let x = mem.index.is_some_and(|r| r.is_extended());
3775 let b = mem.base.is_some_and(|r| r.is_extended());
3776 if needs_rex(false, false, x, b) {
3777 buf.push(rex(false, false, x, b));
3778 }
3779 buf.extend_from_slice(&[0x0F, 0xAE]);
3780 emit_mem_modrm(buf, 7, mem);
3781 Ok(())
3782 }
3783 _ => Err(invalid_operands(
3784 "clflush",
3785 "expected memory operand",
3786 instr.span,
3787 )),
3788 }
3789}
3790
3791#[cfg(any(feature = "x86", feature = "x86_64"))]
3793pub(crate) fn encode_clflushopt(
3794 buf: &mut InstrBytes,
3795 ops: &OperandList,
3796 instr: &Instruction,
3797) -> Result<(), AsmError> {
3798 match ops.first() {
3799 Some(Operand::Memory(mem)) => {
3800 buf.push(0x66);
3801 let x = mem.index.is_some_and(|r| r.is_extended());
3802 let b = mem.base.is_some_and(|r| r.is_extended());
3803 if needs_rex(false, false, x, b) {
3804 buf.push(rex(false, false, x, b));
3805 }
3806 buf.extend_from_slice(&[0x0F, 0xAE]);
3807 emit_mem_modrm(buf, 7, mem);
3808 Ok(())
3809 }
3810 _ => Err(invalid_operands(
3811 "clflushopt",
3812 "expected memory operand",
3813 instr.span,
3814 )),
3815 }
3816}
3817
3818#[cfg(any(feature = "x86", feature = "x86_64"))]
3820pub(crate) fn encode_clwb(
3821 buf: &mut InstrBytes,
3822 ops: &OperandList,
3823 instr: &Instruction,
3824) -> Result<(), AsmError> {
3825 match ops.first() {
3826 Some(Operand::Memory(mem)) => {
3827 buf.push(0x66);
3828 let x = mem.index.is_some_and(|r| r.is_extended());
3829 let b = mem.base.is_some_and(|r| r.is_extended());
3830 if needs_rex(false, false, x, b) {
3831 buf.push(rex(false, false, x, b));
3832 }
3833 buf.extend_from_slice(&[0x0F, 0xAE]);
3834 emit_mem_modrm(buf, 6, mem);
3835 Ok(())
3836 }
3837 _ => Err(invalid_operands(
3838 "clwb",
3839 "expected memory operand",
3840 instr.span,
3841 )),
3842 }
3843}
3844
3845#[cfg(any(feature = "x86", feature = "x86_64"))]
3847pub(crate) fn encode_prefetchw(
3848 buf: &mut InstrBytes,
3849 ops: &OperandList,
3850 instr: &Instruction,
3851) -> Result<(), AsmError> {
3852 match ops.first() {
3853 Some(Operand::Memory(mem)) => {
3854 let x = mem.index.is_some_and(|r| r.is_extended());
3855 let b = mem.base.is_some_and(|r| r.is_extended());
3856 if needs_rex(false, false, x, b) {
3857 buf.push(rex(false, false, x, b));
3858 }
3859 buf.extend_from_slice(&[0x0F, 0x0D]);
3860 emit_mem_modrm(buf, 1, mem);
3861 Ok(())
3862 }
3863 _ => Err(invalid_operands(
3864 "prefetchw",
3865 "expected memory operand",
3866 instr.span,
3867 )),
3868 }
3869}
3870
3871#[cfg(any(feature = "x86", feature = "x86_64"))]
3873pub(crate) fn encode_crc32(
3874 buf: &mut InstrBytes,
3875 ops: &OperandList,
3876 instr: &Instruction,
3877) -> Result<(), AsmError> {
3878 match (ops.first(), ops.get(1)) {
3879 (Some(Operand::Register(dst)), Some(Operand::Register(src))) => {
3880 let dst_s = dst.size_bits();
3881 let src_s = src.size_bits();
3882 if dst_s != 32 && dst_s != 64 {
3883 return Err(invalid_operands(
3884 "crc32",
3885 "destination must be r32 or r64",
3886 instr.span,
3887 ));
3888 }
3889 buf.push(0xF2);
3890 let w = dst_s == 64;
3891 let opcode2 = if src_s == 8 { 0xF0u8 } else { 0xF1 };
3892 if src_s == 16 {
3893 buf.push(0x66);
3894 }
3895 emit_rex_sse_rr(buf, w, *dst, *src);
3896 buf.extend_from_slice(&[0x0F, 0x38, opcode2]);
3897 buf.push(modrm(0b11, dst.base_code(), src.base_code()));
3898 Ok(())
3899 }
3900 (Some(Operand::Register(dst)), Some(Operand::Memory(mem))) => {
3901 let dst_s = dst.size_bits();
3902 if dst_s != 32 && dst_s != 64 {
3903 return Err(invalid_operands(
3904 "crc32",
3905 "destination must be r32 or r64",
3906 instr.span,
3907 ));
3908 }
3909 let src_s = instr.size_hint.map_or_else(
3910 || mem.size.map_or(32u8, |s| s.bits() as u8),
3911 |s| s.bits() as u8,
3912 );
3913 buf.push(0xF2);
3914 let w = dst_s == 64;
3915 let opcode2 = if src_s == 8 { 0xF0u8 } else { 0xF1 };
3916 if src_s == 16 {
3917 buf.push(0x66);
3918 }
3919 emit_rex_sse_rm(buf, w, *dst, mem);
3920 buf.extend_from_slice(&[0x0F, 0x38, opcode2]);
3921 emit_mem_modrm(buf, dst.base_code(), mem);
3922 Ok(())
3923 }
3924 _ => Err(invalid_operands(
3925 "crc32",
3926 "expected r32/r64, r/m operands",
3927 instr.span,
3928 )),
3929 }
3930}
3931
3932#[cfg(any(feature = "x86", feature = "x86_64"))]
3941fn vex_pp(mandatory_prefix: u8) -> u8 {
3942 match mandatory_prefix {
3943 0x00 => 0b00,
3944 0x66 => 0b01,
3945 0xF3 => 0b10,
3946 0xF2 => 0b11,
3947 _ => 0b00,
3948 }
3949}
3950
3951#[cfg(any(feature = "x86", feature = "x86_64"))]
3954fn vex_mmmmm(escape: &[u8]) -> u8 {
3955 match escape {
3956 [0x0F] => 0b00001,
3957 [0x0F, 0x38] => 0b00010,
3958 [0x0F, 0x3A] => 0b00011,
3959 _ => 0b00001,
3960 }
3961}
3962
3963#[cfg(any(feature = "x86", feature = "x86_64"))]
3974fn emit_vex2(buf: &mut InstrBytes, r: bool, vvvv: u8, l: bool, pp: u8) {
3975 let byte1 = (if r { 0 } else { 0x80 })
3976 | (((!vvvv) & 0x0F) << 3)
3977 | (if l { 0x04 } else { 0 })
3978 | (pp & 0x03);
3979 buf.push(0xC5);
3980 buf.push(byte1);
3981}
3982
3983#[cfg(any(feature = "x86", feature = "x86_64"))]
3985fn emit_vex3(
3986 buf: &mut InstrBytes,
3987 r: bool,
3988 x: bool,
3989 b: bool,
3990 mmmmm: u8,
3991 w: bool,
3992 vvvv: u8,
3993 l: bool,
3994 pp: u8,
3995) {
3996 let byte1 = (if r { 0 } else { 0x80 })
3997 | (if x { 0 } else { 0x40 })
3998 | (if b { 0 } else { 0x20 })
3999 | (mmmmm & 0x1F);
4000 let byte2 = (if w { 0x80 } else { 0 })
4001 | (((!vvvv) & 0x0F) << 3)
4002 | (if l { 0x04 } else { 0 })
4003 | (pp & 0x03);
4004 buf.push(0xC4);
4005 buf.push(byte1);
4006 buf.push(byte2);
4007}
4008
4009#[cfg(any(feature = "x86", feature = "x86_64"))]
4022fn emit_vex_prefix(
4023 buf: &mut InstrBytes,
4024 reg_extended: bool,
4025 x_extended: bool,
4026 rm_extended: bool,
4027 w: bool,
4028 vvvv: u8,
4029 l: bool,
4030 pp: u8,
4031 escape: &[u8],
4032) {
4033 let mmmmm = vex_mmmmm(escape);
4034 if mmmmm == 0b00001 && !w && !x_extended && !rm_extended {
4036 emit_vex2(buf, reg_extended, vvvv, l, pp);
4037 } else {
4038 emit_vex3(
4039 buf,
4040 reg_extended,
4041 x_extended,
4042 rm_extended,
4043 mmmmm,
4044 w,
4045 vvvv,
4046 l,
4047 pp,
4048 );
4049 }
4050}
4051
4052#[cfg(any(feature = "x86", feature = "x86_64"))]
4055pub(crate) fn encode_vex_rrr(
4056 buf: &mut InstrBytes,
4057 pp: u8,
4058 escape: &[u8],
4059 opcode: u8,
4060 dst: Register,
4061 src1: Register,
4062 src2: Register,
4063 w: bool,
4064 l: bool,
4065) {
4066 let mandatory_pp = vex_pp(pp);
4067 emit_vex_prefix(
4068 buf,
4069 dst.is_extended(),
4070 false,
4071 src2.is_extended(),
4072 w,
4073 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4074 l,
4075 mandatory_pp,
4076 escape,
4077 );
4078 buf.push(opcode);
4079 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
4080}
4081
4082#[cfg(any(feature = "x86", feature = "x86_64"))]
4084pub(crate) fn encode_vex_rrm(
4085 buf: &mut InstrBytes,
4086 pp: u8,
4087 escape: &[u8],
4088 opcode: u8,
4089 dst: Register,
4090 src1: Register,
4091 mem: &MemoryOperand,
4092 reloc: &mut Option<Relocation>,
4093 w: bool,
4094 l: bool,
4095) {
4096 let mandatory_pp = vex_pp(pp);
4097 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4098 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4099 emit_vex_prefix(
4100 buf,
4101 dst.is_extended(),
4102 x_ext,
4103 b_ext,
4104 w,
4105 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4106 l,
4107 mandatory_pp,
4108 escape,
4109 );
4110 buf.push(opcode);
4111 emit_mem_modrm(buf, dst.base_code(), mem);
4112 if let Some(ref mut rel) = reloc {
4113 rel.offset = buf.len() - 4;
4114 }
4115}
4116
4117#[cfg(any(feature = "x86", feature = "x86_64"))]
4124pub(crate) fn encode_vex_op(
4125 buf: &mut InstrBytes,
4126 ops: &OperandList,
4127 instr: &Instruction,
4128 pp: u8,
4129 escape: &[u8],
4130 load_opcode: u8,
4131 store_opcode: Option<u8>,
4132 w: bool,
4133 reloc: &mut Option<Relocation>,
4134) -> Result<(), AsmError> {
4135 use Operand::*;
4136 let o = (ops.first(), ops.get(1), ops.get(2));
4137 match o {
4138 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)))
4140 if dst.is_vector() && src1.is_vector() && src2.is_vector() =>
4141 {
4142 let l = dst.is_ymm() || src1.is_ymm();
4143 encode_vex_rrr(buf, pp, escape, load_opcode, *dst, *src1, *src2, w, l);
4144 Ok(())
4145 }
4146 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)))
4148 if dst.is_vector() && src1.is_vector() =>
4149 {
4150 let l = dst.is_ymm() || src1.is_ymm();
4151 encode_vex_rrm(buf, pp, escape, load_opcode, *dst, *src1, mem, reloc, w, l);
4152 Ok(())
4153 }
4154 (Some(Register(dst)), Some(Register(src)), None) if dst.is_vector() && src.is_vector() => {
4156 let l = dst.is_ymm() || src.is_ymm();
4157 let mandatory_pp = vex_pp(pp);
4158 emit_vex_prefix(
4159 buf,
4160 dst.is_extended(),
4161 false,
4162 src.is_extended(),
4163 w,
4164 0,
4165 l,
4166 mandatory_pp,
4167 escape,
4168 );
4169 buf.push(load_opcode);
4170 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
4171 Ok(())
4172 }
4173 (Some(Register(dst)), Some(Memory(mem)), None) if dst.is_vector() => {
4175 let l = dst.is_ymm();
4176 let mandatory_pp = vex_pp(pp);
4177 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4178 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4179 emit_vex_prefix(
4180 buf,
4181 dst.is_extended(),
4182 x_ext,
4183 b_ext,
4184 w,
4185 0,
4186 l,
4187 mandatory_pp,
4188 escape,
4189 );
4190 buf.push(load_opcode);
4191 emit_mem_modrm(buf, dst.base_code(), mem);
4192 Ok(())
4193 }
4194 (Some(Memory(mem)), Some(Register(src)), None)
4196 if src.is_vector() && store_opcode.is_some() =>
4197 {
4198 let l = src.is_ymm();
4199 let mandatory_pp = vex_pp(pp);
4200 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4201 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4202 emit_vex_prefix(
4203 buf,
4204 src.is_extended(),
4205 x_ext,
4206 b_ext,
4207 w,
4208 0,
4209 l,
4210 mandatory_pp,
4211 escape,
4212 );
4213 buf.push(store_opcode.unwrap_or(0));
4215 emit_mem_modrm(buf, src.base_code(), mem);
4216 Ok(())
4217 }
4218 _ => Err(invalid_operands(
4219 &instr.mnemonic,
4220 "expected VEX xmm/ymm operands",
4221 instr.span,
4222 )),
4223 }
4224}
4225
4226#[cfg(any(feature = "x86", feature = "x86_64"))]
4228pub(crate) fn encode_vex_imm(
4229 buf: &mut InstrBytes,
4230 ops: &OperandList,
4231 instr: &Instruction,
4232 pp: u8,
4233 escape: &[u8],
4234 opcode: u8,
4235 w: bool,
4236 reloc: &mut Option<Relocation>,
4237) -> Result<(), AsmError> {
4238 use Operand::*;
4239 let o = (ops.first(), ops.get(1), ops.get(2), ops.get(3));
4240 match o {
4241 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)), Some(Immediate(imm)))
4243 if dst.is_vector() && src1.is_vector() && src2.is_vector() =>
4244 {
4245 let l = dst.is_ymm() || src1.is_ymm();
4246 encode_vex_rrr(buf, pp, escape, opcode, *dst, *src1, *src2, w, l);
4247 buf.push(*imm as u8);
4248 Ok(())
4249 }
4250 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)), Some(Immediate(imm)))
4252 if dst.is_vector() && src1.is_vector() =>
4253 {
4254 let l = dst.is_ymm() || src1.is_ymm();
4255 encode_vex_rrm(buf, pp, escape, opcode, *dst, *src1, mem, reloc, w, l);
4256 buf.push(*imm as u8);
4257 Ok(())
4258 }
4259 (Some(Register(dst)), Some(Register(src)), Some(Immediate(imm)), None)
4261 if dst.is_vector() && src.is_vector() =>
4262 {
4263 let l = dst.is_ymm() || src.is_ymm();
4264 let mandatory_pp = vex_pp(pp);
4265 emit_vex_prefix(
4266 buf,
4267 dst.is_extended(),
4268 false,
4269 src.is_extended(),
4270 w,
4271 0,
4272 l,
4273 mandatory_pp,
4274 escape,
4275 );
4276 buf.push(opcode);
4277 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
4278 buf.push(*imm as u8);
4279 Ok(())
4280 }
4281 (Some(Register(dst)), Some(Memory(mem)), Some(Immediate(imm)), None) if dst.is_vector() => {
4282 let l = dst.is_ymm();
4283 let mandatory_pp = vex_pp(pp);
4284 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4285 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4286 emit_vex_prefix(
4287 buf,
4288 dst.is_extended(),
4289 x_ext,
4290 b_ext,
4291 w,
4292 0,
4293 l,
4294 mandatory_pp,
4295 escape,
4296 );
4297 buf.push(opcode);
4298 emit_mem_modrm(buf, dst.base_code(), mem);
4299 buf.push(*imm as u8);
4300 Ok(())
4301 }
4302 _ => Err(invalid_operands(
4303 &instr.mnemonic,
4304 "expected VEX xmm/ymm operands with imm8",
4305 instr.span,
4306 )),
4307 }
4308}
4309
4310#[cfg(any(feature = "x86", feature = "x86_64"))]
4313pub(crate) fn encode_vex_bmi_vex_ndd(
4314 buf: &mut InstrBytes,
4315 ops: &OperandList,
4316 instr: &Instruction,
4317 pp: u8,
4318 escape: &[u8],
4319 opcode: u8,
4320 w_from_size: bool,
4321) -> Result<(), AsmError> {
4322 use Operand::*;
4323 match (ops.first(), ops.get(1), ops.get(2)) {
4324 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2))) => {
4326 let w = if w_from_size {
4327 dst.size_bits() == 64
4328 } else {
4329 false
4330 };
4331 let mandatory_pp = vex_pp(pp);
4332 emit_vex_prefix(
4333 buf,
4334 dst.is_extended(),
4335 false,
4336 src2.is_extended(),
4337 w,
4338 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4339 false,
4340 mandatory_pp,
4341 escape,
4342 );
4343 buf.push(opcode);
4344 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
4345 Ok(())
4346 }
4347 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem))) => {
4348 let w = if w_from_size {
4349 dst.size_bits() == 64
4350 } else {
4351 false
4352 };
4353 let mandatory_pp = vex_pp(pp);
4354 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4355 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4356 emit_vex_prefix(
4357 buf,
4358 dst.is_extended(),
4359 x_ext,
4360 b_ext,
4361 w,
4362 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4363 false,
4364 mandatory_pp,
4365 escape,
4366 );
4367 buf.push(opcode);
4368 emit_mem_modrm(buf, dst.base_code(), mem);
4369 Ok(())
4370 }
4371 (Some(Register(dst)), Some(Register(src)), None) => {
4373 let w = if w_from_size {
4374 dst.size_bits() == 64
4375 } else {
4376 false
4377 };
4378 let mandatory_pp = vex_pp(pp);
4379 emit_vex_prefix(
4380 buf,
4381 false, false,
4383 src.is_extended(),
4384 w,
4385 dst.base_code() | if dst.is_extended() { 8 } else { 0 },
4386 false,
4387 mandatory_pp,
4388 escape,
4389 );
4390 buf.push(opcode);
4391 buf.push(0xC0 | src.base_code());
4395 Ok(())
4396 }
4397 (Some(Register(dst)), Some(Memory(mem)), None) => {
4398 let w = if w_from_size {
4399 dst.size_bits() == 64
4400 } else {
4401 false
4402 };
4403 let mandatory_pp = vex_pp(pp);
4404 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4405 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4406 emit_vex_prefix(
4407 buf,
4408 false,
4409 x_ext,
4410 b_ext,
4411 w,
4412 dst.base_code() | if dst.is_extended() { 8 } else { 0 },
4413 false,
4414 mandatory_pp,
4415 escape,
4416 );
4417 buf.push(opcode);
4418 emit_mem_modrm(buf, 0, mem);
4419 Ok(())
4420 }
4421 _ => Err(invalid_operands(
4422 &instr.mnemonic,
4423 "expected GP register operands",
4424 instr.span,
4425 )),
4426 }
4427}
4428
4429#[cfg(any(feature = "x86", feature = "x86_64"))]
4431pub(crate) fn encode_vex_bmi_digit(
4432 buf: &mut InstrBytes,
4433 ops: &OperandList,
4434 instr: &Instruction,
4435 pp: u8,
4436 escape: &[u8],
4437 opcode: u8,
4438 digit: u8,
4439 w_from_size: bool,
4440) -> Result<(), AsmError> {
4441 use Operand::*;
4442 match (ops.first(), ops.get(1)) {
4443 (Some(Register(dst)), Some(Register(src))) => {
4444 let w = if w_from_size {
4445 dst.size_bits() == 64
4446 } else {
4447 false
4448 };
4449 let mandatory_pp = vex_pp(pp);
4450 emit_vex_prefix(
4451 buf,
4452 false, false,
4454 src.is_extended(),
4455 w,
4456 dst.base_code() | if dst.is_extended() { 8 } else { 0 },
4457 false,
4458 mandatory_pp,
4459 escape,
4460 );
4461 buf.push(opcode);
4462 buf.push(0xC0 | (digit << 3) | src.base_code());
4463 Ok(())
4464 }
4465 (Some(Register(dst)), Some(Memory(mem))) => {
4466 let w = if w_from_size {
4467 dst.size_bits() == 64
4468 } else {
4469 false
4470 };
4471 let mandatory_pp = vex_pp(pp);
4472 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4473 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4474 emit_vex_prefix(
4475 buf,
4476 false,
4477 x_ext,
4478 b_ext,
4479 w,
4480 dst.base_code() | if dst.is_extended() { 8 } else { 0 },
4481 false,
4482 mandatory_pp,
4483 escape,
4484 );
4485 buf.push(opcode);
4486 emit_mem_modrm(buf, digit, mem);
4487 Ok(())
4488 }
4489 _ => Err(invalid_operands(
4490 &instr.mnemonic,
4491 "expected r32/r64, r/m32/r/m64",
4492 instr.span,
4493 )),
4494 }
4495}
4496
4497#[cfg(any(feature = "x86", feature = "x86_64"))]
4499pub(crate) fn encode_vex_bmi_imm(
4500 buf: &mut InstrBytes,
4501 ops: &OperandList,
4502 instr: &Instruction,
4503 pp: u8,
4504 escape: &[u8],
4505 opcode: u8,
4506 w_from_size: bool,
4507) -> Result<(), AsmError> {
4508 use Operand::*;
4509 match (ops.first(), ops.get(1), ops.get(2)) {
4510 (Some(Register(dst)), Some(Register(src)), Some(Immediate(imm))) => {
4511 let w = if w_from_size {
4512 dst.size_bits() == 64
4513 } else {
4514 false
4515 };
4516 let mandatory_pp = vex_pp(pp);
4517 emit_vex_prefix(
4518 buf,
4519 dst.is_extended(),
4520 false,
4521 src.is_extended(),
4522 w,
4523 0,
4524 false,
4525 mandatory_pp,
4526 escape,
4527 );
4528 buf.push(opcode);
4529 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
4530 buf.push(*imm as u8);
4531 Ok(())
4532 }
4533 (Some(Register(dst)), Some(Memory(mem)), Some(Immediate(imm))) => {
4534 let w = if w_from_size {
4535 dst.size_bits() == 64
4536 } else {
4537 false
4538 };
4539 let mandatory_pp = vex_pp(pp);
4540 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4541 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4542 emit_vex_prefix(
4543 buf,
4544 dst.is_extended(),
4545 x_ext,
4546 b_ext,
4547 w,
4548 0,
4549 false,
4550 mandatory_pp,
4551 escape,
4552 );
4553 buf.push(opcode);
4554 emit_mem_modrm(buf, dst.base_code(), mem);
4555 buf.push(*imm as u8);
4556 Ok(())
4557 }
4558 _ => Err(invalid_operands(
4559 &instr.mnemonic,
4560 "expected r, r/m, imm8",
4561 instr.span,
4562 )),
4563 }
4564}
4565
4566#[cfg(any(feature = "x86", feature = "x86_64"))]
4570pub(crate) fn encode_vex_bmi_rmv(
4571 buf: &mut InstrBytes,
4572 ops: &OperandList,
4573 instr: &Instruction,
4574 pp: u8,
4575 escape: &[u8],
4576 opcode: u8,
4577 w_from_size: bool,
4578) -> Result<(), AsmError> {
4579 use Operand::*;
4580 match (ops.first(), ops.get(1), ops.get(2)) {
4581 (Some(Register(dst)), Some(Register(src)), Some(Register(ctrl))) => {
4583 let w = if w_from_size {
4584 dst.size_bits() == 64
4585 } else {
4586 false
4587 };
4588 let mandatory_pp = vex_pp(pp);
4589 emit_vex_prefix(
4590 buf,
4591 dst.is_extended(),
4592 false,
4593 src.is_extended(),
4594 w,
4595 ctrl.base_code() | if ctrl.is_extended() { 8 } else { 0 },
4596 false,
4597 mandatory_pp,
4598 escape,
4599 );
4600 buf.push(opcode);
4601 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
4602 Ok(())
4603 }
4604 (Some(Register(dst)), Some(Memory(mem)), Some(Register(ctrl))) => {
4606 let w = if w_from_size {
4607 dst.size_bits() == 64
4608 } else {
4609 false
4610 };
4611 let mandatory_pp = vex_pp(pp);
4612 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4613 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4614 emit_vex_prefix(
4615 buf,
4616 dst.is_extended(),
4617 x_ext,
4618 b_ext,
4619 w,
4620 ctrl.base_code() | if ctrl.is_extended() { 8 } else { 0 },
4621 false,
4622 mandatory_pp,
4623 escape,
4624 );
4625 buf.push(opcode);
4626 emit_mem_modrm(buf, dst.base_code(), mem);
4627 Ok(())
4628 }
4629 _ => Err(invalid_operands(
4630 &instr.mnemonic,
4631 "expected r, r/m, r",
4632 instr.span,
4633 )),
4634 }
4635}
4636
4637#[cfg(any(feature = "x86", feature = "x86_64"))]
4648pub(crate) fn encode_vex_shift(
4649 buf: &mut InstrBytes,
4650 ops: &OperandList,
4651 instr: &Instruction,
4652 pp: u8,
4653 escape: &[u8],
4654 reg_opcode: u8,
4655 imm_opcode: u8,
4656 digit: u8,
4657 reloc: &mut Option<Relocation>,
4658) -> Result<(), AsmError> {
4659 use Operand::*;
4660 match (ops.first(), ops.get(1), ops.get(2)) {
4661 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)))
4663 if dst.is_vector() && src1.is_vector() && src2.is_vector() =>
4664 {
4665 let l = dst.is_ymm() || src1.is_ymm();
4666 encode_vex_rrr(buf, pp, escape, reg_opcode, *dst, *src1, *src2, false, l);
4667 Ok(())
4668 }
4669 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)))
4671 if dst.is_vector() && src1.is_vector() =>
4672 {
4673 let l = dst.is_ymm() || src1.is_ymm();
4674 encode_vex_rrm(
4675 buf, pp, escape, reg_opcode, *dst, *src1, mem, reloc, false, l,
4676 );
4677 Ok(())
4678 }
4679 (Some(Register(dst)), Some(Register(src)), Some(Immediate(imm)))
4681 if dst.is_vector() && src.is_vector() =>
4682 {
4683 let l = dst.is_ymm() || src.is_ymm();
4684 let mandatory_pp = vex_pp(pp);
4685 emit_vex_prefix(
4687 buf,
4688 false, false,
4690 src.is_extended(),
4691 false, dst.base_code() | if dst.is_extended() { 8 } else { 0 },
4693 l,
4694 mandatory_pp,
4695 escape,
4696 );
4697 buf.push(imm_opcode);
4698 buf.push(0xC0 | (digit << 3) | src.base_code());
4699 buf.push(*imm as u8);
4700 Ok(())
4701 }
4702 _ => Err(invalid_operands(
4703 &instr.mnemonic,
4704 "expected VEX xmm/ymm shift operands",
4705 instr.span,
4706 )),
4707 }
4708}
4709
4710#[cfg(any(feature = "x86", feature = "x86_64"))]
4717pub(crate) fn encode_vex_cvt(
4718 buf: &mut InstrBytes,
4719 ops: &OperandList,
4720 instr: &Instruction,
4721 pp: u8,
4722 escape: &[u8],
4723 opcode: u8,
4724 _reloc: &mut Option<Relocation>,
4725) -> Result<(), AsmError> {
4726 use Operand::*;
4727 match (ops.first(), ops.get(1), ops.get(2)) {
4728 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)))
4730 if dst.is_xmm() && src1.is_xmm() =>
4731 {
4732 let w = src2.size_bits() == 64;
4733 let mandatory_pp = vex_pp(pp);
4734 emit_vex_prefix(
4735 buf,
4736 dst.is_extended(),
4737 false,
4738 src2.is_extended(),
4739 w,
4740 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4741 false,
4742 mandatory_pp,
4743 escape,
4744 );
4745 buf.push(opcode);
4746 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
4747 Ok(())
4748 }
4749 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)))
4750 if dst.is_xmm() && src1.is_xmm() =>
4751 {
4752 let w = mem.size.is_some_and(|s| s.bits() == 64);
4753 let mandatory_pp = vex_pp(pp);
4754 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4755 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4756 emit_vex_prefix(
4757 buf,
4758 dst.is_extended(),
4759 x_ext,
4760 b_ext,
4761 w,
4762 src1.base_code() | if src1.is_extended() { 8 } else { 0 },
4763 false,
4764 mandatory_pp,
4765 escape,
4766 );
4767 buf.push(opcode);
4768 emit_mem_modrm(buf, dst.base_code(), mem);
4769 Ok(())
4770 }
4771 (Some(Register(dst)), Some(Register(src)), None) if !dst.is_vector() && src.is_xmm() => {
4773 let w = dst.size_bits() == 64;
4774 let mandatory_pp = vex_pp(pp);
4775 emit_vex_prefix(
4776 buf,
4777 dst.is_extended(),
4778 false,
4779 src.is_extended(),
4780 w,
4781 0,
4782 false,
4783 mandatory_pp,
4784 escape,
4785 );
4786 buf.push(opcode);
4787 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
4788 Ok(())
4789 }
4790 (Some(Register(dst)), Some(Memory(mem)), None) if !dst.is_vector() => {
4792 let w = dst.size_bits() == 64;
4793 let mandatory_pp = vex_pp(pp);
4794 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4795 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4796 emit_vex_prefix(
4797 buf,
4798 dst.is_extended(),
4799 x_ext,
4800 b_ext,
4801 w,
4802 0,
4803 false,
4804 mandatory_pp,
4805 escape,
4806 );
4807 buf.push(opcode);
4808 emit_mem_modrm(buf, dst.base_code(), mem);
4809 Ok(())
4810 }
4811 _ => Err(invalid_operands(
4812 &instr.mnemonic,
4813 "expected conversion operands",
4814 instr.span,
4815 )),
4816 }
4817}
4818
4819#[cfg(any(feature = "x86", feature = "x86_64"))]
4846fn emit_evex(
4847 buf: &mut InstrBytes,
4848 r_ext: bool,
4849 x_ext: bool,
4850 b_ext: bool,
4851 r_prime: bool,
4852 mm: u8,
4853 w: bool,
4854 vvvv: u8,
4855 v_prime: bool,
4856 pp: u8,
4857 z: bool,
4858 ll: u8,
4859 b_bit: bool,
4860 aaa: u8,
4861) {
4862 let p0 = (if r_ext { 0 } else { 0x80 })
4864 | (if x_ext { 0 } else { 0x40 })
4865 | (if b_ext { 0 } else { 0x20 })
4866 | (if r_prime { 0 } else { 0x10 })
4867 | (mm & 0x03);
4868
4869 let p1 = (if w { 0x80 } else { 0 })
4871 | (((!vvvv) & 0x0F) << 3)
4872 | 0x04 | (pp & 0x03);
4874
4875 let p2 = (if z { 0x80 } else { 0 })
4877 | ((ll & 0x03) << 5)
4878 | (if b_bit { 0x10 } else { 0 })
4879 | (if v_prime { 0 } else { 0x08 })
4880 | (aaa & 0x07);
4881
4882 buf.push(0x62);
4883 buf.push(p0);
4884 buf.push(p1);
4885 buf.push(p2);
4886}
4887
4888#[cfg(any(feature = "x86", feature = "x86_64"))]
4891fn evex_reg_bits(reg: Register) -> (u8, bool, bool) {
4892 (reg.base_code(), reg.is_extended(), reg.is_evex_extended())
4893}
4894
4895#[cfg(any(feature = "x86", feature = "x86_64"))]
4898fn evex_ll(reg: Register) -> u8 {
4899 if reg.is_zmm() {
4900 2
4901 } else if reg.is_ymm() {
4902 1
4903 } else {
4904 0
4905 }
4906}
4907
4908#[cfg(any(feature = "x86", feature = "x86_64"))]
4913fn emit_evex_prefix_rrr(
4914 buf: &mut InstrBytes,
4915 dst: Register,
4916 src1: Register,
4917 src2: Register,
4918 mm: u8,
4919 w: bool,
4920 pp: u8,
4921 ll: u8,
4922 aaa: u8,
4923 z: bool,
4924) {
4925 let (_, dst_ext, dst_evex) = evex_reg_bits(dst);
4926 let (src1_code, src1_ext, src1_evex) = evex_reg_bits(src1);
4927 let (_, src2_ext, src2_evex) = evex_reg_bits(src2);
4928
4929 let vvvv = src1_code | if src1_ext { 8 } else { 0 };
4930
4931 emit_evex(
4932 buf, dst_ext, src2_evex, src2_ext, dst_evex, mm, w, vvvv, src1_evex, pp, z, ll, false, aaa,
4939 );
4940}
4941
4942#[cfg(any(feature = "x86", feature = "x86_64"))]
4945fn emit_evex_prefix_rrm(
4946 buf: &mut InstrBytes,
4947 dst: Register,
4948 src1: Register,
4949 mem: &MemoryOperand,
4950 mm: u8,
4951 w: bool,
4952 pp: u8,
4953 ll: u8,
4954 b_bit: bool,
4955 aaa: u8,
4956 z: bool,
4957) {
4958 let (_, dst_ext, dst_evex) = evex_reg_bits(dst);
4959 let (src1_code, src1_ext, src1_evex) = evex_reg_bits(src1);
4960
4961 let vvvv = src1_code | if src1_ext { 8 } else { 0 };
4962 let x_ext = mem.index.is_some_and(|r| r.is_extended());
4963 let b_ext = mem.base.is_some_and(|r| r.is_extended());
4964
4965 emit_evex(
4966 buf, dst_ext, x_ext, b_ext, dst_evex, mm, w, vvvv, src1_evex, pp, z, ll, b_bit, aaa,
4967 );
4968}
4969
4970#[cfg(any(feature = "x86", feature = "x86_64"))]
4981fn evex_aaa(instr: &Instruction) -> u8 {
4982 instr.opmask.map_or(0, |reg| reg.base_code())
4983}
4984
4985#[cfg(any(feature = "x86", feature = "x86_64"))]
4986fn evex_broadcast_bit(instr: &Instruction) -> bool {
4987 instr.broadcast.is_some()
4988}
4989
4990#[cfg(any(feature = "x86", feature = "x86_64"))]
4991pub(crate) fn encode_evex_op(
4992 buf: &mut InstrBytes,
4993 ops: &OperandList,
4994 instr: &Instruction,
4995 pp: u8,
4996 mm: u8,
4997 load_opcode: u8,
4998 store_opcode: Option<u8>,
4999 w: bool,
5000 reloc: &mut Option<Relocation>,
5001) -> Result<(), AsmError> {
5002 use Operand::*;
5003 let mandatory_pp = vex_pp(pp);
5004 let o = (ops.first(), ops.get(1), ops.get(2));
5005 match o {
5006 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)))
5008 if dst.is_vector() && src1.is_vector() && src2.is_vector() =>
5009 {
5010 let ll = evex_ll(*dst);
5011 let aaa = evex_aaa(instr);
5012 emit_evex_prefix_rrr(
5013 buf,
5014 *dst,
5015 *src1,
5016 *src2,
5017 mm,
5018 w,
5019 mandatory_pp,
5020 ll,
5021 aaa,
5022 instr.zeroing,
5023 );
5024 buf.push(load_opcode);
5025 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
5026 Ok(())
5027 }
5028 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)))
5030 if dst.is_vector() && src1.is_vector() =>
5031 {
5032 let ll = evex_ll(*dst);
5033 let aaa = evex_aaa(instr);
5034 let b_bit = evex_broadcast_bit(instr);
5035 emit_evex_prefix_rrm(
5036 buf,
5037 *dst,
5038 *src1,
5039 mem,
5040 mm,
5041 w,
5042 mandatory_pp,
5043 ll,
5044 b_bit,
5045 aaa,
5046 instr.zeroing,
5047 );
5048 buf.push(load_opcode);
5049 emit_mem_modrm(buf, dst.base_code(), mem);
5050 if let Some(ref mut rel) = reloc {
5051 rel.offset = buf.len() - 4;
5052 }
5053 Ok(())
5054 }
5055 (Some(Register(dst)), Some(Register(src)), None) if dst.is_vector() && src.is_vector() => {
5057 let ll = evex_ll(*dst);
5058 let aaa = evex_aaa(instr);
5059 let (_, src_ext, src_evex) = evex_reg_bits(*src);
5061 let (_, dst_ext, dst_evex) = evex_reg_bits(*dst);
5062 emit_evex(
5063 buf,
5064 dst_ext,
5065 src_evex,
5066 src_ext,
5067 dst_evex,
5068 mm,
5069 w,
5070 0,
5071 false,
5072 mandatory_pp,
5073 instr.zeroing,
5074 ll,
5075 false,
5076 aaa,
5077 );
5078 buf.push(load_opcode);
5079 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
5080 Ok(())
5081 }
5082 (Some(Register(dst)), Some(Memory(mem)), None) if dst.is_vector() => {
5084 let ll = evex_ll(*dst);
5085 let aaa = evex_aaa(instr);
5086 let b_bit = evex_broadcast_bit(instr);
5087 let (_, dst_ext, dst_evex) = evex_reg_bits(*dst);
5088 let x_ext = mem.index.is_some_and(|r| r.is_extended());
5089 let b_ext = mem.base.is_some_and(|r| r.is_extended());
5090 emit_evex(
5091 buf,
5092 dst_ext,
5093 x_ext,
5094 b_ext,
5095 dst_evex,
5096 mm,
5097 w,
5098 0,
5099 false,
5100 mandatory_pp,
5101 instr.zeroing,
5102 ll,
5103 b_bit,
5104 aaa,
5105 );
5106 buf.push(load_opcode);
5107 emit_mem_modrm(buf, dst.base_code(), mem);
5108 if let Some(ref mut rel) = reloc {
5109 rel.offset = buf.len() - 4;
5110 }
5111 Ok(())
5112 }
5113 (Some(Memory(mem)), Some(Register(src)), None)
5115 if src.is_vector() && store_opcode.is_some() =>
5116 {
5117 let ll = evex_ll(*src);
5118 let aaa = evex_aaa(instr);
5119 let (_, src_ext, src_evex) = evex_reg_bits(*src);
5120 let x_ext = mem.index.is_some_and(|r| r.is_extended());
5121 let b_ext = mem.base.is_some_and(|r| r.is_extended());
5122 emit_evex(
5123 buf,
5124 src_ext,
5125 x_ext,
5126 b_ext,
5127 src_evex,
5128 mm,
5129 w,
5130 0,
5131 false,
5132 mandatory_pp,
5133 instr.zeroing,
5134 ll,
5135 false,
5136 aaa,
5137 );
5138 buf.push(store_opcode.unwrap_or(0));
5140 emit_mem_modrm(buf, src.base_code(), mem);
5141 if let Some(ref mut rel) = reloc {
5142 rel.offset = buf.len() - 4;
5143 }
5144 Ok(())
5145 }
5146 _ => Err(invalid_operands(
5147 &instr.mnemonic,
5148 "expected EVEX zmm/ymm/xmm operands",
5149 instr.span,
5150 )),
5151 }
5152}
5153
5154#[cfg(any(feature = "x86", feature = "x86_64"))]
5156pub(crate) fn encode_evex_imm(
5157 buf: &mut InstrBytes,
5158 ops: &OperandList,
5159 instr: &Instruction,
5160 pp: u8,
5161 mm: u8,
5162 opcode: u8,
5163 w: bool,
5164 reloc: &mut Option<Relocation>,
5165) -> Result<(), AsmError> {
5166 use Operand::*;
5167 let mandatory_pp = vex_pp(pp);
5168 match (ops.first(), ops.get(1), ops.get(2), ops.get(3)) {
5169 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)), Some(Immediate(imm)))
5171 if dst.is_vector() && src1.is_vector() && src2.is_vector() =>
5172 {
5173 let ll = evex_ll(*dst);
5174 let aaa = evex_aaa(instr);
5175 emit_evex_prefix_rrr(
5176 buf,
5177 *dst,
5178 *src1,
5179 *src2,
5180 mm,
5181 w,
5182 mandatory_pp,
5183 ll,
5184 aaa,
5185 instr.zeroing,
5186 );
5187 buf.push(opcode);
5188 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
5189 buf.push(*imm as u8);
5190 Ok(())
5191 }
5192 (Some(Register(dst)), Some(Register(src1)), Some(Memory(mem)), Some(Immediate(imm)))
5194 if dst.is_vector() && src1.is_vector() =>
5195 {
5196 let ll = evex_ll(*dst);
5197 let aaa = evex_aaa(instr);
5198 let b_bit = evex_broadcast_bit(instr);
5199 emit_evex_prefix_rrm(
5200 buf,
5201 *dst,
5202 *src1,
5203 mem,
5204 mm,
5205 w,
5206 mandatory_pp,
5207 ll,
5208 b_bit,
5209 aaa,
5210 instr.zeroing,
5211 );
5212 buf.push(opcode);
5213 emit_mem_modrm(buf, dst.base_code(), mem);
5214 if let Some(ref mut rel) = reloc {
5215 rel.offset = buf.len() - 4;
5216 }
5217 buf.push(*imm as u8);
5218 Ok(())
5219 }
5220 (Some(Register(dst)), Some(Register(src)), Some(Immediate(imm)), None)
5222 if dst.is_vector() && src.is_vector() =>
5223 {
5224 let ll = evex_ll(*dst);
5225 let aaa = evex_aaa(instr);
5226 let (_, src_ext, src_evex) = evex_reg_bits(*src);
5227 let (_, dst_ext, dst_evex) = evex_reg_bits(*dst);
5228 emit_evex(
5229 buf,
5230 dst_ext,
5231 src_evex,
5232 src_ext,
5233 dst_evex,
5234 mm,
5235 w,
5236 0,
5237 false,
5238 mandatory_pp,
5239 instr.zeroing,
5240 ll,
5241 false,
5242 aaa,
5243 );
5244 buf.push(opcode);
5245 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
5246 buf.push(*imm as u8);
5247 Ok(())
5248 }
5249 _ => Err(invalid_operands(
5250 &instr.mnemonic,
5251 "expected EVEX operands with immediate",
5252 instr.span,
5253 )),
5254 }
5255}
5256
5257#[cfg(any(feature = "x86", feature = "x86_64"))]
5261#[allow(dead_code)]
5262pub(crate) fn encode_evex_opmask(
5263 buf: &mut InstrBytes,
5264 ops: &OperandList,
5265 instr: &Instruction,
5266 pp: u8,
5267 _mm: u8,
5268 opcode: u8,
5269 w: bool,
5270) -> Result<(), AsmError> {
5271 use Operand::*;
5272 let mandatory_pp = vex_pp(pp);
5273 match (ops.first(), ops.get(1), ops.get(2)) {
5274 (Some(Register(dst)), Some(Register(src1)), Some(Register(src2)))
5276 if dst.is_opmask() && src1.is_opmask() && src2.is_opmask() =>
5277 {
5278 let src1_vvvv = src1.base_code();
5281 emit_vex_prefix(
5282 buf,
5283 false,
5284 false,
5285 false,
5286 w,
5287 src1_vvvv,
5288 true,
5289 mandatory_pp,
5290 &[0x0F],
5291 );
5292 buf.push(opcode);
5293 buf.push(0xC0 | (dst.base_code() << 3) | src2.base_code());
5294 Ok(())
5295 }
5296 (Some(Register(dst)), Some(Register(src)), None) if dst.is_opmask() && src.is_opmask() => {
5298 emit_vex_prefix(buf, false, false, false, w, 0, true, mandatory_pp, &[0x0F]);
5299 buf.push(opcode);
5300 buf.push(0xC0 | (dst.base_code() << 3) | src.base_code());
5301 Ok(())
5302 }
5303 _ => Err(invalid_operands(
5304 &instr.mnemonic,
5305 "expected opmask register operands (k0-k7)",
5306 instr.span,
5307 )),
5308 }
5309}
5310
5311#[cfg(test)]
5312mod tests {
5313 use super::*;
5314 use crate::error::Span;
5315
5316 fn span() -> Span {
5317 Span::new(1, 1, 0, 0)
5318 }
5319
5320 fn make_instr(mnemonic: &str, operands: Vec<Operand>) -> Instruction {
5321 Instruction {
5322 mnemonic: Mnemonic::from(mnemonic),
5323 operands: OperandList::from(operands),
5324 size_hint: None,
5325 prefixes: PrefixList::new(),
5326 opmask: None,
5327 zeroing: false,
5328 broadcast: None,
5329 span: span(),
5330 }
5331 }
5332
5333 fn make_instr_with_hint(
5334 mnemonic: &str,
5335 operands: Vec<Operand>,
5336 hint: Option<OperandSize>,
5337 ) -> Instruction {
5338 Instruction {
5339 mnemonic: Mnemonic::from(mnemonic),
5340 operands: OperandList::from(operands),
5341 size_hint: hint,
5342 prefixes: PrefixList::new(),
5343 opmask: None,
5344 zeroing: false,
5345 broadcast: None,
5346 span: span(),
5347 }
5348 }
5349
5350 fn encode(mnemonic: &str, operands: Vec<Operand>) -> Vec<u8> {
5351 let instr = make_instr(mnemonic, operands);
5352 encode_instruction(&instr, Arch::X86_64)
5353 .unwrap()
5354 .bytes
5355 .to_vec()
5356 }
5357
5358 fn encode_with_hint(mnemonic: &str, operands: Vec<Operand>, hint: OperandSize) -> Vec<u8> {
5359 let mut instr = make_instr(mnemonic, operands);
5360 instr.size_hint = Some(hint);
5361 encode_instruction(&instr, Arch::X86_64)
5362 .unwrap()
5363 .bytes
5364 .to_vec()
5365 }
5366
5367 fn encode_with_prefix(mnemonic: &str, operands: Vec<Operand>, prefix: Prefix) -> Vec<u8> {
5368 let mut instr = make_instr(mnemonic, operands);
5369 instr.prefixes = PrefixList::from(alloc::vec![prefix]);
5370 encode_instruction(&instr, Arch::X86_64)
5371 .unwrap()
5372 .bytes
5373 .to_vec()
5374 }
5375
5376 use crate::ir::Register::*;
5377 use Operand::*;
5378
5379 #[test]
5382 fn test_nop() {
5383 assert_eq!(encode("nop", vec![]), vec![0x90]);
5384 }
5385
5386 #[test]
5387 fn test_ret() {
5388 assert_eq!(encode("ret", vec![]), vec![0xC3]);
5389 }
5390
5391 #[test]
5392 fn test_syscall() {
5393 assert_eq!(encode("syscall", vec![]), vec![0x0F, 0x05]);
5394 }
5395
5396 #[test]
5397 fn test_int3() {
5398 assert_eq!(encode("int3", vec![]), vec![0xCC]);
5399 }
5400
5401 #[test]
5402 fn test_int_0x80() {
5403 assert_eq!(encode("int", vec![Immediate(0x80)]), vec![0xCD, 0x80]);
5404 }
5405
5406 #[test]
5407 fn test_hlt() {
5408 assert_eq!(encode("hlt", vec![]), vec![0xF4]);
5409 }
5410
5411 #[test]
5414 fn test_mov_rax_rbx() {
5415 let bytes = encode("mov", vec![Register(Rax), Register(Rbx)]);
5417 assert_eq!(bytes, vec![0x48, 0x89, 0xD8]);
5418 }
5419
5420 #[test]
5421 fn test_mov_eax_ecx() {
5422 let bytes = encode("mov", vec![Register(Eax), Register(Ecx)]);
5424 assert_eq!(bytes, vec![0x89, 0xC8]);
5425 }
5426
5427 #[test]
5428 fn test_mov_r8_r9() {
5429 let bytes = encode("mov", vec![Register(R8), Register(R9)]);
5431 assert_eq!(bytes, vec![0x4D, 0x89, 0xC8]);
5432 }
5433
5434 #[test]
5435 fn test_mov_al_bl() {
5436 let bytes = encode("mov", vec![Register(Al), Register(Bl)]);
5437 assert_eq!(bytes, vec![0x88, 0xD8]);
5438 }
5439
5440 #[test]
5443 fn test_mov_eax_1() {
5444 let bytes = encode("mov", vec![Register(Eax), Immediate(1)]);
5445 assert_eq!(bytes, vec![0xB8, 0x01, 0x00, 0x00, 0x00]);
5446 }
5447
5448 #[test]
5449 fn test_mov_al_0xff() {
5450 let bytes = encode("mov", vec![Register(Al), Immediate(0xFF)]);
5451 assert_eq!(bytes, vec![0xB0, 0xFF]);
5452 }
5453
5454 #[test]
5455 fn test_mov_rax_small_imm() {
5456 let bytes = encode("mov", vec![Register(Rax), Immediate(1)]);
5458 assert_eq!(bytes, vec![0xB8, 0x01, 0x00, 0x00, 0x00]);
5459 }
5460
5461 #[test]
5462 fn test_mov_rax_neg1() {
5463 let bytes = encode("mov", vec![Register(Rax), Immediate(-1)]);
5465 assert_eq!(bytes, vec![0x48, 0xC7, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF]);
5466 }
5467
5468 #[test]
5469 fn test_mov_rax_large_imm() {
5470 let bytes = encode("mov", vec![Register(Rax), Immediate(0x0102030405060708)]);
5472 assert_eq!(
5473 bytes,
5474 vec![0x48, 0xB8, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
5475 );
5476 }
5477
5478 #[test]
5479 fn test_mov_r8d_imm() {
5480 let bytes = encode("mov", vec![Register(R8d), Immediate(42)]);
5481 assert_eq!(bytes, vec![0x41, 0xB8, 0x2A, 0x00, 0x00, 0x00]);
5482 }
5483
5484 #[test]
5487 fn test_mov_rax_mem_rbx() {
5488 let mem = MemoryOperand {
5490 base: Some(Rbx),
5491 ..Default::default()
5492 };
5493 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
5494 assert_eq!(bytes, vec![0x48, 0x8B, 0x03]);
5495 }
5496
5497 #[test]
5498 fn test_mov_mem_rbx_rax() {
5499 let mem = MemoryOperand {
5501 base: Some(Rbx),
5502 ..Default::default()
5503 };
5504 let bytes = encode("mov", vec![Memory(Box::new(mem)), Register(Rax)]);
5505 assert_eq!(bytes, vec![0x48, 0x89, 0x03]);
5506 }
5507
5508 #[test]
5509 fn test_mov_rax_mem_rbp_disp8() {
5510 let mem = MemoryOperand {
5512 base: Some(Rbp),
5513 disp: 8,
5514 ..Default::default()
5515 };
5516 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
5517 assert_eq!(bytes, vec![0x48, 0x8B, 0x45, 0x08]);
5518 }
5519
5520 #[test]
5521 fn test_mov_rax_mem_rbp_disp32() {
5522 let mem = MemoryOperand {
5524 base: Some(Rbp),
5525 disp: 0x200,
5526 ..Default::default()
5527 };
5528 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
5529 assert_eq!(bytes, vec![0x48, 0x8B, 0x85, 0x00, 0x02, 0x00, 0x00]);
5530 }
5531
5532 #[test]
5535 fn test_push_rbp() {
5536 assert_eq!(encode("push", vec![Register(Rbp)]), vec![0x55]);
5537 }
5538
5539 #[test]
5540 fn test_push_r12() {
5541 assert_eq!(encode("push", vec![Register(R12)]), vec![0x41, 0x54]);
5542 }
5543
5544 #[test]
5545 fn test_pop_rbp() {
5546 assert_eq!(encode("pop", vec![Register(Rbp)]), vec![0x5D]);
5547 }
5548
5549 #[test]
5550 fn test_push_imm8() {
5551 assert_eq!(encode("push", vec![Immediate(1)]), vec![0x6A, 0x01]);
5552 }
5553
5554 #[test]
5555 fn test_push_imm32() {
5556 assert_eq!(
5557 encode("push", vec![Immediate(0x1000)]),
5558 vec![0x68, 0x00, 0x10, 0x00, 0x00]
5559 );
5560 }
5561
5562 #[test]
5565 fn test_add_rax_rbx() {
5566 let bytes = encode("add", vec![Register(Rax), Register(Rbx)]);
5567 assert_eq!(bytes, vec![0x48, 0x01, 0xD8]); }
5569
5570 #[test]
5571 fn test_add_eax_1() {
5572 let bytes = encode("add", vec![Register(Eax), Immediate(1)]);
5574 assert_eq!(bytes, vec![0x83, 0xC0, 0x01]);
5575 }
5576
5577 #[test]
5578 fn test_sub_rsp_8() {
5579 let bytes = encode("sub", vec![Register(Rsp), Immediate(8)]);
5581 assert_eq!(bytes, vec![0x48, 0x83, 0xEC, 0x08]);
5582 }
5583
5584 #[test]
5585 fn test_xor_eax_eax() {
5586 let bytes = encode("xor", vec![Register(Eax), Register(Eax)]);
5587 assert_eq!(bytes, vec![0x31, 0xC0]);
5588 }
5589
5590 #[test]
5591 fn test_cmp_rax_0() {
5592 let bytes = encode("cmp", vec![Register(Rax), Immediate(0)]);
5593 assert_eq!(bytes, vec![0x48, 0x83, 0xF8, 0x00]);
5594 }
5595
5596 #[test]
5597 fn test_and_al_imm() {
5598 let bytes = encode("and", vec![Register(Al), Immediate(0x0F)]);
5600 assert_eq!(bytes, vec![0x24, 0x0F]);
5601 }
5602
5603 #[test]
5604 fn test_or_eax_large_imm() {
5605 let bytes = encode("or", vec![Register(Eax), Immediate(0x1000)]);
5607 assert_eq!(bytes, vec![0x0D, 0x00, 0x10, 0x00, 0x00]);
5608 }
5609
5610 #[test]
5613 fn test_test_al_imm() {
5614 let bytes = encode("test", vec![Register(Al), Immediate(1)]);
5615 assert_eq!(bytes, vec![0xA8, 0x01]);
5616 }
5617
5618 #[test]
5619 fn test_test_eax_eax() {
5620 let bytes = encode("test", vec![Register(Eax), Register(Eax)]);
5621 assert_eq!(bytes, vec![0x85, 0xC0]);
5622 }
5623
5624 #[test]
5627 fn test_shl_eax_1() {
5628 let bytes = encode("shl", vec![Register(Eax), Immediate(1)]);
5629 assert_eq!(bytes, vec![0xD1, 0xE0]);
5630 }
5631
5632 #[test]
5633 fn test_shr_rcx_4() {
5634 let bytes = encode("shr", vec![Register(Rcx), Immediate(4)]);
5635 assert_eq!(bytes, vec![0x48, 0xC1, 0xE9, 0x04]);
5636 }
5637
5638 #[test]
5639 fn test_sar_rax_cl() {
5640 let bytes = encode("sar", vec![Register(Rax), Register(Cl)]);
5641 assert_eq!(bytes, vec![0x48, 0xD3, 0xF8]);
5642 }
5643
5644 #[test]
5647 fn test_inc_rax() {
5648 let bytes = encode("inc", vec![Register(Rax)]);
5649 assert_eq!(bytes, vec![0x48, 0xFF, 0xC0]);
5650 }
5651
5652 #[test]
5653 fn test_dec_ecx() {
5654 let bytes = encode("dec", vec![Register(Ecx)]);
5655 assert_eq!(bytes, vec![0xFF, 0xC9]);
5656 }
5657
5658 #[test]
5661 fn test_neg_rax() {
5662 let bytes = encode("neg", vec![Register(Rax)]);
5663 assert_eq!(bytes, vec![0x48, 0xF7, 0xD8]);
5664 }
5665
5666 #[test]
5667 fn test_not_eax() {
5668 let bytes = encode("not", vec![Register(Eax)]);
5669 assert_eq!(bytes, vec![0xF7, 0xD0]);
5670 }
5671
5672 #[test]
5675 fn test_jmp_label_relocation() {
5676 let instr = make_instr("jmp", vec![Label(String::from("target"))]);
5677 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
5678 assert_eq!(result.bytes, vec![0xE9, 0x00, 0x00, 0x00, 0x00]);
5679 assert!(result.relocation.is_some());
5680 let r = result.relocation.unwrap();
5681 assert_eq!(&*r.label, "target");
5682 assert_eq!(r.kind, RelocKind::X86Relative);
5683 assert_eq!(r.size, 4);
5684 }
5685
5686 #[test]
5687 fn test_jmp_reg() {
5688 let bytes = encode("jmp", vec![Register(Rax)]);
5689 assert_eq!(bytes, vec![0xFF, 0xE0]);
5690 }
5691
5692 #[test]
5693 fn test_call_reg() {
5694 let bytes = encode("call", vec![Register(Rax)]);
5695 assert_eq!(bytes, vec![0xFF, 0xD0]);
5696 }
5697
5698 #[test]
5699 fn test_call_r12() {
5700 let bytes = encode("call", vec![Register(R12)]);
5701 assert_eq!(bytes, vec![0x41, 0xFF, 0xD4]);
5702 }
5703
5704 #[test]
5707 fn test_je_label() {
5708 let instr = make_instr("je", vec![Label(String::from("target"))]);
5709 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
5710 assert_eq!(result.bytes[0..2], [0x0F, 0x84]);
5711 assert!(result.relocation.is_some());
5712 }
5713
5714 #[test]
5715 fn test_jne_label() {
5716 let instr = make_instr("jne", vec![Label(String::from("target"))]);
5717 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
5718 assert_eq!(result.bytes[0..2], [0x0F, 0x85]);
5719 }
5720
5721 #[test]
5724 fn test_sete_al() {
5725 let bytes = encode("sete", vec![Register(Al)]);
5726 assert_eq!(bytes, vec![0x0F, 0x94, 0xC0]);
5727 }
5728
5729 #[test]
5732 fn test_cmove_rax_rbx() {
5733 let bytes = encode("cmove", vec![Register(Rax), Register(Rbx)]);
5734 assert_eq!(bytes, vec![0x48, 0x0F, 0x44, 0xC3]);
5735 }
5736
5737 #[test]
5740 fn test_movzx_eax_al() {
5741 let bytes = encode("movzx", vec![Register(Eax), Register(Al)]);
5742 assert_eq!(bytes, vec![0x0F, 0xB6, 0xC0]);
5743 }
5744
5745 #[test]
5746 fn test_movsx_rax_eax() {
5747 let bytes = encode("movsx", vec![Register(Rax), Register(Eax)]);
5748 assert_eq!(bytes, vec![0x48, 0x63, 0xC0]);
5749 }
5750
5751 #[test]
5754 fn test_lea_rax_rbx_rcx_8() {
5755 let mem = MemoryOperand {
5756 base: Some(Rbx),
5757 index: Some(Rcx),
5758 scale: 8,
5759 disp: 0,
5760 ..Default::default()
5761 };
5762 let bytes = encode("lea", vec![Register(Rax), Memory(Box::new(mem))]);
5763 assert_eq!(bytes, vec![0x48, 0x8D, 0x04, 0xCB]);
5764 }
5765
5766 #[test]
5769 fn test_lock_prefix() {
5770 let mem = MemoryOperand {
5771 base: Some(Rax),
5772 ..Default::default()
5773 };
5774 let bytes = encode_with_prefix(
5775 "add",
5776 vec![Memory(Box::new(mem)), Immediate(1)],
5777 Prefix::Lock,
5778 );
5779 assert_eq!(bytes[0], 0xF0); }
5781
5782 #[test]
5785 fn test_imul_r_r() {
5786 let bytes = encode("imul", vec![Register(Rax), Register(Rbx)]);
5787 assert_eq!(bytes, vec![0x48, 0x0F, 0xAF, 0xC3]);
5788 }
5789
5790 #[test]
5791 fn test_imul_r_r_imm8() {
5792 let bytes = encode("imul", vec![Register(Rax), Register(Rbx), Immediate(10)]);
5793 assert_eq!(bytes, vec![0x48, 0x6B, 0xC3, 0x0A]);
5794 }
5795
5796 #[test]
5799 fn test_bswap_eax() {
5800 let bytes = encode("bswap", vec![Register(Eax)]);
5801 assert_eq!(bytes, vec![0x0F, 0xC8]);
5802 }
5803
5804 #[test]
5805 fn test_bswap_rax() {
5806 let bytes = encode("bswap", vec![Register(Rax)]);
5807 assert_eq!(bytes, vec![0x48, 0x0F, 0xC8]);
5808 }
5809
5810 #[test]
5813 fn test_rep_movsb() {
5814 let mut instr = make_instr("movsb", vec![]);
5815 instr.prefixes = PrefixList::from(alloc::vec![Prefix::Rep]);
5816 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
5817 assert_eq!(result.bytes, vec![0xF3, 0xA4]);
5818 }
5819
5820 #[test]
5823 fn test_nop3_encoding() {
5824 let instr = make_instr("nop3", vec![]);
5825 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
5826 assert_eq!(result.bytes, vec![0x0F, 0x1F, 0x00]);
5827 }
5828
5829 #[test]
5832 fn test_mov_rax_mem_rsp() {
5833 let mem = MemoryOperand {
5835 base: Some(Rsp),
5836 ..Default::default()
5837 };
5838 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
5839 assert_eq!(bytes, vec![0x48, 0x8B, 0x04, 0x24]);
5841 }
5842
5843 #[test]
5846 fn test_cdq() {
5847 assert_eq!(encode("cdq", vec![]), vec![0x99]);
5848 }
5849
5850 #[test]
5851 fn test_cqo() {
5852 assert_eq!(encode("cqo", vec![]), vec![0x48, 0x99]);
5853 }
5854
5855 #[test]
5858 fn test_mov_ax_bx() {
5859 let bytes = encode("mov", vec![Register(Ax), Register(Bx)]);
5860 assert_eq!(bytes, vec![0x66, 0x89, 0xD8]);
5861 }
5862
5863 #[test]
5864 fn test_add_ax_imm() {
5865 let bytes = encode("add", vec![Register(Ax), Immediate(1)]);
5866 assert_eq!(bytes, vec![0x66, 0x83, 0xC0, 0x01]);
5867 }
5868
5869 #[test]
5872 fn test_arch_x86_nop() {
5873 let instr = make_instr("nop", vec![]);
5874 let result = encode_instruction(&instr, Arch::X86);
5875 assert!(result.is_ok());
5876 assert_eq!(result.unwrap().bytes, vec![0x90]);
5877 }
5878
5879 #[test]
5882 fn test_x86_32_inc_eax() {
5883 let instr = make_instr("inc", vec![Register(Eax)]);
5885 let result = encode_instruction(&instr, Arch::X86).unwrap();
5886 assert_eq!(result.bytes, vec![0x40]);
5887 }
5888
5889 #[test]
5890 fn test_x86_32_inc_ebx() {
5891 let instr = make_instr("inc", vec![Register(Ebx)]);
5893 let result = encode_instruction(&instr, Arch::X86).unwrap();
5894 assert_eq!(result.bytes, vec![0x43]);
5895 }
5896
5897 #[test]
5898 fn test_x86_32_inc_edi() {
5899 let instr = make_instr("inc", vec![Register(Edi)]);
5901 let result = encode_instruction(&instr, Arch::X86).unwrap();
5902 assert_eq!(result.bytes, vec![0x47]);
5903 }
5904
5905 #[test]
5906 fn test_x86_32_dec_eax() {
5907 let instr = make_instr("dec", vec![Register(Eax)]);
5909 let result = encode_instruction(&instr, Arch::X86).unwrap();
5910 assert_eq!(result.bytes, vec![0x48]);
5911 }
5912
5913 #[test]
5914 fn test_x86_32_dec_esp() {
5915 let instr = make_instr("dec", vec![Register(Esp)]);
5917 let result = encode_instruction(&instr, Arch::X86).unwrap();
5918 assert_eq!(result.bytes, vec![0x4C]);
5919 }
5920
5921 #[test]
5922 fn test_x86_32_inc_ax() {
5923 let instr = make_instr("inc", vec![Register(Ax)]);
5925 let result = encode_instruction(&instr, Arch::X86).unwrap();
5926 assert_eq!(result.bytes, vec![0x66, 0x40]);
5927 }
5928
5929 #[test]
5930 fn test_x86_32_dec_cx() {
5931 let instr = make_instr("dec", vec![Register(Cx)]);
5933 let result = encode_instruction(&instr, Arch::X86).unwrap();
5934 assert_eq!(result.bytes, vec![0x66, 0x49]);
5935 }
5936
5937 #[test]
5938 fn test_x86_32_inc_al_uses_modrm() {
5939 let instr = make_instr("inc", vec![Register(Al)]);
5941 let result = encode_instruction(&instr, Arch::X86).unwrap();
5942 assert_eq!(result.bytes, vec![0xFE, 0xC0]);
5943 }
5944
5945 #[test]
5948 fn test_push_ax() {
5949 let bytes = encode("push", vec![Register(Ax)]);
5951 assert_eq!(bytes, vec![0x66, 0x50]);
5952 }
5953
5954 #[test]
5955 fn test_pop_ax() {
5956 let bytes = encode("pop", vec![Register(Ax)]);
5958 assert_eq!(bytes, vec![0x66, 0x58]);
5959 }
5960
5961 #[test]
5962 fn test_push_bx() {
5963 let bytes = encode("push", vec![Register(Bx)]);
5964 assert_eq!(bytes, vec![0x66, 0x53]);
5965 }
5966
5967 #[test]
5968 fn test_pop_bx() {
5969 let bytes = encode("pop", vec![Register(Bx)]);
5970 assert_eq!(bytes, vec![0x66, 0x5B]);
5971 }
5972
5973 #[test]
5976 fn test_xchg_ax_bx_shortcut() {
5977 let bytes = encode("xchg", vec![Register(Ax), Register(Bx)]);
5979 assert_eq!(bytes, vec![0x66, 0x93]);
5980 }
5981
5982 #[test]
5985 fn test_movsx_eax_byte_mem() {
5986 let mem = MemoryOperand {
5988 base: Some(Rbx),
5989 ..Default::default()
5990 };
5991 let bytes = encode_with_hint(
5992 "movsx",
5993 vec![Register(Eax), Memory(Box::new(mem))],
5994 OperandSize::Byte,
5995 );
5996 assert_eq!(bytes, vec![0x0F, 0xBE, 0x03]);
5997 }
5998
5999 #[test]
6000 fn test_movsx_rax_word_mem() {
6001 let mem = MemoryOperand {
6003 base: Some(Rbx),
6004 ..Default::default()
6005 };
6006 let bytes = encode_with_hint(
6007 "movsx",
6008 vec![Register(Rax), Memory(Box::new(mem))],
6009 OperandSize::Word,
6010 );
6011 assert_eq!(bytes, vec![0x48, 0x0F, 0xBF, 0x03]);
6012 }
6013
6014 #[test]
6015 fn test_movsxd_rax_dword_mem() {
6016 let mem = MemoryOperand {
6018 base: Some(Rbx),
6019 ..Default::default()
6020 };
6021 let bytes = encode_with_hint(
6022 "movsx",
6023 vec![Register(Rax), Memory(Box::new(mem))],
6024 OperandSize::Dword,
6025 );
6026 assert_eq!(bytes, vec![0x48, 0x63, 0x03]);
6027 }
6028
6029 #[test]
6032 fn test_bsf_eax_mem() {
6033 let mem = MemoryOperand {
6035 base: Some(Rbx),
6036 ..Default::default()
6037 };
6038 let bytes = encode("bsf", vec![Register(Eax), Memory(Box::new(mem))]);
6039 assert_eq!(bytes, vec![0x0F, 0xBC, 0x03]);
6040 }
6041
6042 #[test]
6043 fn test_bsr_rax_mem() {
6044 let mem = MemoryOperand {
6046 base: Some(Rbx),
6047 ..Default::default()
6048 };
6049 let bytes = encode("bsr", vec![Register(Rax), Memory(Box::new(mem))]);
6050 assert_eq!(bytes, vec![0x48, 0x0F, 0xBD, 0x03]);
6051 }
6052
6053 #[test]
6056 fn test_popcnt_eax_mem() {
6057 let mem = MemoryOperand {
6059 base: Some(Rbx),
6060 ..Default::default()
6061 };
6062 let bytes = encode("popcnt", vec![Register(Eax), Memory(Box::new(mem))]);
6063 assert_eq!(bytes, vec![0xF3, 0x0F, 0xB8, 0x03]);
6064 }
6065
6066 #[test]
6067 fn test_lzcnt_rax_mem() {
6068 let mem = MemoryOperand {
6070 base: Some(Rbx),
6071 ..Default::default()
6072 };
6073 let bytes = encode("lzcnt", vec![Register(Rax), Memory(Box::new(mem))]);
6074 assert_eq!(bytes, vec![0xF3, 0x48, 0x0F, 0xBD, 0x03]);
6075 }
6076
6077 #[test]
6078 fn test_tzcnt_eax_mem() {
6079 let mem = MemoryOperand {
6081 base: Some(Rbx),
6082 ..Default::default()
6083 };
6084 let bytes = encode("tzcnt", vec![Register(Eax), Memory(Box::new(mem))]);
6085 assert_eq!(bytes, vec![0xF3, 0x0F, 0xBC, 0x03]);
6086 }
6087
6088 #[test]
6091 fn test_bt_mem_reg() {
6092 let mem = MemoryOperand {
6094 base: Some(Rbx),
6095 ..Default::default()
6096 };
6097 let bytes = encode("bt", vec![Memory(Box::new(mem)), Register(Eax)]);
6098 assert_eq!(bytes, vec![0x0F, 0xA3, 0x03]);
6099 }
6100
6101 #[test]
6102 fn test_bts_mem_imm() {
6103 let mem = MemoryOperand {
6105 base: Some(Rbx),
6106 size: Some(OperandSize::Dword),
6107 ..Default::default()
6108 };
6109 let bytes = encode("bts", vec![Memory(Box::new(mem)), Immediate(5)]);
6110 assert_eq!(bytes, vec![0x0F, 0xBA, 0x2B, 0x05]);
6111 }
6112
6113 #[test]
6116 fn test_shl_mem_1() {
6117 let mem = MemoryOperand {
6119 base: Some(Rbx),
6120 size: Some(OperandSize::Dword),
6121 ..Default::default()
6122 };
6123 let bytes = encode("shl", vec![Memory(Box::new(mem)), Immediate(1)]);
6124 assert_eq!(bytes, vec![0xD1, 0x23]);
6125 }
6126
6127 #[test]
6128 fn test_shr_mem_imm() {
6129 let mem = MemoryOperand {
6131 base: Some(Rbx),
6132 size: Some(OperandSize::Dword),
6133 ..Default::default()
6134 };
6135 let bytes = encode("shr", vec![Memory(Box::new(mem)), Immediate(4)]);
6136 assert_eq!(bytes, vec![0xC1, 0x2B, 0x04]);
6137 }
6138
6139 #[test]
6140 fn test_sar_mem_cl() {
6141 let mem = MemoryOperand {
6143 base: Some(Rbx),
6144 size: Some(OperandSize::Dword),
6145 ..Default::default()
6146 };
6147 let bytes = encode("sar", vec![Memory(Box::new(mem)), Register(Cl)]);
6148 assert_eq!(bytes, vec![0xD3, 0x3B]);
6149 }
6150
6151 #[test]
6154 fn test_mov_xmm_imm_error() {
6155 let instr = make_instr("mov", vec![Register(Xmm0), Immediate(1)]);
6156 let result = encode_instruction(&instr, Arch::X86_64);
6157 assert!(result.is_err());
6158 }
6159
6160 #[test]
6163 fn test_mov_rax_label_expression() {
6164 let expr = Expr::Add(
6166 Box::new(Expr::Label(String::from("data"))),
6167 Box::new(Expr::Num(8)),
6168 );
6169 let instr = make_instr("mov", vec![Register(Rax), Expression(expr)]);
6170 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6171 assert_eq!(result.bytes[0], 0x48); assert_eq!(result.bytes[1], 0xB8); let reloc = result.relocation.unwrap();
6174 assert_eq!(&*reloc.label, "data");
6175 assert_eq!(reloc.addend, 8);
6176 assert_eq!(reloc.size, 8);
6177 assert_eq!(reloc.kind, RelocKind::Absolute);
6178 }
6179
6180 #[test]
6181 fn test_jmp_label_expression() {
6182 let expr = Expr::Sub(
6183 Box::new(Expr::Label(String::from("target"))),
6184 Box::new(Expr::Num(2)),
6185 );
6186 let instr = make_instr("jmp", vec![Expression(expr)]);
6187 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6188 assert_eq!(result.bytes[0], 0xE9); let reloc = result.relocation.unwrap();
6190 assert_eq!(&*reloc.label, "target");
6191 assert_eq!(reloc.addend, -2);
6192 assert_eq!(reloc.kind, RelocKind::X86Relative);
6193 assert!(result.relax.is_some()); }
6195
6196 #[test]
6197 fn test_call_label_expression() {
6198 let expr = Expr::Add(
6199 Box::new(Expr::Label(String::from("func"))),
6200 Box::new(Expr::Num(4)),
6201 );
6202 let instr = make_instr("call", vec![Expression(expr)]);
6203 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6204 assert_eq!(result.bytes[0], 0xE8); let reloc = result.relocation.unwrap();
6206 assert_eq!(&*reloc.label, "func");
6207 assert_eq!(reloc.addend, 4);
6208 }
6209
6210 #[test]
6211 fn test_jcc_label_expression() {
6212 let expr = Expr::Add(
6213 Box::new(Expr::Label(String::from("dest"))),
6214 Box::new(Expr::Num(0)),
6215 );
6216 let instr = make_instr("je", vec![Expression(expr)]);
6217 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6218 assert_eq!(result.bytes[0], 0x0F); let reloc = result.relocation.unwrap();
6220 assert_eq!(&*reloc.label, "dest");
6221 assert_eq!(reloc.addend, 0);
6222 }
6223
6224 #[test]
6225 fn test_push_label_expression() {
6226 let expr = Expr::Add(
6227 Box::new(Expr::Label(String::from("data"))),
6228 Box::new(Expr::Num(16)),
6229 );
6230 let instr = make_instr("push", vec![Expression(expr)]);
6231 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6232 assert_eq!(result.bytes[0], 0x68); let reloc = result.relocation.unwrap();
6234 assert_eq!(&*reloc.label, "data");
6235 assert_eq!(reloc.addend, 16);
6236 }
6237
6238 #[test]
6239 fn test_loop_label_expression() {
6240 let expr = Expr::Sub(
6241 Box::new(Expr::Label(String::from("top"))),
6242 Box::new(Expr::Num(1)),
6243 );
6244 let instr = make_instr("loop", vec![Expression(expr)]);
6245 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6246 assert_eq!(result.bytes[0], 0xE2); let reloc = result.relocation.unwrap();
6249 assert_eq!(&*reloc.label, "top");
6250 assert_eq!(reloc.addend, -1);
6251 assert_eq!(reloc.size, 4); assert!(result.relax.is_some());
6254 let ri = result.relax.unwrap();
6255 assert_eq!(ri.short_bytes[0], 0xE2);
6256 assert_eq!(ri.short_bytes.len(), 2);
6257 }
6258
6259 #[test]
6262 fn test_extract_label_plain() {
6263 let op = Label(String::from("foo"));
6264 assert_eq!(extract_label(&op), Some(("foo", 0)));
6265 }
6266
6267 #[test]
6268 fn test_extract_label_expression() {
6269 let expr = Expr::Add(
6270 Box::new(Expr::Label(String::from("bar"))),
6271 Box::new(Expr::Num(10)),
6272 );
6273 assert_eq!(extract_label(&Expression(expr)), Some(("bar", 10)));
6274 }
6275
6276 #[test]
6277 fn test_extract_label_non_label() {
6278 assert_eq!(extract_label(&Immediate(42)), None);
6279 assert_eq!(extract_label(&Register(Rax)), None);
6280 }
6281
6282 #[test]
6285 fn test_imul_reg_mem_imm8() {
6286 let mem = MemoryOperand {
6288 base: Some(Rcx),
6289 ..Default::default()
6290 };
6291 let bytes = encode(
6292 "imul",
6293 vec![Register(Eax), Memory(Box::new(mem)), Immediate(5)],
6294 );
6295 assert_eq!(bytes, vec![0x6B, 0x01, 0x05]);
6296 }
6297
6298 #[test]
6299 fn test_imul_reg_mem_imm32() {
6300 let mem = MemoryOperand {
6302 base: Some(Rdx),
6303 ..Default::default()
6304 };
6305 let bytes = encode(
6306 "imul",
6307 vec![Register(Rax), Memory(Box::new(mem)), Immediate(1000)],
6308 );
6309 assert_eq!(bytes, vec![0x48, 0x69, 0x02, 0xE8, 0x03, 0x00, 0x00]);
6310 }
6311
6312 #[test]
6315 fn test_ret_imm16() {
6316 let bytes = encode("ret", vec![Immediate(8)]);
6318 assert_eq!(bytes, vec![0xC2, 0x08, 0x00]);
6319 }
6320
6321 #[test]
6322 fn test_ret_imm16_large() {
6323 let bytes = encode("ret", vec![Immediate(0x1234)]);
6325 assert_eq!(bytes, vec![0xC2, 0x34, 0x12]);
6326 }
6327
6328 #[test]
6329 fn test_retn_alias() {
6330 assert_eq!(encode("retn", vec![]), vec![0xC3]);
6332 assert_eq!(encode("retn", vec![Immediate(4)]), vec![0xC2, 0x04, 0x00]);
6333 }
6334
6335 #[test]
6338 fn test_retf() {
6339 assert_eq!(encode("retf", vec![]), vec![0xCB]);
6340 }
6341
6342 #[test]
6343 fn test_retf_imm16() {
6344 let bytes = encode("retf", vec![Immediate(4)]);
6346 assert_eq!(bytes, vec![0xCA, 0x04, 0x00]);
6347 }
6348
6349 #[test]
6350 fn test_lret_alias() {
6351 assert_eq!(encode("lret", vec![]), vec![0xCB]);
6352 assert_eq!(encode("lret", vec![Immediate(8)]), vec![0xCA, 0x08, 0x00]);
6353 }
6354
6355 #[test]
6358 fn test_movabs_alias() {
6359 let bytes_mov = encode("mov", vec![Register(Rax), Immediate(0x12345678)]);
6361 let bytes_movabs = encode("movabs", vec![Register(Rax), Immediate(0x12345678)]);
6362 assert_eq!(bytes_mov, bytes_movabs);
6363 }
6364
6365 #[test]
6366 fn test_movabs_imm64() {
6367 let bytes = encode("movabs", vec![Register(Rax), Immediate(0x0102030405060708)]);
6369 assert_eq!(
6370 bytes,
6371 vec![0x48, 0xB8, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]
6372 );
6373 }
6374
6375 #[test]
6378 fn test_high_byte_rex_conflict_rejected() {
6379 let instr = make_instr("mov", vec![Register(Ah), Register(Sil)]);
6381 let result = encode_instruction(&instr, Arch::X86_64);
6382 assert!(result.is_err());
6383 let err = result.unwrap_err();
6384 match err {
6385 AsmError::InvalidOperands { detail, .. } => {
6386 assert!(detail.contains("high-byte"));
6387 }
6388 other => panic!("expected InvalidOperands, got {:?}", other),
6389 }
6390 }
6391
6392 #[test]
6393 fn test_high_byte_extended_reg_conflict_rejected() {
6394 let instr = make_instr("add", vec![Register(Ah), Register(R8b)]);
6396 let result = encode_instruction(&instr, Arch::X86_64);
6397 assert!(result.is_err());
6398 }
6399
6400 #[test]
6401 fn test_high_byte_without_rex_ok() {
6402 let bytes = encode("mov", vec![Register(Ah), Register(Al)]);
6405 assert_eq!(bytes, vec![0x88, 0xC4]);
6406 }
6407
6408 #[test]
6409 fn test_high_byte_pair_ok() {
6410 let bytes = encode("xor", vec![Register(Ah), Register(Ch)]);
6413 assert_eq!(bytes, vec![0x30, 0xEC]);
6414 }
6415
6416 #[test]
6419 fn test_lock_valid_memory_dest() {
6420 let mem = MemoryOperand {
6422 base: Some(Rax),
6423 ..Default::default()
6424 };
6425 let bytes = encode_with_prefix(
6426 "add",
6427 vec![Memory(Box::new(mem)), Immediate(1)],
6428 Prefix::Lock,
6429 );
6430 assert_eq!(bytes[0], 0xF0);
6431 }
6432
6433 #[test]
6434 fn test_lock_invalid_reg_dest() {
6435 let mut instr = make_instr("add", vec![Register(Eax), Register(Ebx)]);
6437 instr.prefixes = PrefixList::from(alloc::vec![Prefix::Lock]);
6438 let result = encode_instruction(&instr, Arch::X86_64);
6439 assert!(result.is_err());
6440 match result.unwrap_err() {
6441 AsmError::InvalidOperands { detail, .. } => {
6442 assert!(detail.contains("LOCK"));
6443 }
6444 other => panic!("expected InvalidOperands for LOCK, got {:?}", other),
6445 }
6446 }
6447
6448 #[test]
6449 fn test_lock_invalid_imm_dest() {
6450 let mut instr = make_instr("xchg", vec![Register(Eax), Register(Ecx)]);
6452 instr.prefixes = PrefixList::from(alloc::vec![Prefix::Lock]);
6453 let result = encode_instruction(&instr, Arch::X86_64);
6454 assert!(result.is_err());
6455 }
6456
6457 #[test]
6460 fn test_push_fs() {
6461 assert_eq!(encode("push", vec![Register(Fs)]), vec![0x0F, 0xA0]);
6463 }
6464
6465 #[test]
6466 fn test_push_gs() {
6467 assert_eq!(encode("push", vec![Register(Gs)]), vec![0x0F, 0xA8]);
6469 }
6470
6471 #[test]
6472 fn test_pop_fs() {
6473 assert_eq!(encode("pop", vec![Register(Fs)]), vec![0x0F, 0xA1]);
6475 }
6476
6477 #[test]
6478 fn test_pop_gs() {
6479 assert_eq!(encode("pop", vec![Register(Gs)]), vec![0x0F, 0xA9]);
6481 }
6482
6483 #[test]
6486 fn test_xchg_eax_eax_is_nop() {
6487 let bytes = encode("xchg", vec![Register(Eax), Register(Eax)]);
6489 assert_eq!(bytes, vec![0x90]);
6490 }
6491
6492 #[test]
6493 fn test_xchg_rax_rax() {
6494 let bytes = encode("xchg", vec![Register(Rax), Register(Rax)]);
6496 assert_eq!(bytes, vec![0x48, 0x90]);
6497 }
6498
6499 #[test]
6500 fn test_xchg_ax_ax() {
6501 let bytes = encode("xchg", vec![Register(Ax), Register(Ax)]);
6503 assert_eq!(bytes, vec![0x66, 0x90]);
6504 }
6505
6506 #[test]
6509 fn test_mov_ah_imm8() {
6510 let bytes = encode("mov", vec![Register(Ah), Immediate(0x42)]);
6512 assert_eq!(bytes, vec![0xB4, 0x42]);
6513 }
6514
6515 #[test]
6516 fn test_mov_ch_imm8() {
6517 let bytes = encode("mov", vec![Register(Ch), Immediate(0x11)]);
6519 assert_eq!(bytes, vec![0xB5, 0x11]);
6520 }
6521
6522 #[test]
6523 fn test_mov_dh_imm8() {
6524 let bytes = encode("mov", vec![Register(Dh), Immediate(0x22)]);
6526 assert_eq!(bytes, vec![0xB6, 0x22]);
6527 }
6528
6529 #[test]
6530 fn test_mov_bh_imm8() {
6531 let bytes = encode("mov", vec![Register(Bh), Immediate(0x33)]);
6533 assert_eq!(bytes, vec![0xB7, 0x33]);
6534 }
6535
6536 #[test]
6539 fn test_shl_byte_ptr_mem_1() {
6540 let mem = MemoryOperand {
6542 base: Some(Rbx),
6543 ..Default::default()
6544 };
6545 let bytes = encode_with_hint(
6546 "shl",
6547 vec![Memory(Box::new(mem)), Immediate(1)],
6548 OperandSize::Byte,
6549 );
6550 assert_eq!(bytes[0], 0xD0); }
6553
6554 #[test]
6555 fn test_shr_qword_ptr_mem_cl() {
6556 let mem = MemoryOperand {
6558 base: Some(Rax),
6559 ..Default::default()
6560 };
6561 let bytes = encode_with_hint(
6562 "shr",
6563 vec![Memory(Box::new(mem)), Register(Cl)],
6564 OperandSize::Qword,
6565 );
6566 assert_eq!(bytes[0], 0x48); assert_eq!(bytes[1], 0xD3); }
6569
6570 #[test]
6571 fn test_shl_word_ptr_mem_imm() {
6572 let mem = MemoryOperand {
6574 base: Some(Rcx),
6575 ..Default::default()
6576 };
6577 let bytes = encode_with_hint(
6578 "shl",
6579 vec![Memory(Box::new(mem)), Immediate(4)],
6580 OperandSize::Word,
6581 );
6582 assert_eq!(bytes[0], 0x66); assert_eq!(bytes[1], 0xC1); }
6585
6586 #[test]
6589 fn test_push_eax_rejected() {
6590 let instr = make_instr("push", vec![Register(Eax)]);
6592 let result = encode_instruction(&instr, Arch::X86_64);
6593 assert!(result.is_err());
6594 }
6595
6596 #[test]
6597 fn test_pop_eax_rejected() {
6598 let instr = make_instr("pop", vec![Register(Eax)]);
6600 let result = encode_instruction(&instr, Arch::X86_64);
6601 assert!(result.is_err());
6602 }
6603
6604 #[test]
6605 fn test_push_al_rejected() {
6606 let instr = make_instr("push", vec![Register(Al)]);
6608 let result = encode_instruction(&instr, Arch::X86_64);
6609 assert!(result.is_err());
6610 }
6611
6612 #[test]
6613 fn test_push_cs_rejected() {
6614 let instr = make_instr("push", vec![Register(Cs)]);
6616 let result = encode_instruction(&instr, Arch::X86_64);
6617 assert!(result.is_err());
6618 }
6619
6620 #[test]
6621 fn test_pop_ds_rejected() {
6622 let instr = make_instr("pop", vec![Register(Ds)]);
6624 let result = encode_instruction(&instr, Arch::X86_64);
6625 assert!(result.is_err());
6626 }
6627
6628 #[test]
6631 fn test_cmove_8bit_rejected() {
6632 let instr = make_instr("cmove", vec![Register(Al), Register(Bl)]);
6633 let result = encode_instruction(&instr, Arch::X86_64);
6634 assert!(result.is_err());
6635 }
6636
6637 #[test]
6640 fn test_add_rax_mem_label_reloc() {
6641 let mem = MemoryOperand {
6643 base: Some(Rip),
6644 disp_label: Some(alloc::string::String::from("my_data")),
6645 addr_mode: AddrMode::Offset,
6646 ..Default::default()
6647 };
6648 let instr = make_instr("add", vec![Register(Rax), Memory(Box::new(mem))]);
6649 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6650 assert!(
6651 result.relocation.is_some(),
6652 "expected relocation for add rax, [my_data]"
6653 );
6654 let reloc = result.relocation.unwrap();
6655 assert_eq!(&*reloc.label, "my_data");
6656 assert_eq!(reloc.kind, RelocKind::X86Relative);
6657 }
6658
6659 #[test]
6660 fn test_cmp_mem_label_imm_reloc() {
6661 let mem = MemoryOperand {
6663 base: Some(Rip),
6664 disp_label: Some(alloc::string::String::from("counter")),
6665 addr_mode: AddrMode::Offset,
6666 ..Default::default()
6667 };
6668 let mut instr = make_instr("cmp", vec![Memory(Box::new(mem)), Immediate(0)]);
6669 instr.size_hint = Some(OperandSize::Dword);
6670 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6671 assert!(
6672 result.relocation.is_some(),
6673 "expected relocation for cmp [counter], 0"
6674 );
6675 let reloc = result.relocation.unwrap();
6676 assert_eq!(&*reloc.label, "counter");
6677 }
6678
6679 #[test]
6680 fn test_mov_mem_label_reg_reloc() {
6681 let mem = MemoryOperand {
6683 base: Some(Rip),
6684 disp_label: Some(alloc::string::String::from("my_var")),
6685 addr_mode: AddrMode::Offset,
6686 ..Default::default()
6687 };
6688 let instr = make_instr("mov", vec![Memory(Box::new(mem)), Register(Rax)]);
6689 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6690 assert!(
6691 result.relocation.is_some(),
6692 "expected relocation for mov [my_var], rax"
6693 );
6694 let reloc = result.relocation.unwrap();
6695 assert_eq!(&*reloc.label, "my_var");
6696 assert_eq!(reloc.kind, RelocKind::X86Relative);
6697 }
6698
6699 #[test]
6700 fn test_mov_mem_label_imm_reloc() {
6701 let mem = MemoryOperand {
6703 base: Some(Rip),
6704 disp_label: Some(alloc::string::String::from("flag")),
6705 addr_mode: AddrMode::Offset,
6706 ..Default::default()
6707 };
6708 let mut instr = make_instr("mov", vec![Memory(Box::new(mem)), Immediate(1)]);
6709 instr.size_hint = Some(OperandSize::Dword);
6710 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6711 assert!(
6712 result.relocation.is_some(),
6713 "expected relocation for mov [flag], 1"
6714 );
6715 let reloc = result.relocation.unwrap();
6716 assert_eq!(&*reloc.label, "flag");
6717 assert_eq!(reloc.kind, RelocKind::X86Relative);
6718 }
6719
6720 #[test]
6721 fn test_test_mem_label_reloc() {
6722 let mem = MemoryOperand {
6724 base: Some(Rip),
6725 disp_label: Some(alloc::string::String::from("status")),
6726 addr_mode: AddrMode::Offset,
6727 ..Default::default()
6728 };
6729 let mut instr = make_instr("test", vec![Memory(Box::new(mem)), Immediate(1)]);
6730 instr.size_hint = Some(OperandSize::Dword);
6731 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6732 assert!(
6733 result.relocation.is_some(),
6734 "expected relocation for test [status], 1"
6735 );
6736 }
6737
6738 #[test]
6741 fn test_segment_override_fs_prefix_position() {
6742 let mem = MemoryOperand {
6744 base: Some(Rbx),
6745 segment: Some(Fs),
6746 ..Default::default()
6747 };
6748 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
6749 assert_eq!(bytes[0], 0x64, "FS segment override must be first byte");
6751 assert_eq!(bytes[1], 0x48, "REX.W must follow segment override");
6752 assert_eq!(bytes[2], 0x8B, "opcode must follow REX");
6753 }
6754
6755 #[test]
6756 fn test_segment_override_gs_prefix_position() {
6757 let mem = MemoryOperand {
6759 base: Some(Rdx),
6760 segment: Some(Gs),
6761 ..Default::default()
6762 };
6763 let bytes = encode("mov", vec![Register(Eax), Memory(Box::new(mem))]);
6764 assert_eq!(bytes[0], 0x65, "GS segment override must be first byte");
6765 assert_eq!(bytes[1], 0x8B, "opcode must follow segment override");
6766 }
6767
6768 #[test]
6769 fn test_segment_override_with_extended_reg() {
6770 let mem = MemoryOperand {
6772 base: Some(R12),
6773 segment: Some(Fs),
6774 ..Default::default()
6775 };
6776 let bytes = encode("add", vec![Register(Rax), Memory(Box::new(mem))]);
6777 assert_eq!(bytes[0], 0x64, "FS must precede REX");
6778 assert_eq!(bytes[1] & 0xF0, 0x40, "REX must follow segment override");
6779 }
6780
6781 #[test]
6784 fn test_sib_index_only_disp0() {
6785 let mem = MemoryOperand {
6788 index: Some(Rsi),
6789 scale: 4,
6790 ..Default::default()
6791 };
6792 let bytes = encode("mov", vec![Register(Rax), Memory(Box::new(mem))]);
6793 assert_eq!(bytes.len(), 8, "SIB index-only must include 4-byte disp32");
6794 assert_eq!(bytes[0], 0x48); assert_eq!(bytes[1], 0x8B); assert_eq!(bytes[2] & 0xC7, 0x04); assert_eq!(bytes[3], 0xB5); assert_eq!(&bytes[4..8], &[0, 0, 0, 0]); }
6801
6802 #[test]
6803 fn test_sib_index_only_with_disp() {
6804 let mem = MemoryOperand {
6807 index: Some(Rdi),
6808 scale: 8,
6809 disp: 16,
6810 ..Default::default()
6811 };
6812 let bytes = encode("lea", vec![Register(Rax), Memory(Box::new(mem))]);
6813 assert_eq!(bytes.len(), 8, "SIB index-only with disp must use disp32");
6814 assert_eq!(bytes[2] & 0xC0, 0x00, "mod must be 00 (disp32, no base)");
6815 assert_eq!(&bytes[4..8], &(16i32).to_le_bytes());
6817 }
6818
6819 #[test]
6820 fn test_sib_index_only_extended_index() {
6821 let mem = MemoryOperand {
6823 index: Some(R9),
6824 scale: 2,
6825 ..Default::default()
6826 };
6827 let bytes = encode("mov", vec![Register(Eax), Memory(Box::new(mem))]);
6828 assert_eq!(bytes.len(), 8, "SIB index-only with extended index");
6829 assert_eq!(bytes[0] & 0x42, 0x42, "REX.X must be set for R9 index");
6830 }
6831
6832 #[test]
6835 fn test_bt_rejects_8bit() {
6836 let instr = make_instr("bt", vec![Register(Al), Immediate(1)]);
6837 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6838 }
6839
6840 #[test]
6841 fn test_bsf_rejects_8bit() {
6842 let instr = make_instr("bsf", vec![Register(Al), Register(Cl)]);
6843 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6844 }
6845
6846 #[test]
6847 fn test_bsr_rejects_8bit() {
6848 let instr = make_instr("bsr", vec![Register(Al), Register(Cl)]);
6849 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6850 }
6851
6852 #[test]
6853 fn test_popcnt_rejects_8bit() {
6854 let instr = make_instr("popcnt", vec![Register(Al), Register(Cl)]);
6855 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6856 }
6857
6858 #[test]
6859 fn test_lzcnt_rejects_8bit() {
6860 let instr = make_instr("lzcnt", vec![Register(Al), Register(Cl)]);
6861 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6862 }
6863
6864 #[test]
6865 fn test_tzcnt_rejects_8bit() {
6866 let instr = make_instr("tzcnt", vec![Register(Al), Register(Cl)]);
6867 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6868 }
6869
6870 #[test]
6871 fn test_bswap_rejects_8bit() {
6872 let instr = make_instr("bswap", vec![Register(Al)]);
6873 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6874 }
6875
6876 #[test]
6877 fn test_bswap_rejects_16bit() {
6878 let instr = make_instr("bswap", vec![Register(Ax)]);
6879 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
6880 }
6881
6882 #[test]
6885 fn test_push_mem_no_redundant_rex() {
6886 let mem = MemoryOperand {
6888 base: Some(Rdi),
6889 ..Default::default()
6890 };
6891 let bytes = encode("push", vec![Memory(Box::new(mem))]);
6892 assert_eq!(bytes, &[0xFF, 0x37], "push [rdi] should not have REX.W");
6893 }
6894
6895 #[test]
6896 fn test_pop_mem_no_redundant_rex() {
6897 let mem = MemoryOperand {
6899 base: Some(Rdi),
6900 ..Default::default()
6901 };
6902 let bytes = encode("pop", vec![Memory(Box::new(mem))]);
6903 assert_eq!(bytes, &[0x8F, 0x07], "pop [rdi] should not have REX.W");
6904 }
6905
6906 #[test]
6907 fn test_jmp_mem_no_redundant_rex() {
6908 let mem = MemoryOperand {
6910 base: Some(Rdi),
6911 ..Default::default()
6912 };
6913 let bytes = encode("jmp", vec![Memory(Box::new(mem))]);
6914 assert_eq!(bytes, &[0xFF, 0x27], "jmp [rdi] should not have REX.W");
6915 }
6916
6917 #[test]
6918 fn test_call_mem_no_redundant_rex() {
6919 let mem = MemoryOperand {
6921 base: Some(Rdi),
6922 ..Default::default()
6923 };
6924 let bytes = encode("call", vec![Memory(Box::new(mem))]);
6925 assert_eq!(bytes, &[0xFF, 0x17], "call [rdi] should not have REX.W");
6926 }
6927
6928 #[test]
6929 fn test_push_mem_extended_needs_rex() {
6930 let mem = MemoryOperand {
6932 base: Some(R15),
6933 ..Default::default()
6934 };
6935 let bytes = encode("push", vec![Memory(Box::new(mem))]);
6936 assert_eq!(bytes[0], 0x41, "push [r15] needs REX.B");
6937 assert_eq!(bytes[1], 0xFF);
6938 }
6939
6940 #[test]
6943 fn test_xchg_rbx_rax_short_form() {
6944 let bytes = encode("xchg", vec![Register(Rbx), Register(Rax)]);
6946 assert_eq!(bytes, &[0x48, 0x93], "xchg rbx, rax should use short form");
6947 }
6948
6949 #[test]
6950 fn test_xchg_ecx_eax_short_form() {
6951 let bytes = encode("xchg", vec![Register(Ecx), Register(Eax)]);
6953 assert_eq!(bytes, &[0x91], "xchg ecx, eax should use short form");
6954 }
6955
6956 #[test]
6959 fn test_alu_mem_imm_reloc_explicit() {
6960 let mem = MemoryOperand {
6962 base: Some(Rip),
6963 disp_label: Some(alloc::string::String::from("data")),
6964 addr_mode: AddrMode::Offset,
6965 ..Default::default()
6966 };
6967 let mut instr = make_instr("add", vec![Memory(Box::new(mem)), Immediate(5)]);
6968 instr.size_hint = Some(OperandSize::Dword);
6969 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6970 assert!(
6971 result.relocation.is_some(),
6972 "expected relocation for add [label], imm"
6973 );
6974 let roff = result.relocation.as_ref().unwrap().offset;
6976 assert_eq!(roff, 2, "reloc should point at displacement, not immediate");
6978 }
6979
6980 #[test]
6983 fn test_no_double_segment_override() {
6984 let mem = MemoryOperand {
6986 base: Some(Rbx),
6987 segment: Some(Fs),
6988 ..Default::default()
6989 };
6990 let mut instr = make_instr("mov", vec![Register(Rax), Memory(Box::new(mem))]);
6991 instr.prefixes.push(Prefix::SegFs);
6992 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
6993 let count_64 = result.bytes.iter().filter(|&&b| b == 0x64).count();
6995 assert_eq!(count_64, 1, "should not emit double FS segment override");
6996 }
6997
6998 #[test]
6999 fn test_rip_relative_trailing_bytes_mov_mem_imm() {
7000 let mem = MemoryOperand {
7003 base: Some(crate::ir::Register::Rip),
7004 index: None,
7005 scale: 1,
7006 disp: 0,
7007 size: Some(OperandSize::Dword),
7008 segment: None,
7009 disp_label: Some(String::from("data")),
7010 addr_mode: AddrMode::Offset,
7011 index_subtract: false,
7012 };
7013 let instr = make_instr_with_hint(
7014 "mov",
7015 vec![Memory(Box::new(mem)), Immediate(42)],
7016 Some(OperandSize::Dword),
7017 );
7018 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7019 assert_eq!(result.bytes[0], 0xC7); assert_eq!(result.bytes[1], 0x05); let reloc = result.relocation.as_ref().unwrap();
7023 assert_eq!(reloc.offset, 2); assert_eq!(reloc.size, 4); assert_eq!(reloc.kind, RelocKind::X86Relative);
7026 assert_eq!(reloc.trailing_bytes, 4); assert_eq!(result.bytes.len(), 10); }
7029
7030 #[test]
7031 fn test_rip_relative_trailing_bytes_mov_mem_reg() {
7032 let mem = MemoryOperand {
7035 base: Some(crate::ir::Register::Rip),
7036 index: None,
7037 scale: 1,
7038 disp: 0,
7039 size: None,
7040 segment: None,
7041 disp_label: Some(String::from("data")),
7042 addr_mode: AddrMode::Offset,
7043 index_subtract: false,
7044 };
7045 let instr = make_instr(
7046 "mov",
7047 vec![
7048 Memory(Box::new(mem)),
7049 Operand::Register(crate::ir::Register::Rax),
7050 ],
7051 );
7052 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7053 let reloc = result.relocation.as_ref().unwrap();
7054 assert_eq!(reloc.kind, RelocKind::X86Relative);
7055 assert_eq!(reloc.trailing_bytes, 0); }
7057
7058 #[test]
7059 fn test_rip_relative_trailing_bytes_alu_mem_imm8() {
7060 let mem = MemoryOperand {
7063 base: Some(crate::ir::Register::Rip),
7064 index: None,
7065 scale: 1,
7066 disp: 0,
7067 size: Some(OperandSize::Dword),
7068 segment: None,
7069 disp_label: Some(String::from("target")),
7070 addr_mode: AddrMode::Offset,
7071 index_subtract: false,
7072 };
7073 let instr = make_instr_with_hint(
7074 "add",
7075 vec![Memory(Box::new(mem)), Immediate(5)],
7076 Some(OperandSize::Dword),
7077 );
7078 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7079 let reloc = result.relocation.as_ref().unwrap();
7080 assert_eq!(reloc.kind, RelocKind::X86Relative);
7081 assert_eq!(reloc.trailing_bytes, 1); }
7083
7084 #[test]
7085 fn test_rip_relative_trailing_bytes_jmp() {
7086 let instr = make_instr("jmp", vec![Label(String::from("target"))]);
7089 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7090 let reloc = result.relocation.as_ref().unwrap();
7091 assert_eq!(reloc.kind, RelocKind::X86Relative);
7092 assert_eq!(reloc.trailing_bytes, 0);
7093 }
7094
7095 #[test]
7098 fn test_push_imm8_short_form() {
7099 assert_eq!(encode("push", vec![Immediate(0x42)]), vec![0x6A, 0x42]);
7101 }
7102
7103 #[test]
7104 fn test_push_imm32_full_form() {
7105 assert_eq!(
7106 encode("push", vec![Immediate(0x12345678)]),
7107 vec![0x68, 0x78, 0x56, 0x34, 0x12]
7108 );
7109 }
7110
7111 #[test]
7112 fn test_push_imm_out_of_range_rejects() {
7113 let instr = make_instr("push", vec![Immediate(0x1_0000_0000)]);
7115 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7116 }
7117
7118 #[test]
7121 fn test_imul_2op_rejects_8bit() {
7122 let instr = make_instr("imul", vec![Register(Al), Register(Bl)]);
7123 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7124 }
7125
7126 #[test]
7127 fn test_imul_2op_mem_rejects_8bit() {
7128 let mem = MemoryOperand {
7129 base: Some(Rbx),
7130 ..Default::default()
7131 };
7132 let instr = make_instr("imul", vec![Register(Al), Memory(Box::new(mem))]);
7133 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7134 }
7135
7136 #[test]
7137 fn test_imul_3op_rejects_8bit() {
7138 let instr = make_instr("imul", vec![Register(Al), Register(Bl), Immediate(5)]);
7139 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7140 }
7141
7142 #[test]
7143 fn test_imul_3op_mem_rejects_8bit() {
7144 let mem = MemoryOperand {
7145 base: Some(Rcx),
7146 ..Default::default()
7147 };
7148 let instr = make_instr(
7149 "imul",
7150 vec![Register(Al), Memory(Box::new(mem)), Immediate(5)],
7151 );
7152 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7153 }
7154
7155 #[test]
7158 fn test_cmovcc_reg_mem_rejects_8bit() {
7159 let mem = MemoryOperand {
7160 base: Some(Rbx),
7161 ..Default::default()
7162 };
7163 let instr = make_instr("cmove", vec![Register(Al), Memory(Box::new(mem))]);
7164 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7165 }
7166
7167 #[test]
7170 fn test_setcc_rejects_32bit_register() {
7171 let instr = make_instr("sete", vec![Register(Eax)]);
7172 assert!(encode_instruction(&instr, Arch::X86_64).is_err());
7173 }
7174
7175 #[test]
7176 fn test_setcc_accepts_8bit_register() {
7177 assert_eq!(encode("sete", vec![Register(Al)]), vec![0x0F, 0x94, 0xC0]);
7179 }
7180
7181 #[test]
7184 fn test_movzx_mem_word_source_via_mem_size() {
7185 let mem = MemoryOperand {
7187 base: Some(Rbx),
7188 size: Some(OperandSize::Word),
7189 ..Default::default()
7190 };
7191 let instr = make_instr("movzx", vec![Register(Eax), Memory(Box::new(mem))]);
7193 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7194 assert_eq!(result.bytes, vec![0x0F, 0xB7, 0x03]);
7196 }
7197
7198 #[test]
7199 fn test_movsx_mem_word_source_via_mem_size() {
7200 let mem = MemoryOperand {
7202 base: Some(Rbx),
7203 size: Some(OperandSize::Word),
7204 ..Default::default()
7205 };
7206 let instr = make_instr("movsx", vec![Register(Eax), Memory(Box::new(mem))]);
7207 let result = encode_instruction(&instr, Arch::X86_64).unwrap();
7208 assert_eq!(result.bytes, vec![0x0F, 0xBF, 0x03]);
7210 }
7211
7212 #[test]
7215 fn test_16bit_mov_ax_imm16() {
7216 let instr = make_instr("mov", vec![Register(Ax), Immediate(0x1234)]);
7219 let result = encode_instruction_16(&instr).unwrap();
7220 assert_eq!(result.bytes, vec![0xB8, 0x34, 0x12]);
7221 }
7222
7223 #[test]
7224 fn test_16bit_mov_eax_imm32() {
7225 let instr = make_instr("mov", vec![Register(Eax), Immediate(0x1234_5678)]);
7228 let result = encode_instruction_16(&instr).unwrap();
7229 assert_eq!(result.bytes, vec![0x66, 0xB8, 0x78, 0x56, 0x34, 0x12]);
7230 }
7231
7232 #[test]
7233 fn test_16bit_xor_ax_ax() {
7234 let instr = make_instr("xor", vec![Register(Ax), Register(Ax)]);
7236 let result = encode_instruction_16(&instr).unwrap();
7237 assert_eq!(result.bytes, vec![0x31, 0xC0]);
7238 }
7239
7240 #[test]
7241 fn test_16bit_xor_eax_eax() {
7242 let instr = make_instr("xor", vec![Register(Eax), Register(Eax)]);
7244 let result = encode_instruction_16(&instr).unwrap();
7245 assert_eq!(result.bytes, vec![0x66, 0x31, 0xC0]);
7246 }
7247
7248 #[test]
7249 fn test_16bit_push_ax() {
7250 let instr = make_instr("push", vec![Register(Ax)]);
7252 let result = encode_instruction_16(&instr).unwrap();
7253 assert_eq!(result.bytes, vec![0x50]);
7254 }
7255
7256 #[test]
7257 fn test_16bit_push_eax() {
7258 let instr = make_instr("push", vec![Register(Eax)]);
7260 let result = encode_instruction_16(&instr).unwrap();
7261 assert_eq!(result.bytes, vec![0x66, 0x50]);
7262 }
7263
7264 #[test]
7265 fn test_16bit_pop_bx() {
7266 let instr = make_instr("pop", vec![Register(Bx)]);
7268 let result = encode_instruction_16(&instr).unwrap();
7269 assert_eq!(result.bytes, vec![0x5B]);
7270 }
7271
7272 #[test]
7273 fn test_16bit_pop_ebx() {
7274 let instr = make_instr("pop", vec![Register(Ebx)]);
7276 let result = encode_instruction_16(&instr).unwrap();
7277 assert_eq!(result.bytes, vec![0x66, 0x5B]);
7278 }
7279
7280 #[test]
7281 fn test_16bit_inc_cx() {
7282 let instr = make_instr("inc", vec![Register(Cx)]);
7284 let result = encode_instruction_16(&instr).unwrap();
7285 assert_eq!(result.bytes, vec![0x41]);
7286 }
7287
7288 #[test]
7289 fn test_16bit_inc_ecx() {
7290 let instr = make_instr("inc", vec![Register(Ecx)]);
7292 let result = encode_instruction_16(&instr).unwrap();
7293 assert_eq!(result.bytes, vec![0x66, 0x41]);
7294 }
7295
7296 #[test]
7297 fn test_16bit_dec_dx() {
7298 let instr = make_instr("dec", vec![Register(Dx)]);
7300 let result = encode_instruction_16(&instr).unwrap();
7301 assert_eq!(result.bytes, vec![0x4A]);
7302 }
7303
7304 #[test]
7305 fn test_16bit_nop() {
7306 let instr = make_instr("nop", vec![]);
7308 let result = encode_instruction_16(&instr).unwrap();
7309 assert_eq!(result.bytes, vec![0x90]);
7310 }
7311
7312 #[test]
7313 fn test_16bit_cli() {
7314 let instr = make_instr("cli", vec![]);
7316 let result = encode_instruction_16(&instr).unwrap();
7317 assert_eq!(result.bytes, vec![0xFA]);
7318 }
7319
7320 #[test]
7321 fn test_16bit_int_10h() {
7322 let instr = make_instr("int", vec![Immediate(0x10)]);
7324 let result = encode_instruction_16(&instr).unwrap();
7325 assert_eq!(result.bytes, vec![0xCD, 0x10]);
7326 }
7327
7328 #[test]
7329 fn test_16bit_push_es() {
7330 let instr = make_instr("push", vec![Register(Es)]);
7332 let result = encode_instruction_16(&instr).unwrap();
7333 assert_eq!(result.bytes, vec![0x06]);
7334 }
7335
7336 #[test]
7337 fn test_16bit_push_cs() {
7338 let instr = make_instr("push", vec![Register(Cs)]);
7340 let result = encode_instruction_16(&instr).unwrap();
7341 assert_eq!(result.bytes, vec![0x0E]);
7342 }
7343
7344 #[test]
7345 fn test_16bit_pop_ds() {
7346 let instr = make_instr("pop", vec![Register(Ds)]);
7348 let result = encode_instruction_16(&instr).unwrap();
7349 assert_eq!(result.bytes, vec![0x1F]);
7350 }
7351
7352 #[test]
7353 fn test_16bit_push_imm8() {
7354 let instr = make_instr("push", vec![Immediate(0x42)]);
7356 let result = encode_instruction_16(&instr).unwrap();
7357 assert_eq!(result.bytes, vec![0x6A, 0x42]);
7358 }
7359
7360 #[test]
7361 fn test_16bit_add_ax_bx() {
7362 let instr = make_instr("add", vec![Register(Ax), Register(Bx)]);
7364 let result = encode_instruction_16(&instr).unwrap();
7365 assert_eq!(result.bytes, vec![0x01, 0xD8]);
7366 }
7367
7368 #[test]
7369 fn test_16bit_mov_al_imm8() {
7370 let instr = make_instr("mov", vec![Register(Al), Immediate(0x42)]);
7372 let result = encode_instruction_16(&instr).unwrap();
7373 assert_eq!(result.bytes, vec![0xB0, 0x42]);
7374 }
7375
7376 #[test]
7377 fn test_16bit_rejects_64bit_register() {
7378 let instr = make_instr("mov", vec![Register(Rax), Immediate(1)]);
7380 assert!(encode_instruction_16(&instr).is_err());
7381 }
7382
7383 #[test]
7390 fn test_emit_evex_basic_prefix() {
7391 let mut buf = InstrBytes::new();
7393 emit_evex(
7398 &mut buf, false, false, false, false, 1, false, 1, false, 0, false, 2, false, 0,
7399 );
7400 assert_eq!(buf[0], 0x62, "EVEX escape byte");
7401 assert_eq!(buf[1], 0xF1, "P0");
7403 assert_eq!(buf[2], 0x74, "P1");
7405 assert_eq!(buf[3], 0x48, "P2");
7407 }
7408
7409 #[test]
7410 fn test_emit_evex_w_bit() {
7411 let mut buf = InstrBytes::new();
7412 emit_evex(
7414 &mut buf, false, false, false, false, 1, true, 0, false, 0, false, 2, false, 0,
7415 );
7416 assert_eq!(buf[2], 0xFC, "P1 with W=1");
7418 }
7419
7420 #[test]
7421 fn test_emit_evex_extended_reg() {
7422 let mut buf = InstrBytes::new();
7423 emit_evex(
7425 &mut buf, true, false, false, true, 1, false, 0, false, 0, false, 2, false, 0,
7426 );
7427 assert_eq!(buf[1], 0x61, "P0 with R,R' extended");
7429 }
7430
7431 #[test]
7434 fn test_evex_ll_zmm() {
7435 assert_eq!(evex_ll(Zmm0), 2);
7436 assert_eq!(evex_ll(Zmm31), 2);
7437 }
7438
7439 #[test]
7440 fn test_evex_ll_ymm() {
7441 assert_eq!(evex_ll(Ymm0), 1);
7442 }
7443
7444 #[test]
7445 fn test_evex_ll_xmm() {
7446 assert_eq!(evex_ll(Xmm0), 0);
7447 }
7448
7449 #[test]
7452 fn test_evex_vaddps_zmm0_zmm1_zmm2() {
7453 let bytes = encode(
7455 "vaddps",
7456 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7457 );
7458 assert_eq!(bytes, vec![0x62, 0xF1, 0x74, 0x48, 0x58, 0xC2]);
7459 }
7460
7461 #[test]
7462 fn test_evex_vaddpd_zmm0_zmm1_zmm2() {
7463 let bytes = encode(
7467 "vaddpd",
7468 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7469 );
7470 assert_eq!(bytes, vec![0x62, 0xF1, 0xF5, 0x48, 0x58, 0xC2]);
7471 }
7472
7473 #[test]
7474 fn test_evex_vsubps_zmm3_zmm4_zmm5() {
7475 let bytes = encode(
7483 "vsubps",
7484 vec![Register(Zmm3), Register(Zmm4), Register(Zmm5)],
7485 );
7486 assert_eq!(bytes, vec![0x62, 0xF1, 0x5C, 0x48, 0x5C, 0xDD]);
7487 }
7488
7489 #[test]
7490 fn test_evex_vmulps_zmm0_zmm1_zmm2() {
7491 let bytes = encode(
7492 "vmulps",
7493 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7494 );
7495 assert_eq!(bytes, vec![0x62, 0xF1, 0x74, 0x48, 0x59, 0xC2]);
7496 }
7497
7498 #[test]
7499 fn test_evex_vdivps_zmm0_zmm1_zmm2() {
7500 let bytes = encode(
7501 "vdivps",
7502 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7503 );
7504 assert_eq!(bytes, vec![0x62, 0xF1, 0x74, 0x48, 0x5E, 0xC2]);
7505 }
7506
7507 #[test]
7508 fn test_evex_vmovaps_zmm0_zmm1() {
7509 let bytes = encode("vmovaps", vec![Register(Zmm0), Register(Zmm1)]);
7514 assert_eq!(bytes, vec![0x62, 0xF1, 0x7C, 0x48, 0x28, 0xC1]);
7515 }
7516
7517 #[test]
7518 fn test_evex_vmovdqa32_zmm0_zmm1() {
7519 let bytes = encode("vmovdqa32", vec![Register(Zmm0), Register(Zmm1)]);
7522 assert_eq!(bytes, vec![0x62, 0xF1, 0x7D, 0x48, 0x6F, 0xC1]);
7523 }
7524
7525 #[test]
7526 fn test_evex_vmovdqa64_zmm0_zmm1() {
7527 let bytes = encode("vmovdqa64", vec![Register(Zmm0), Register(Zmm1)]);
7530 assert_eq!(bytes, vec![0x62, 0xF1, 0xFD, 0x48, 0x6F, 0xC1]);
7531 }
7532
7533 #[test]
7534 fn test_evex_vpternlogd_zmm0_zmm1_zmm2_imm() {
7535 let bytes = encode(
7540 "vpternlogd",
7541 vec![
7542 Register(Zmm0),
7543 Register(Zmm1),
7544 Register(Zmm2),
7545 Immediate(0xFF),
7546 ],
7547 );
7548 assert_eq!(bytes, vec![0x62, 0xF3, 0x75, 0x48, 0x25, 0xC2, 0xFF]);
7549 }
7550
7551 #[test]
7552 fn test_evex_vpternlogq_zmm0_zmm1_zmm2_imm() {
7553 let bytes = encode(
7555 "vpternlogq",
7556 vec![
7557 Register(Zmm0),
7558 Register(Zmm1),
7559 Register(Zmm2),
7560 Immediate(0xDB),
7561 ],
7562 );
7563 assert_eq!(bytes, vec![0x62, 0xF3, 0xF5, 0x48, 0x25, 0xC2, 0xDB]);
7564 }
7565
7566 #[test]
7567 fn test_evex_vpaddd_zmm0_zmm1_zmm2() {
7568 let bytes = encode(
7570 "vpaddd",
7571 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7572 );
7573 assert_eq!(bytes, vec![0x62, 0xF1, 0x75, 0x48, 0xFE, 0xC2]);
7574 }
7575
7576 #[test]
7577 fn test_evex_vpaddq_zmm0_zmm1_zmm2() {
7578 let bytes = encode(
7580 "vpaddq",
7581 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7582 );
7583 assert_eq!(bytes, vec![0x62, 0xF1, 0xF5, 0x48, 0xD4, 0xC2]);
7584 }
7585
7586 #[test]
7587 fn test_evex_vpxord_zmm0_zmm1_zmm2() {
7588 let bytes = encode(
7589 "vpxord",
7590 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7591 );
7592 assert_eq!(bytes, vec![0x62, 0xF1, 0x75, 0x48, 0xEF, 0xC2]);
7593 }
7594
7595 #[test]
7596 fn test_evex_vpxorq_zmm0_zmm1_zmm2() {
7597 let bytes = encode(
7598 "vpxorq",
7599 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7600 );
7601 assert_eq!(bytes, vec![0x62, 0xF1, 0xF5, 0x48, 0xEF, 0xC2]);
7602 }
7603
7604 #[test]
7605 fn test_evex_vblendmps_zmm0_zmm1_zmm2() {
7606 let bytes = encode(
7608 "vblendmps",
7609 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7610 );
7611 assert_eq!(bytes, vec![0x62, 0xF2, 0x75, 0x48, 0x65, 0xC2]);
7612 }
7613
7614 #[test]
7615 fn test_evex_vpmullq_zmm0_zmm1_zmm2() {
7616 let bytes = encode(
7618 "vpmullq",
7619 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7620 );
7621 assert_eq!(bytes, vec![0x62, 0xF2, 0xF5, 0x48, 0x40, 0xC2]);
7622 }
7623
7624 #[test]
7627 fn test_evex_vaddps_zmm16_zmm17_zmm18() {
7628 let bytes = encode(
7638 "vaddps",
7639 vec![Register(Zmm16), Register(Zmm17), Register(Zmm18)],
7640 );
7641 assert_eq!(bytes, vec![0x62, 0xA1, 0x74, 0x40, 0x58, 0xC2]);
7642 }
7643
7644 #[test]
7645 fn test_evex_vmovaps_zmm31_zmm16() {
7646 let bytes = encode("vmovaps", vec![Register(Zmm31), Register(Zmm16)]);
7656 assert_eq!(bytes, vec![0x62, 0x21, 0x7C, 0x48, 0x28, 0xF8]);
7657 }
7658
7659 #[test]
7662 fn test_evex_vmovdqu8_zmm0_zmm1() {
7663 let bytes = encode("vmovdqu8", vec![Register(Zmm0), Register(Zmm1)]);
7666 assert_eq!(bytes, vec![0x62, 0xF1, 0x7F, 0x48, 0x6F, 0xC1]);
7667 }
7668
7669 #[test]
7670 fn test_evex_vmovdqu16_zmm0_zmm1() {
7671 let bytes = encode("vmovdqu16", vec![Register(Zmm0), Register(Zmm1)]);
7674 assert_eq!(bytes, vec![0x62, 0xF1, 0xFF, 0x48, 0x6F, 0xC1]);
7675 }
7676
7677 #[test]
7678 fn test_evex_vpsravq_zmm0_zmm1_zmm2() {
7679 let bytes = encode(
7681 "vpsravq",
7682 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7683 );
7684 assert_eq!(bytes, vec![0x62, 0xF2, 0xF5, 0x48, 0x46, 0xC2]);
7685 }
7686
7687 #[test]
7688 fn test_evex_vpandd_zmm0_zmm1_zmm2() {
7689 let bytes = encode(
7690 "vpandd",
7691 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7692 );
7693 assert_eq!(bytes, vec![0x62, 0xF1, 0x75, 0x48, 0xDB, 0xC2]);
7694 }
7695
7696 #[test]
7697 fn test_evex_vpord_zmm0_zmm1_zmm2() {
7698 let bytes = encode(
7699 "vpord",
7700 vec![Register(Zmm0), Register(Zmm1), Register(Zmm2)],
7701 );
7702 assert_eq!(bytes, vec![0x62, 0xF1, 0x75, 0x48, 0xEB, 0xC2]);
7703 }
7704
7705 #[test]
7708 fn test_vex_vaddps_xmm_still_works() {
7709 let bytes = encode(
7711 "vaddps",
7712 vec![Register(Xmm0), Register(Xmm1), Register(Xmm2)],
7713 );
7714 assert_eq!(bytes[0], 0xC5, "should be 2-byte VEX prefix");
7716 }
7717
7718 #[test]
7719 fn test_vex_vaddps_ymm_still_works() {
7720 let bytes = encode(
7722 "vaddps",
7723 vec![Register(Ymm0), Register(Ymm1), Register(Ymm2)],
7724 );
7725 assert_eq!(bytes[0], 0xC5, "should be 2-byte VEX prefix for ymm");
7727 }
7728
7729 #[test]
7732 fn test_evex_vcompressps_zmm0_zmm1() {
7733 let bytes = encode("vcompressps", vec![Register(Zmm0), Register(Zmm1)]);
7735 assert_eq!(bytes, vec![0x62, 0xF2, 0x7D, 0x48, 0x8A, 0xC1]);
7736 }
7737
7738 #[test]
7739 fn test_evex_vexpandps_zmm0_zmm1() {
7740 let bytes = encode("vexpandps", vec![Register(Zmm0), Register(Zmm1)]);
7742 assert_eq!(bytes, vec![0x62, 0xF2, 0x7D, 0x48, 0x88, 0xC1]);
7743 }
7744
7745 #[test]
7748 fn test_evex_vpshufd_zmm0_zmm1_imm() {
7749 let bytes = encode(
7752 "vpshufd",
7753 vec![Register(Zmm0), Register(Zmm1), Immediate(0xE4)],
7754 );
7755 assert_eq!(bytes, vec![0x62, 0xF1, 0x7D, 0x48, 0x70, 0xC1, 0xE4]);
7756 }
7757}