1#![allow(dead_code)]
2use super::emit::{self, PendingPrefixes};
3use super::emitter::{CallEmitter, JmpEmitter, MovEmitter};
4use super::operands::*;
5use crate::{
6 X86Error,
7 core::{
8 arch_traits::Arch,
9 buffer::{CodeBuffer, CodeOffset, ConstantData, LabelUse},
10 globals::InstOptions,
11 operand::*,
12 patch::{PatchBlockId, PatchSiteId},
13 target::Environment,
14 },
15};
16
17pub struct Assembler<'a> {
19 pub(crate) buffer: &'a mut CodeBuffer,
20 flags: u64,
21 extra_reg: Reg,
22}
23
24const RC_RN: u64 = 0x0000000;
25const RC_RD: u64 = 0x0800000;
26const RC_RU: u64 = 0x1000000;
27const RC_RZ: u64 = 0x1800000;
28const RC_MASK: u64 = RC_RD | RC_RU;
29const RC_ENABLED: u64 = 0x4000000;
30const SEG_MASK: u64 = 0xe0000000;
31const LONG: u64 = 0x100000000;
32
33const OPC_LOCK: u64 = 0x2000000000;
37const OPC_Z: u64 = 0x1000000000;
39
40impl crate::core::builder::InstSink for Assembler<'_> {
41 fn arch(&self) -> Arch {
42 self.environment().arch()
43 }
44
45 fn emit_inst(&mut self, inst: &crate::core::inst::Inst) -> Result<(), crate::AsmError> {
46 let ops = inst.operands();
47 let mut refs: smallvec::SmallVec<[&Operand; 6]> = smallvec::SmallVec::new();
48 refs.extend(ops.iter());
49
50 let extra_reg = inst.extra_reg();
51 let mask_id = match extra_reg.signature.try_op_type() {
52 Some(OperandType::None) if extra_reg.signature.bits() == 0 => 0,
53 Some(OperandType::Reg) if extra_reg.signature.try_reg_type() == Some(RegType::Mask) => {
54 extra_reg.id()
55 }
56 _ => {
57 return Err(X86Error::InvalidMasking {
58 mask_reg: extra_reg.id(),
59 reason: "x86 extra register must be a mask register",
60 }
61 .into());
62 }
63 };
64 self.try_emit_n_with_prefixes(
65 inst.id(),
66 &refs,
67 PendingPrefixes {
68 options: inst.options(),
69 segment_id: 0,
70 mask_id,
71 },
72 )
73 }
74
75 fn bind_label(&mut self, label: Label) -> Result<(), crate::AsmError> {
76 self.try_bind_label(label)
77 }
78}
79
80impl<'a> Assembler<'a> {
81 fn take_pending_prefixes(&mut self) -> PendingPrefixes {
85 let flags = self.flags;
86 self.flags = 0;
87
88 let mut prefixes = PendingPrefixes::default();
89 if flags & OPC_LOCK != 0 {
90 prefixes.options |= InstOptions::X86_LOCK;
91 }
92 if flags & 0x200000 != 0 {
93 prefixes.options |= InstOptions::X86_REP;
94 }
95 if flags & 0x100000 != 0 {
96 prefixes.options |= InstOptions::X86_REPNE;
97 }
98 if flags & LONG != 0 {
99 prefixes.options |= InstOptions::LONG_FORM;
100 }
101 if flags & OPC_Z != 0 {
102 prefixes.options |= InstOptions::X86_ZMASK;
103 }
104 if flags & RC_ENABLED != 0 {
105 let rc = flags & (RC_RD | RC_RU);
106 prefixes.options |= if rc == RC_RD {
107 InstOptions::X86_ER | InstOptions::X86_RD_SAE
108 } else if rc == RC_RU {
109 InstOptions::X86_ER | InstOptions::X86_RU_SAE
110 } else if rc == RC_RZ {
111 InstOptions::X86_ER | InstOptions::X86_RZ_SAE
112 } else {
113 InstOptions::X86_SAE
116 };
117 }
118 prefixes.segment_id = ((flags & SEG_MASK) >> 29) as u32;
119 prefixes.mask_id = ((flags >> 33) & 0x7) as u32;
120 prefixes
121 }
122
123 pub fn emit_n(&mut self, id: impl Into<u32>, ops: &[&Operand]) {
127 if let Err(error) = self.try_emit_n(id, ops) {
128 self.buffer.record_error(error);
129 }
130 }
131
132 pub fn try_emit_n(
133 &mut self,
134 id: impl Into<u32>,
135 ops: &[&Operand],
136 ) -> Result<(), crate::AsmError> {
137 if let Some(error) = self.buffer.error().cloned() {
138 return Err(error);
139 }
140 let prefixes = self.take_pending_prefixes();
141 self.try_emit_n_with_prefixes(id, ops, prefixes)
142 }
143
144 fn try_emit_n_with_prefixes(
145 &mut self,
146 id: impl Into<u32>,
147 ops: &[&Operand],
148 prefixes: PendingPrefixes,
149 ) -> Result<(), crate::AsmError> {
150 if let Some(error) = self.buffer.error().cloned() {
151 return Err(error);
152 }
153 let checkpoint = self.buffer.checkpoint();
154 if let Err(error) = emit::emit_n(self.buffer, id.into(), ops, prefixes, self.is_32bit()) {
155 self.buffer.rollback(checkpoint);
156 return Err(error);
157 }
158 Ok(())
159 }
160
161 pub fn new(buf: &'a mut CodeBuffer) -> Self {
162 if !matches!(buf.env().arch(), Arch::X86 | Arch::X64) {
163 return Self::poisoned(buf, crate::AsmError::InvalidArch);
164 }
165 Self::unchecked(buf)
166 }
167
168 pub fn try_new(buf: &'a mut CodeBuffer) -> Result<Self, crate::AsmError> {
169 if !matches!(buf.env().arch(), Arch::X86 | Arch::X64) {
170 return Err(crate::AsmError::InvalidArch);
171 }
172 Ok(Self::unchecked(buf))
173 }
174
175 fn unchecked(buf: &'a mut CodeBuffer) -> Self {
176 Self {
177 buffer: buf,
178 extra_reg: Reg::new(),
179 flags: 0,
180 }
181 }
182
183 fn poisoned(buf: &'a mut CodeBuffer, error: crate::AsmError) -> Self {
184 buf.record_error(error);
185 Self {
186 buffer: buf,
187 extra_reg: Reg::new(),
188 flags: 0,
189 }
190 }
191
192 pub fn environment(&self) -> &Environment {
194 self.buffer.env()
195 }
196
197 pub fn is_32bit(&self) -> bool {
199 self.buffer.env().is_32bit()
200 }
201
202 pub fn is_64bit(&self) -> bool {
204 self.buffer.env().is_64bit()
205 }
206
207 #[cfg(test)]
208 fn last_error(&self) -> Option<X86Error> {
209 match self.buffer.error() {
210 Some(crate::AsmError::X86(error)) => Some(error.clone()),
211 _ => None,
212 }
213 }
214
215 pub fn sae(&mut self) -> &mut Self {
216 self.set_rounding(RC_RN)
217 }
218
219 pub fn rn_sae(&mut self) -> &mut Self {
220 self.set_rounding(RC_RN)
221 }
222
223 pub fn rd_sae(&mut self) -> &mut Self {
224 self.set_rounding(RC_RD)
225 }
226 pub fn ru_sae(&mut self) -> &mut Self {
227 self.set_rounding(RC_RU)
228 }
229
230 pub fn rz_sae(&mut self) -> &mut Self {
231 self.set_rounding(RC_RZ)
232 }
233
234 fn set_rounding(&mut self, rounding: u64) -> &mut Self {
235 let mask = RC_ENABLED | RC_MASK;
236 let pending = self.flags & mask;
237 let requested = RC_ENABLED | rounding;
238 if pending != 0 && pending != requested {
239 self.buffer
240 .record_error(crate::AsmError::X86(X86Error::InvalidRoundingControl {
241 rc: requested,
242 reason: "conflicting pending rounding modes",
243 }));
244 return self;
245 }
246 self.flags = (self.flags & !mask) | requested;
247 self
248 }
249
250 pub fn seg(&mut self, sreg: SReg) -> &mut Self {
251 let segment_id = sreg.id();
252 if !(SReg::ES..=SReg::GS).contains(&segment_id) {
253 self.buffer
254 .record_error(crate::AsmError::X86(X86Error::InvalidPrefix {
255 prefix: segment_id as u64,
256 reason: "invalid segment override",
257 }));
258 return self;
259 }
260 let pending = (self.flags & SEG_MASK) >> 29;
261 if pending != 0 && pending != segment_id as u64 {
262 self.buffer
263 .record_error(crate::AsmError::X86(X86Error::InvalidPrefix {
264 prefix: segment_id as u64,
265 reason: "conflicting pending segment overrides",
266 }));
267 return self;
268 }
269 self.flags = (self.flags & !SEG_MASK) | (segment_id as u64) << 29;
270 self
271 }
272
273 pub fn fs(&mut self) -> &mut Self {
274 self.seg(FS)
275 }
276
277 pub fn gs(&mut self) -> &mut Self {
278 self.seg(GS)
279 }
280
281 pub fn k(&mut self, k: KReg) -> &mut Self {
282 let mask_id = k.id();
283 if !(1..=7).contains(&mask_id) {
284 self.buffer
285 .record_error(crate::AsmError::X86(X86Error::InvalidMasking {
286 mask_reg: mask_id,
287 reason: "mask register must be k1..k7",
288 }));
289 return self;
290 }
291 let pending = (self.flags >> 33) & 0x7;
292 if pending != 0 && pending != mask_id as u64 {
293 self.buffer
294 .record_error(crate::AsmError::X86(X86Error::InvalidMasking {
295 mask_reg: mask_id,
296 reason: "conflicting pending mask registers",
297 }));
298 return self;
299 }
300 self.flags = (self.flags & !(0x7 << 33)) | (mask_id as u64) << 33;
301
302 self
303 }
304
305 pub fn z(&mut self) -> &mut Self {
307 self.flags |= OPC_Z;
308 self
309 }
310
311 pub fn rep(&mut self) -> &mut Self {
312 self.flags |= 0x200000;
313 self
314 }
315
316 pub fn repnz(&mut self) -> &mut Self {
317 self.flags |= 0x100000;
318 self
319 }
320
321 pub fn repz(&mut self) -> &mut Self {
322 self.rep()
323 }
324
325 pub fn lock(&mut self) -> &mut Self {
326 self.flags |= OPC_LOCK;
327 self
328 }
329
330 pub fn long(&mut self) -> &mut Self {
331 self.flags |= LONG;
332 self
333 }
334
335 pub fn get_label(&mut self) -> Label {
336 self.buffer.get_label()
337 }
338
339 pub fn bind_label(&mut self, label: Label) {
340 if let Err(error) = self.try_bind_label(label) {
341 self.buffer.record_error(error);
342 }
343 }
344
345 pub fn try_bind_label(&mut self, label: Label) -> Result<(), crate::AsmError> {
346 self.buffer.try_bind_label(label)
347 }
348
349 pub fn add_constant(&mut self, c: impl Into<ConstantData>) -> Label {
350 let c = self.buffer.add_constant(c);
351 self.buffer.get_label_for_constant(c)
352 }
353
354 pub fn label_offset(&self, label: Label) -> CodeOffset {
355 self.buffer.label_offset(label)
356 }
357
358 pub fn data(&self) -> &[u8] {
359 self.buffer.data()
360 }
361
362 pub fn error(&self) -> Option<&crate::AsmError> {
363 self.buffer.error()
364 }
365
366 pub fn patchable_jmp(&mut self, label: Label) -> PatchSiteId {
367 self.long();
368 self.jmp(label);
369 let offset = self
370 .buffer
371 .cur_offset()
372 .saturating_sub(LabelUse::X86JmpRel32.patch_size() as u32);
373 self.buffer
374 .record_label_patch_site(offset, label, LabelUse::X86JmpRel32)
375 }
376
377 pub fn patchable_call(&mut self, label: Label) -> PatchSiteId {
378 self.long();
379 self.call(label);
380 let offset = self
381 .buffer
382 .cur_offset()
383 .saturating_sub(LabelUse::X86JmpRel32.patch_size() as u32);
384 self.buffer
385 .record_label_patch_site(offset, label, LabelUse::X86JmpRel32)
386 }
387
388 pub fn patchable_mov<A, B>(&mut self, dst: A, src: B) -> PatchBlockId
389 where
390 A: OperandCast + Copy,
391 B: OperandCast + Copy,
392 Self: MovEmitter<A, B>,
393 {
394 let dst_op = *dst.as_operand();
395 let src_op = *src.as_operand();
396 let size = if dst_op.is_reg_type_of(RegType::Gp64) {
397 8
398 } else if dst_op.is_reg_type_of(RegType::Gp32) {
399 4
400 } else {
401 self.buffer
402 .record_error(crate::AsmError::X86(X86Error::InvalidOperand {
403 operand_index: 0,
404 reason: "patchable_mov requires a Gp32 or Gp64 destination",
405 }));
406 return PatchBlockId::from_index(usize::MAX);
407 };
408
409 if !src_op.is_imm() {
410 self.buffer
411 .record_error(crate::AsmError::X86(X86Error::InvalidOperand {
412 operand_index: 1,
413 reason: "patchable_mov requires an immediate source",
414 }));
415 return PatchBlockId::from_index(usize::MAX);
416 }
417
418 let offset = self.buffer.cur_offset();
419 let previous_error = self.buffer.error().cloned();
420 self.long();
421 MovEmitter::mov(self, dst, src);
422 if self.buffer.error().cloned() != previous_error
423 || self.buffer.cur_offset() < offset + size
424 {
425 return PatchBlockId::from_index(usize::MAX);
426 }
427
428 let offset = self.buffer.cur_offset() - size;
429 self.buffer.record_patch_block(offset, size, 1)
430 }
431}
432
433#[derive(Debug, Clone, Copy, PartialEq, Eq)]
434pub enum CondCode {
435 O = 0x0,
436 NO = 0x1,
437 C = 0x2,
438 NC = 0x3,
439 Z = 0x4,
440 NZ = 0x5,
441 BE = 0x6,
442 A = 0x7,
443 S = 0x8,
444 NS = 0x9,
445 P = 0xa,
446
447 NP = 0xb,
448 L = 0xc,
449 GE = 0xd,
450 LE = 0xe,
451 G = 0xf,
452}
453
454impl CondCode {
455 pub const B: Self = Self::C;
456 pub const NAE: Self = Self::C;
457 pub const AE: Self = Self::NC;
458 pub const NB: Self = Self::NC;
459 pub const E: Self = Self::Z;
460 pub const NE: Self = Self::NZ;
461 pub const NA: Self = Self::BE;
462 pub const NBE: Self = Self::A;
463 pub const PO: Self = Self::NP;
464 pub const NGE: Self = Self::L;
465 pub const NL: Self = Self::GE;
466 pub const NG: Self = Self::LE;
467 pub const NLE: Self = Self::G;
468 pub const PE: Self = Self::P;
469
470 pub const fn code(self) -> u8 {
471 self as u8
472 }
473
474 pub fn invert(self) -> Self {
475 match self {
476 Self::O => Self::NO,
477 Self::NO => Self::O,
478 Self::C => Self::NC,
479 Self::NC => Self::C,
480 Self::Z => Self::NZ,
481 Self::NZ => Self::Z,
482 Self::BE => Self::A,
483 Self::A => Self::BE,
484 Self::S => Self::NS,
485 Self::NS => Self::S,
486 Self::P => Self::NP,
487 Self::NP => Self::P,
488 Self::L => Self::GE,
489 Self::GE => Self::L,
490 Self::LE => Self::G,
491 Self::G => Self::LE,
492 }
493 }
494}
495
496#[cfg(test)]
497mod tests {
498 use super::*;
499 use crate::core::builder::Builder;
500 use crate::core::inst::Inst;
501 use crate::x86::instdb::InstId;
502 use crate::x86::operands::regs::*;
503
504 fn asm(f: impl FnOnce(&mut Assembler)) -> std::vec::Vec<u8> {
506 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
507 {
508 let mut a = Assembler::new(&mut buf);
509 f(&mut a);
510 assert!(a.last_error().is_none(), "{:?}", a.last_error());
511 }
512 buf.finish().unwrap().data().to_vec()
513 }
514
515 #[test]
516 fn emit_n_integer_forms() {
517 assert_eq!(
519 asm(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), imm(1).as_operand()])),
520 [0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00]
521 );
522 assert_eq!(
524 asm(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), RBX.as_operand()])),
525 [0x48, 0x89, 0xD8]
526 );
527 assert_eq!(
529 asm(|a| a.emit_n(InstId::Add as u32, &[RAX.as_operand(), RBX.as_operand()])),
530 [0x48, 0x01, 0xD8]
531 );
532 assert_eq!(
534 asm(|a| a.emit_n(InstId::Push as u32, &[RAX.as_operand()])),
535 [0x50]
536 );
537 assert_eq!(
538 asm(|a| a.emit_n(InstId::Pop as u32, &[RAX.as_operand()])),
539 [0x58]
540 );
541 assert_eq!(
543 asm(|a| a.emit_n(InstId::Cmovz as u32, &[RAX.as_operand(), RBX.as_operand()])),
544 [0x48, 0x0F, 0x44, 0xC3]
545 );
546 assert_eq!(asm(|a| a.emit_n(InstId::Ret as u32, &[])), [0xC3]);
548 assert_eq!(asm(|a| a.emit_n(InstId::Syscall as u32, &[])), [0x0F, 0x05]);
549 assert_eq!(
551 asm(|a| a.emit_n(
552 InstId::Mov as u32,
553 &[RAX.as_operand(), imm(0x1_2345_6789i64).as_operand()]
554 )),
555 [0x48, 0xB8, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00, 0x00, 0x00]
556 );
557 }
558
559 #[test]
560 fn emit_n_invalid_sets_last_error() {
561 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
562 let mut a = Assembler::new(&mut buf);
563 a.emit_n(InstId::Add as u32, &[RAX.as_operand(), XMM0.as_operand()]);
565 assert!(matches!(
566 a.last_error(),
567 Some(X86Error::InvalidInstruction { .. })
568 ));
569 assert!(a.buffer.data().is_empty());
570 a.buffer.clear();
572 a.emit_n(u32::MAX, &[]);
573 assert!(a.last_error().is_some());
574 }
575
576 #[test]
577 fn raw_invalid_symbol_id_is_rejected() {
578 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
579 let mut a = Assembler::new(&mut buf);
580 let mut operand = Operand::new();
581 operand.set_signature(OperandSignature::from(0x001A_0012));
582
583 assert_eq!(
584 a.try_emit_n(727u32, &[&operand]),
585 Err(crate::AsmError::X86(X86Error::InvalidOperand {
586 operand_index: 0,
587 reason: "symbol is not declared in this buffer",
588 }))
589 );
590 assert!(a.buffer.data().is_empty());
591
592 a.emit_n(727u32, &[&operand]);
593 assert_eq!(
594 a.buffer.error(),
595 Some(&crate::AsmError::X86(X86Error::InvalidOperand {
596 operand_index: 0,
597 reason: "symbol is not declared in this buffer",
598 }))
599 );
600 assert!(a.buffer.data().is_empty());
601 }
602
603 #[test]
604 fn emit_n_rejects_more_than_six_operands() {
605 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
606 let mut a = Assembler::new(&mut buf);
607 let ops = [RAX.as_operand(); 7];
608
609 a.emit_n(InstId::Ret as u32, &ops);
610
611 assert!(a.last_error().is_some());
612 assert!(a.buffer.data().is_empty());
613 }
614
615 #[test]
616 fn patchable_mov_emits_once_and_rejects_unsupported_operands() {
617 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
618 {
619 let mut a = Assembler::new(&mut buf);
620 a.patchable_mov(EAX, imm(42));
621 assert_eq!(a.buffer.data(), &[0xB8, 42, 0, 0, 0]);
622 assert!(a.last_error().is_none());
623
624 a.patchable_mov(RAX, imm(42));
625 assert_eq!(
626 a.buffer.data(),
627 &[0xB8, 42, 0, 0, 0, 0x48, 0xB8, 42, 0, 0, 0, 0, 0, 0, 0]
628 );
629
630 a.patchable_mov(RAX, RBX);
631 assert!(matches!(
632 a.last_error(),
633 Some(X86Error::InvalidOperand {
634 operand_index: 1,
635 ..
636 })
637 ));
638 assert_eq!(
639 a.buffer.data(),
640 &[0xB8, 42, 0, 0, 0, 0x48, 0xB8, 42, 0, 0, 0, 0, 0, 0, 0]
641 );
642 }
643
644 assert!(matches!(
645 buf.finish_patched(),
646 Err(crate::AsmError::X86(X86Error::InvalidOperand {
647 operand_index: 1,
648 ..
649 }))
650 ));
651 }
652
653 #[test]
654 fn emit_n_memory_forms() {
655 assert_eq!(
657 asm(|a| a.emit_n(
658 InstId::Mov as u32,
659 &[RAX.as_operand(), qword_ptr_rip(0x1234).as_operand()]
660 )),
661 [0x48, 0x8B, 0x05, 0x34, 0x12, 0x00, 0x00]
662 );
663 assert_eq!(
665 asm(|a| {
666 let label = a.get_label();
667 a.emit_n(
668 InstId::Mov as u32,
669 &[dword_ptr_label(label, 0).as_operand(), EAX.as_operand()],
670 );
671 a.bind_label(label);
672 a.emit_n(InstId::Ret as u32, &[]);
673 }),
674 [0x89, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC3]
675 );
676 assert_eq!(
678 asm(|a| {
679 a.fs();
680 a.emit_n(
681 InstId::Mov as u32,
682 &[RAX.as_operand(), qword_ptr_u64(0x40).as_operand()],
683 );
684 }),
685 [0x64, 0x48, 0x8B, 0x04, 0x25, 0x40, 0x00, 0x00, 0x00]
686 );
687 }
688
689 #[test]
690 fn emit_n_branch_forms() {
691 assert_eq!(
693 asm(|a| {
694 let label = a.get_label();
695 a.bind_label(label);
696 a.emit_n(
697 InstId::Jmp as u32,
698 &[Label::from_id(label.id()).as_operand()],
699 );
700 }),
701 [0xEB, 0xFE]
702 );
703 assert_eq!(
705 asm(|a| {
706 let label = a.get_label();
707 a.emit_n(
708 InstId::Jmp as u32,
709 &[Label::from_id(label.id()).as_operand()],
710 );
711 a.bind_label(label);
712 }),
713 [0xEB, 0x00]
714 );
715 assert_eq!(
717 asm(|a| {
718 let label = a.get_label();
719 a.emit_n(
720 InstId::Call as u32,
721 &[Label::from_id(label.id()).as_operand()],
722 );
723 a.bind_label(label);
724 }),
725 [0xE8, 0x00, 0x00, 0x00, 0x00]
726 );
727 }
728
729 #[test]
730 fn patchable_branches_keep_the_near_form() {
731 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
732 let target = buf.get_label();
733 let site = {
734 let mut asm = Assembler::new(&mut buf);
735 asm.patchable_jmp(target)
736 };
737 buf.bind_label(target);
738
739 let code = buf.finish_patched().unwrap();
740 assert_eq!(code.data(), &[0xE9, 0, 0, 0, 0]);
741 let site = code.patch_catalog().site(site).unwrap();
742 assert_eq!(site.offset, 1);
743 assert_eq!(site.current_target, 5);
744 }
745
746 #[test]
747 fn emit_n_vex_evex_forms() {
748 assert_eq!(
750 asm(|a| a.emit_n(
751 InstId::Vaddps as u32,
752 &[YMM1.as_operand(), YMM2.as_operand(), YMM3.as_operand()]
753 )),
754 [0xC5, 0xEC, 0x58, 0xCB]
755 );
756 assert_eq!(
758 asm(|a| a.emit_n(
759 InstId::Vmovdqu as u32,
760 &[YMM0.as_operand(), YMM1.as_operand()]
761 )),
762 [0xC5, 0xFE, 0x6F, 0xC1]
763 );
764 assert_eq!(
766 asm(|a| a.emit_n(
767 InstId::Vaddpd as u32,
768 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()]
769 )),
770 [0x62, 0xF1, 0xED, 0x48, 0x58, 0xCB]
771 );
772 assert_eq!(
774 asm(|a| {
775 a.k(K1);
776 a.emit_n(
777 InstId::Vaddpd as u32,
778 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()],
779 );
780 }),
781 [0x62, 0xF1, 0xED, 0x49, 0x58, 0xCB]
782 );
783 }
784
785 #[test]
786 fn emitter_traits_match_emit_n() {
787 use crate::x86::emitter::{AddEmitter, JmpEmitter, MovEmitter, VaddpsEmitter};
790
791 assert_eq!(
793 asm(|a| MovEmitter::mov(a, RAX, imm(1))),
794 [0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00]
795 );
796 assert_eq!(asm(|a| MovEmitter::mov(a, RAX, RBX)), [0x48, 0x89, 0xD8]);
798 assert_eq!(asm(|a| AddEmitter::add(a, RAX, RBX)), [0x48, 0x01, 0xD8]);
800 assert_eq!(
802 asm(|a| VaddpsEmitter::vaddps(a, YMM1, YMM2, YMM3)),
803 [0xC5, 0xEC, 0x58, 0xCB]
804 );
805 assert_eq!(
807 asm(|a| {
808 let label = a.get_label();
809 a.bind_label(label);
810 JmpEmitter::jmp(a, label);
811 }),
812 [0xEB, 0xFE]
813 );
814 }
815
816 #[test]
817 fn emitter_typed_call_sites() {
818 use crate::x86::emitter::{AddEmitter, MovEmitter, PaddwEmitter, VaddpsEmitter};
821
822 assert_eq!(
824 asm(|a| MovEmitter::mov(a, RAX, 42)),
825 [0x48, 0xC7, 0xC0, 0x2A, 0x00, 0x00, 0x00]
826 );
827 assert_eq!(
829 asm(|a| MovEmitter::mov(a, EAX, 42)),
830 [0xB8, 0x2A, 0x00, 0x00, 0x00]
831 );
832 assert_eq!(asm(|a| AddEmitter::add(a, RAX, RBX)), [0x48, 0x01, 0xD8]);
834 assert_eq!(
836 asm(|a| PaddwEmitter::paddw(a, XMM0, XMM1)),
837 [0x66, 0x0F, 0xFD, 0xC1]
838 );
839 assert_eq!(
841 asm(|a| VaddpsEmitter::vaddps(a, YMM1, YMM2, YMM3)),
842 [0xC5, 0xEC, 0x58, 0xCB]
843 );
844 }
845
846 #[test]
847 fn emit_n_prefix_forms() {
848 assert_eq!(
850 asm(|a| {
851 a.rep();
852 a.emit_n(
853 InstId::Movs as u32,
854 &[
855 qword_ptr(RDI, 0).as_operand(),
856 qword_ptr(RSI, 0).as_operand(),
857 ],
858 );
859 }),
860 [0xF3, 0x48, 0xA5]
861 );
862 assert_eq!(
864 asm(|a| {
865 a.lock();
866 a.emit_n(
867 InstId::Add as u32,
868 &[dword_ptr(RBX, 0).as_operand(), EAX.as_operand()],
869 );
870 }),
871 [0xF0, 0x01, 0x03]
872 );
873 }
874
875 #[test]
876 fn conflicting_prefix_setters_poison_without_emitting() {
877 let cases: &[fn(&mut Assembler<'_>)] = &[
878 |a| {
879 a.fs().gs();
880 },
881 |a| {
882 a.k(K1).k(K2);
883 },
884 |a| {
885 a.rd_sae().ru_sae();
886 },
887 |a| {
888 a.seg(sreg(7));
889 },
890 |a| {
891 a.k(k(8));
892 },
893 |a| {
894 a.k(K0);
895 },
896 ];
897
898 for set_prefixes in cases {
899 let mut buffer = CodeBuffer::new(Environment::new(Arch::X64));
900 let mut assembler = Assembler::new(&mut buffer);
901 set_prefixes(&mut assembler);
902 assembler.emit_n(InstId::Ret as u32, &[]);
903 assert!(assembler.buffer.error().is_some());
904 assert!(assembler.buffer.data().is_empty());
905 }
906 }
907
908 #[test]
909 fn emit_n_builder_replay_matches_direct() {
910 fn direct() -> std::vec::Vec<u8> {
911 asm(|a| {
912 let done = a.get_label();
913 a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), imm(1).as_operand()]);
914 a.emit_n(InstId::Add as u32, &[RAX.as_operand(), RBX.as_operand()]);
915 a.emit_n(
916 InstId::Jmp as u32,
917 &[Label::from_id(done.id()).as_operand()],
918 );
919 a.emit_n(InstId::Ret as u32, &[]);
920 a.bind_label(done);
921 a.emit_n(InstId::Ret as u32, &[]);
922 })
923 }
924
925 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
926 let mut builder = Builder::new();
927 let done = buf.get_label();
928 builder
929 .push_inst(Inst::with_operands(
930 InstId::Mov as u32,
931 &[*RAX.as_operand(), *imm(1).as_operand()],
932 ))
933 .unwrap();
934 builder
935 .push_inst(Inst::with_operands(
936 InstId::Add as u32,
937 &[*RAX.as_operand(), *RBX.as_operand()],
938 ))
939 .unwrap();
940 builder
941 .push_inst(Inst::with_operands(
942 InstId::Jmp as u32,
943 &[*Label::from_id(done.id()).as_operand()],
944 ))
945 .unwrap();
946 builder
947 .push_inst(Inst::with_operands(InstId::Ret as u32, &[]))
948 .unwrap();
949 builder.push_label(done);
950 builder
951 .push_inst(Inst::with_operands(InstId::Ret as u32, &[]))
952 .unwrap();
953 {
954 let mut a = Assembler::new(&mut buf);
955 builder.emit_into(&mut a).unwrap();
956 assert!(a.last_error().is_none(), "{:?}", a.last_error());
957 }
958 assert_eq!(buf.finish().unwrap().data().to_vec(), direct());
959 }
960
961 #[test]
962 fn builder_replays_options_and_mask_register() {
963 let direct = asm(|a| {
964 a.k(K1).z();
965 a.emit_n(
966 InstId::Vaddpd as u32,
967 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()],
968 );
969 });
970
971 let mut inst = Inst::with_arch_operands(
972 Arch::X64,
973 InstId::Vaddpd as u32,
974 &[*ZMM1.as_operand(), *ZMM2.as_operand(), *ZMM3.as_operand()],
975 )
976 .unwrap();
977 inst.set_options(InstOptions::X86_ZMASK);
978 inst.set_extra_reg(*K1.as_operand());
979 let mut builder = Builder::for_arch(Arch::X64);
980 builder.push_inst(inst).unwrap();
981
982 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
983 builder.emit_into(&mut Assembler::new(&mut buf)).unwrap();
984 assert_eq!(buf.finish().unwrap().data(), direct);
985 }
986
987 fn asm32(f: impl FnOnce(&mut Assembler)) -> std::vec::Vec<u8> {
989 let mut buf = CodeBuffer::new(Environment::new(Arch::X86));
990 {
991 let mut a = Assembler::new(&mut buf);
992 f(&mut a);
993 assert!(a.last_error().is_none(), "{:?}", a.last_error());
994 }
995 buf.finish().unwrap().data().to_vec()
996 }
997
998 fn asm32_err(f: impl FnOnce(&mut Assembler)) -> X86Error {
1000 let mut buf = CodeBuffer::new(Environment::new(Arch::X86));
1001 let mut a = Assembler::new(&mut buf);
1002 f(&mut a);
1003 a.last_error().expect("expected an emit error")
1004 }
1005
1006 fn asm64_err(f: impl FnOnce(&mut Assembler)) -> X86Error {
1008 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
1009 let mut a = Assembler::new(&mut buf);
1010 f(&mut a);
1011 a.last_error().expect("expected an emit error")
1012 }
1013
1014 #[test]
1015 fn emit_n_32bit_gp_forms() {
1016 use crate::x86::emitter::{AddEmitter, MovEmitter};
1017
1018 assert_eq!(asm32(|a| MovEmitter::mov(a, EAX, EBX)), [0x89, 0xD8]);
1020 assert_eq!(asm32(|a| MovEmitter::mov(a, AX, BX)), [0x66, 0x89, 0xD8]);
1022 assert_eq!(asm32(|a| MovEmitter::mov(a, AL, BL)), [0x88, 0xD8]);
1023 assert_eq!(
1025 asm32(|a| a.emit_n(InstId::Add as u32, &[ECX.as_operand(), imm(1).as_operand()])),
1026 [0x83, 0xC1, 0x01]
1027 );
1028 assert_eq!(
1029 asm32(|a| AddEmitter::add(a, EAX, 0x1234_5678i32)),
1030 [0x05, 0x78, 0x56, 0x34, 0x12]
1031 );
1032 assert_eq!(
1034 asm32(|a| MovEmitter::mov(a, EAX, 0x1234_5678i32)),
1035 [0xB8, 0x78, 0x56, 0x34, 0x12]
1036 );
1037 assert_eq!(
1038 asm32(|a| MovEmitter::mov(a, AX, 0x1234)),
1039 [0x66, 0xB8, 0x34, 0x12]
1040 );
1041 assert_eq!(asm32(|a| MovEmitter::mov(a, CL, 0x12)), [0xB1, 0x12]);
1042 }
1043
1044 #[test]
1045 fn emit_n_32bit_inc_dec_short_forms() {
1046 use crate::x86::emitter::{DecEmitter, IncEmitter};
1047
1048 assert_eq!(asm32(|a| IncEmitter::inc(a, EAX)), [0x40]);
1050 assert_eq!(asm32(|a| IncEmitter::inc(a, ECX)), [0x41]);
1051 assert_eq!(asm32(|a| IncEmitter::inc(a, AX)), [0x66, 0x40]);
1052 assert_eq!(asm32(|a| DecEmitter::dec(a, EDX)), [0x4A]);
1053 assert_eq!(asm32(|a| DecEmitter::dec(a, DX)), [0x66, 0x4A]);
1054 assert_eq!(asm32(|a| IncEmitter::inc(a, AL)), [0xFE, 0xC0]);
1056 assert_eq!(
1057 asm32(|a| IncEmitter::inc(a, dword_ptr(ECX, 0))),
1058 [0xFF, 0x01]
1059 );
1060 assert_eq!(
1062 asm(|a| a.emit_n(InstId::Inc as u32, &[EAX.as_operand()])),
1063 [0xFF, 0xC0]
1064 );
1065 }
1066
1067 #[test]
1068 fn emit_n_32bit_push_pop() {
1069 use crate::x86::emitter::{PopEmitter, PushEmitter};
1070
1071 assert_eq!(asm32(|a| PushEmitter::push(a, EAX)), [0x50]);
1072 assert_eq!(asm32(|a| PushEmitter::push(a, AX)), [0x66, 0x50]);
1073 assert_eq!(asm32(|a| PopEmitter::pop(a, ECX)), [0x59]);
1074 assert_eq!(
1075 asm32(|a| PushEmitter::push(a, 0x1234_5678i32)),
1076 [0x68, 0x78, 0x56, 0x34, 0x12]
1077 );
1078 assert_eq!(
1079 asm32(|a| PushEmitter::push(a, dword_ptr(ECX, 0))),
1080 [0xFF, 0x31]
1081 );
1082 assert_eq!(
1083 asm32(|a| PushEmitter::push(a, word_ptr(ECX, 0))),
1084 [0x66, 0xFF, 0x31]
1085 );
1086 asm32_err(|a| PushEmitter::push(a, qword_ptr(ECX, 0)));
1088 asm32_err(|a| PopEmitter::pop(a, qword_ptr(ECX, 0)));
1089 }
1090
1091 #[test]
1092 fn emit_n_32bit_far_pointer_forms() {
1093 assert_eq!(
1095 asm32(|a| a.emit_n(
1096 InstId::Lcall as u32,
1097 &[imm(0x1234).as_operand(), imm(0x1234_5678).as_operand()]
1098 )),
1099 [0x9A, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12]
1100 );
1101 assert_eq!(
1102 asm32(|a| a.emit_n(
1103 InstId::Ljmp as u32,
1104 &[imm(0x10).as_operand(), imm(0x20).as_operand()]
1105 )),
1106 [0xEA, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00]
1107 );
1108 asm32_err(|a| {
1110 a.emit_n(
1111 InstId::Lcall as u32,
1112 &[imm(0x1_0000).as_operand(), imm(0).as_operand()],
1113 )
1114 });
1115 asm64_err(|a| {
1117 a.emit_n(
1118 InstId::Lcall as u32,
1119 &[imm(0x1234).as_operand(), imm(0x1234_5678).as_operand()],
1120 )
1121 });
1122 assert_eq!(
1124 asm32(|a| a.emit_n(InstId::Lcall as u32, &[fword_ptr(ECX, 0).as_operand()])),
1125 [0xFF, 0x19]
1126 );
1127 }
1128
1129 #[test]
1130 fn emit_n_32bit_movabs_and_xchg() {
1131 use crate::x86::emitter::{MovEmitter, XchgEmitter};
1132
1133 assert_eq!(
1135 asm32(|a| MovEmitter::mov(a, EAX, dword_ptr_u64(0x1234_5678))),
1136 [0xA1, 0x78, 0x56, 0x34, 0x12]
1137 );
1138 assert_eq!(
1140 asm32(|a| MovEmitter::mov(a, dword_ptr_u64(0x1234_5678), EAX)),
1141 [0xA3, 0x78, 0x56, 0x34, 0x12]
1142 );
1143 assert_eq!(asm32(|a| XchgEmitter::xchg(a, EAX, EAX)), [0x90]);
1145 assert_eq!(
1146 asm(|a| a.emit_n(InstId::Xchg as u32, &[EAX.as_operand(), EAX.as_operand()])),
1147 [0x87, 0xC0]
1148 );
1149 }
1150
1151 #[test]
1152 fn emit_n_32bit_creg_lock_extension() {
1153 assert_eq!(
1155 asm32(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), CR8.as_operand()])),
1156 [0xF0, 0x0F, 0x20, 0xC0]
1157 );
1158 assert_eq!(
1159 asm32(|a| a.emit_n(InstId::Mov as u32, &[CR8.as_operand(), EAX.as_operand()])),
1160 [0xF0, 0x0F, 0x22, 0xC0]
1161 );
1162 assert_eq!(
1164 asm32(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), CR0.as_operand()])),
1165 [0x0F, 0x20, 0xC0]
1166 );
1167 }
1168
1169 #[test]
1170 fn emit_n_32bit_mode_gating() {
1171 asm32_err(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), RBX.as_operand()]));
1173 asm32_err(|a| a.emit_n(InstId::Push as u32, &[RAX.as_operand()]));
1174 asm32_err(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), R8D.as_operand()]));
1176 asm32_err(|a| {
1177 a.emit_n(
1178 InstId::Paddw as u32,
1179 &[XMM0.as_operand(), XMM8.as_operand()],
1180 )
1181 });
1182 asm32_err(|a| a.emit_n(InstId::Syscall as u32, &[]));
1184 asm32_err(|a| a.emit_n(InstId::Movsxd as u32, &[EAX.as_operand(), EBX.as_operand()]));
1185 asm32_err(|a| {
1187 a.emit_n(
1188 InstId::Mov as u32,
1189 &[EAX.as_operand(), dword_ptr(RBX, 0).as_operand()],
1190 )
1191 });
1192 asm32_err(|a| {
1194 a.emit_n(
1195 InstId::Mov as u32,
1196 &[EAX.as_operand(), dword_ptr_u64(0x1_0000_0000).as_operand()],
1197 )
1198 });
1199 }
1200
1201 #[test]
1202 fn emit_n_32bit_string_ops() {
1203 assert_eq!(
1205 asm32(|a| a.emit_n(
1206 InstId::Movs as u32,
1207 &[
1208 dword_ptr(EDI, 0).as_operand(),
1209 dword_ptr(ESI, 0).as_operand()
1210 ]
1211 )),
1212 [0xA5]
1213 );
1214 assert_eq!(
1216 asm32(|a| a.emit_n(
1217 InstId::Jecxz as u32,
1218 &[CX.as_operand(), imm(-2).as_operand()],
1219 )),
1220 [0x67, 0xE3, 0xFE]
1221 );
1222 }
1223}