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