1#![allow(dead_code)]
2use super::emit::{self, PendingPrefixes};
3use super::emitter::{CallEmitter, JmpEmitter, MovEmitter};
4use super::instdb::InstId;
5use super::operands::*;
6use crate::{
7 X86Error,
8 core::{
9 arch_traits::Arch,
10 buffer::{CodeBuffer, CodeOffset, ConstantData, LabelUse},
11 globals::InstOptions,
12 operand::*,
13 patch::{PatchableBlock, PatchableSite},
14 target::Environment,
15 },
16};
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) };
469 }
470
471 let offset = self.buffer.cur_offset();
472 let previous_error = self.buffer.error().cloned();
473 self.long();
474 MovEmitter::mov(self, dst, src);
475 if self.buffer.error().cloned() != previous_error
476 || self.buffer.cur_offset() < offset + size
477 {
478 return unsafe { PatchableBlock::new(u32::MAX, size, arch) };
481 }
482
483 let offset = self.buffer.cur_offset() - size;
484 let _ = self.buffer.record_patch_block(offset, size, 1);
485 unsafe { PatchableBlock::new(offset, size, arch) }
487 }
488}
489
490#[derive(Debug, Clone, Copy, PartialEq, Eq)]
491pub enum CondCode {
492 O = 0x0,
493 NO = 0x1,
494 C = 0x2,
495 NC = 0x3,
496 Z = 0x4,
497 NZ = 0x5,
498 BE = 0x6,
499 A = 0x7,
500 S = 0x8,
501 NS = 0x9,
502 P = 0xa,
503
504 NP = 0xb,
505 L = 0xc,
506 GE = 0xd,
507 LE = 0xe,
508 G = 0xf,
509}
510
511impl CondCode {
512 pub const B: Self = Self::C;
513 pub const NAE: Self = Self::C;
514 pub const AE: Self = Self::NC;
515 pub const NB: Self = Self::NC;
516 pub const E: Self = Self::Z;
517 pub const NE: Self = Self::NZ;
518 pub const NA: Self = Self::BE;
519 pub const NBE: Self = Self::A;
520 pub const PO: Self = Self::NP;
521 pub const NGE: Self = Self::L;
522 pub const NL: Self = Self::GE;
523 pub const NG: Self = Self::LE;
524 pub const NLE: Self = Self::G;
525 pub const PE: Self = Self::P;
526
527 pub const fn code(self) -> u8 {
528 self as u8
529 }
530
531 pub fn invert(self) -> Self {
532 match self {
533 Self::O => Self::NO,
534 Self::NO => Self::O,
535 Self::C => Self::NC,
536 Self::NC => Self::C,
537 Self::Z => Self::NZ,
538 Self::NZ => Self::Z,
539 Self::BE => Self::A,
540 Self::A => Self::BE,
541 Self::S => Self::NS,
542 Self::NS => Self::S,
543 Self::P => Self::NP,
544 Self::NP => Self::P,
545 Self::L => Self::GE,
546 Self::GE => Self::L,
547 Self::LE => Self::G,
548 Self::G => Self::LE,
549 }
550 }
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use crate::core::builder::Builder;
557 use crate::core::inst::Inst;
558 use crate::x86::instdb::InstId;
559 use crate::x86::operands::regs::*;
560
561 fn asm(f: impl FnOnce(&mut Assembler)) -> std::vec::Vec<u8> {
563 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
564 {
565 let mut a = Assembler::new(&mut buf);
566 f(&mut a);
567 assert!(a.last_error().is_none(), "{:?}", a.last_error());
568 }
569 buf.finish().unwrap().data().to_vec()
570 }
571
572 #[test]
573 fn emit_n_integer_forms() {
574 assert_eq!(
576 asm(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), imm(1).as_operand()])),
577 [0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00]
578 );
579 assert_eq!(
581 asm(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), RBX.as_operand()])),
582 [0x48, 0x89, 0xD8]
583 );
584 assert_eq!(
586 asm(|a| a.emit_n(InstId::Add as u32, &[RAX.as_operand(), RBX.as_operand()])),
587 [0x48, 0x01, 0xD8]
588 );
589 assert_eq!(
591 asm(|a| a.emit_n(InstId::Push as u32, &[RAX.as_operand()])),
592 [0x50]
593 );
594 assert_eq!(
595 asm(|a| a.emit_n(InstId::Pop as u32, &[RAX.as_operand()])),
596 [0x58]
597 );
598 assert_eq!(
600 asm(|a| a.emit_n(InstId::Cmovz as u32, &[RAX.as_operand(), RBX.as_operand()])),
601 [0x48, 0x0F, 0x44, 0xC3]
602 );
603 assert_eq!(asm(|a| a.emit_n(InstId::Ret as u32, &[])), [0xC3]);
605 assert_eq!(asm(|a| a.emit_n(InstId::Syscall as u32, &[])), [0x0F, 0x05]);
606 assert_eq!(
608 asm(|a| a.emit_n(
609 InstId::Mov as u32,
610 &[RAX.as_operand(), imm(0x1_2345_6789i64).as_operand()]
611 )),
612 [0x48, 0xB8, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00, 0x00, 0x00]
613 );
614 }
615
616 #[test]
617 fn emit_n_invalid_sets_last_error() {
618 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
619 let mut a = Assembler::new(&mut buf);
620 a.emit_n(InstId::Add as u32, &[RAX.as_operand(), XMM0.as_operand()]);
622 assert!(matches!(
623 a.last_error(),
624 Some(X86Error::InvalidInstruction { .. })
625 ));
626 assert!(a.buffer.data().is_empty());
627 a.buffer.clear();
629 a.emit_n(u32::MAX, &[]);
630 assert!(a.last_error().is_some());
631 }
632
633 #[test]
634 fn raw_invalid_symbol_id_is_rejected() {
635 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
636 let mut a = Assembler::new(&mut buf);
637 let mut operand = Operand::new();
638 operand.set_signature(OperandSignature::from(0x001A_0012));
639
640 assert_eq!(
641 a.try_emit_n(727u32, &[&operand]),
642 Err(crate::AsmError::X86(X86Error::InvalidOperand {
643 operand_index: 0,
644 reason: "symbol is not declared in this buffer",
645 }))
646 );
647 assert!(a.buffer.data().is_empty());
648
649 a.emit_n(727u32, &[&operand]);
650 assert_eq!(
651 a.buffer.error(),
652 Some(&crate::AsmError::X86(X86Error::InvalidOperand {
653 operand_index: 0,
654 reason: "symbol is not declared in this buffer",
655 }))
656 );
657 assert!(a.buffer.data().is_empty());
658 }
659
660 #[test]
661 fn emit_n_rejects_more_than_six_operands() {
662 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
663 let mut a = Assembler::new(&mut buf);
664 let ops = [RAX.as_operand(); 7];
665
666 a.emit_n(InstId::Ret as u32, &ops);
667
668 assert!(a.last_error().is_some());
669 assert!(a.buffer.data().is_empty());
670 }
671
672 #[test]
673 fn patchable_mov_emits_once_and_rejects_unsupported_operands() {
674 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
675 {
676 let mut a = Assembler::new(&mut buf);
677 a.patchable_mov(EAX, imm(42));
678 assert_eq!(a.buffer.data(), &[0xB8, 42, 0, 0, 0]);
679 assert!(a.last_error().is_none());
680
681 a.patchable_mov(RAX, imm(42));
682 assert_eq!(
683 a.buffer.data(),
684 &[0xB8, 42, 0, 0, 0, 0x48, 0xB8, 42, 0, 0, 0, 0, 0, 0, 0]
685 );
686
687 a.patchable_mov(RAX, RBX);
688 assert!(matches!(
689 a.last_error(),
690 Some(X86Error::InvalidOperand {
691 operand_index: 1,
692 ..
693 })
694 ));
695 assert_eq!(
696 a.buffer.data(),
697 &[0xB8, 42, 0, 0, 0, 0x48, 0xB8, 42, 0, 0, 0, 0, 0, 0, 0]
698 );
699 }
700
701 assert!(matches!(
702 buf.finish_patched(),
703 Err(crate::AsmError::X86(X86Error::InvalidOperand {
704 operand_index: 1,
705 ..
706 }))
707 ));
708 }
709
710 #[test]
711 fn emit_n_memory_forms() {
712 assert_eq!(
714 asm(|a| a.emit_n(
715 InstId::Mov as u32,
716 &[RAX.as_operand(), qword_ptr_rip(0x1234).as_operand()]
717 )),
718 [0x48, 0x8B, 0x05, 0x34, 0x12, 0x00, 0x00]
719 );
720 assert_eq!(
722 asm(|a| {
723 let label = a.get_label();
724 a.emit_n(
725 InstId::Mov as u32,
726 &[dword_ptr_label(label, 0).as_operand(), EAX.as_operand()],
727 );
728 a.bind_label(label);
729 a.emit_n(InstId::Ret as u32, &[]);
730 }),
731 [0x89, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC3]
732 );
733 assert_eq!(
735 asm(|a| {
736 a.fs();
737 a.emit_n(
738 InstId::Mov as u32,
739 &[RAX.as_operand(), qword_ptr_u64(0x40).as_operand()],
740 );
741 }),
742 [0x64, 0x48, 0x8B, 0x04, 0x25, 0x40, 0x00, 0x00, 0x00]
743 );
744 }
745
746 #[test]
747 fn emit_n_branch_forms() {
748 assert_eq!(
750 asm(|a| {
751 let label = a.get_label();
752 a.bind_label(label);
753 a.emit_n(
754 InstId::Jmp as u32,
755 &[Label::from_id(label.id()).as_operand()],
756 );
757 }),
758 [0xEB, 0xFE]
759 );
760 assert_eq!(
762 asm(|a| {
763 let label = a.get_label();
764 a.emit_n(
765 InstId::Jmp as u32,
766 &[Label::from_id(label.id()).as_operand()],
767 );
768 a.bind_label(label);
769 }),
770 [0xEB, 0x00]
771 );
772 assert_eq!(
774 asm(|a| {
775 let label = a.get_label();
776 a.emit_n(
777 InstId::Call as u32,
778 &[Label::from_id(label.id()).as_operand()],
779 );
780 a.bind_label(label);
781 }),
782 [0xE8, 0x00, 0x00, 0x00, 0x00]
783 );
784 }
785
786 #[test]
787 fn patchable_branches_keep_the_near_form() {
788 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
789 let target = buf.get_label();
790 let site = {
791 let mut asm = Assembler::new(&mut buf);
792 asm.patchable_jmp(target)
793 };
794 buf.bind_label(target);
795
796 let code = buf.finish_patched().unwrap();
797 assert_eq!(code.data(), &[0xE9, 0, 0, 0, 0]);
798 assert_eq!(site.offset(), 1);
799 let catalog_site = code
800 .patch_catalog()
801 .sites()
802 .iter()
803 .find(|s| s.offset == site.offset())
804 .unwrap();
805 assert_eq!(catalog_site.current_target, 5);
806 }
807
808 #[test]
809 fn patchable_jcc_and_mov_can_be_rewritten_offline() {
810 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
811 let (jcc, imm_block, alt) = {
812 let mut asm = Assembler::new(&mut buf);
813 let target = asm.get_label();
814 let alt = asm.get_label();
815 let imm_block = asm.patchable_mov(EAX, imm(1i32));
816 let jcc = asm.patchable_jcc(CondCode::Z, target);
817 asm.bind_label(target);
818 asm.emit_n(InstId::Ret as u32, &[]);
819 let alt_off = {
820 asm.bind_label(alt);
821 asm.emit_n(InstId::Ret as u32, &[]);
822 asm.label_offset(alt)
823 };
824 (jcc, imm_block, alt_off)
825 };
826
827 let code = buf.finish_patched().unwrap();
828 let mut bytes = code.data().to_vec();
829 unsafe {
830 imm_block.repatch_u32(&mut bytes, 0x99).unwrap();
831 jcc.retarget(&mut bytes, alt).unwrap();
832 }
833 assert_eq!(
834 &bytes[imm_block.offset() as usize..][..4],
835 &0x99u32.to_le_bytes()
836 );
837 }
838
839 #[test]
840 fn emit_n_vex_evex_forms() {
841 assert_eq!(
843 asm(|a| a.emit_n(
844 InstId::Vaddps as u32,
845 &[YMM1.as_operand(), YMM2.as_operand(), YMM3.as_operand()]
846 )),
847 [0xC5, 0xEC, 0x58, 0xCB]
848 );
849 assert_eq!(
851 asm(|a| a.emit_n(
852 InstId::Vmovdqu as u32,
853 &[YMM0.as_operand(), YMM1.as_operand()]
854 )),
855 [0xC5, 0xFE, 0x6F, 0xC1]
856 );
857 assert_eq!(
859 asm(|a| a.emit_n(
860 InstId::Vaddpd as u32,
861 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()]
862 )),
863 [0x62, 0xF1, 0xED, 0x48, 0x58, 0xCB]
864 );
865 assert_eq!(
867 asm(|a| {
868 a.k(K1);
869 a.emit_n(
870 InstId::Vaddpd as u32,
871 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()],
872 );
873 }),
874 [0x62, 0xF1, 0xED, 0x49, 0x58, 0xCB]
875 );
876 }
877
878 #[test]
879 fn emitter_traits_match_emit_n() {
880 use crate::x86::emitter::{AddEmitter, JmpEmitter, MovEmitter, VaddpsEmitter};
883
884 assert_eq!(
886 asm(|a| MovEmitter::mov(a, RAX, imm(1))),
887 [0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00]
888 );
889 assert_eq!(asm(|a| MovEmitter::mov(a, RAX, RBX)), [0x48, 0x89, 0xD8]);
891 assert_eq!(asm(|a| AddEmitter::add(a, RAX, RBX)), [0x48, 0x01, 0xD8]);
893 assert_eq!(
895 asm(|a| VaddpsEmitter::vaddps(a, YMM1, YMM2, YMM3)),
896 [0xC5, 0xEC, 0x58, 0xCB]
897 );
898 assert_eq!(
900 asm(|a| {
901 let label = a.get_label();
902 a.bind_label(label);
903 JmpEmitter::jmp(a, label);
904 }),
905 [0xEB, 0xFE]
906 );
907 }
908
909 #[test]
910 fn emitter_typed_call_sites() {
911 use crate::x86::emitter::{AddEmitter, MovEmitter, PaddwEmitter, VaddpsEmitter};
914
915 assert_eq!(
917 asm(|a| MovEmitter::mov(a, RAX, 42)),
918 [0x48, 0xC7, 0xC0, 0x2A, 0x00, 0x00, 0x00]
919 );
920 assert_eq!(
922 asm(|a| MovEmitter::mov(a, EAX, 42)),
923 [0xB8, 0x2A, 0x00, 0x00, 0x00]
924 );
925 assert_eq!(asm(|a| AddEmitter::add(a, RAX, RBX)), [0x48, 0x01, 0xD8]);
927 assert_eq!(
929 asm(|a| PaddwEmitter::paddw(a, XMM0, XMM1)),
930 [0x66, 0x0F, 0xFD, 0xC1]
931 );
932 assert_eq!(
934 asm(|a| VaddpsEmitter::vaddps(a, YMM1, YMM2, YMM3)),
935 [0xC5, 0xEC, 0x58, 0xCB]
936 );
937 }
938
939 #[test]
940 fn emit_n_prefix_forms() {
941 assert_eq!(
943 asm(|a| {
944 a.rep();
945 a.emit_n(
946 InstId::Movs as u32,
947 &[
948 qword_ptr(RDI, 0).as_operand(),
949 qword_ptr(RSI, 0).as_operand(),
950 ],
951 );
952 }),
953 [0xF3, 0x48, 0xA5]
954 );
955 assert_eq!(
957 asm(|a| {
958 a.lock();
959 a.emit_n(
960 InstId::Add as u32,
961 &[dword_ptr(RBX, 0).as_operand(), EAX.as_operand()],
962 );
963 }),
964 [0xF0, 0x01, 0x03]
965 );
966 }
967
968 #[test]
969 fn conflicting_prefix_setters_poison_without_emitting() {
970 let cases: &[fn(&mut Assembler<'_>)] = &[
971 |a| {
972 a.fs().gs();
973 },
974 |a| {
975 a.k(K1).k(K2);
976 },
977 |a| {
978 a.rd_sae().ru_sae();
979 },
980 |a| {
981 a.seg(sreg(7));
982 },
983 |a| {
984 a.k(k(8));
985 },
986 |a| {
987 a.k(K0);
988 },
989 ];
990
991 for set_prefixes in cases {
992 let mut buffer = CodeBuffer::new(Environment::new(Arch::X64));
993 let mut assembler = Assembler::new(&mut buffer);
994 set_prefixes(&mut assembler);
995 assembler.emit_n(InstId::Ret as u32, &[]);
996 assert!(assembler.buffer.error().is_some());
997 assert!(assembler.buffer.data().is_empty());
998 }
999 }
1000
1001 #[test]
1002 fn emit_n_builder_replay_matches_direct() {
1003 fn direct() -> std::vec::Vec<u8> {
1004 asm(|a| {
1005 let done = a.get_label();
1006 a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), imm(1).as_operand()]);
1007 a.emit_n(InstId::Add as u32, &[RAX.as_operand(), RBX.as_operand()]);
1008 a.emit_n(
1009 InstId::Jmp as u32,
1010 &[Label::from_id(done.id()).as_operand()],
1011 );
1012 a.emit_n(InstId::Ret as u32, &[]);
1013 a.bind_label(done);
1014 a.emit_n(InstId::Ret as u32, &[]);
1015 })
1016 }
1017
1018 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
1019 let mut builder = Builder::new();
1020 let done = buf.get_label();
1021 builder
1022 .push_inst(Inst::with_operands(
1023 InstId::Mov as u32,
1024 &[*RAX.as_operand(), *imm(1).as_operand()],
1025 ))
1026 .unwrap();
1027 builder
1028 .push_inst(Inst::with_operands(
1029 InstId::Add as u32,
1030 &[*RAX.as_operand(), *RBX.as_operand()],
1031 ))
1032 .unwrap();
1033 builder
1034 .push_inst(Inst::with_operands(
1035 InstId::Jmp as u32,
1036 &[*Label::from_id(done.id()).as_operand()],
1037 ))
1038 .unwrap();
1039 builder
1040 .push_inst(Inst::with_operands(InstId::Ret as u32, &[]))
1041 .unwrap();
1042 builder.push_label(done);
1043 builder
1044 .push_inst(Inst::with_operands(InstId::Ret as u32, &[]))
1045 .unwrap();
1046 {
1047 let mut a = Assembler::new(&mut buf);
1048 builder.emit_into(&mut a).unwrap();
1049 assert!(a.last_error().is_none(), "{:?}", a.last_error());
1050 }
1051 assert_eq!(buf.finish().unwrap().data().to_vec(), direct());
1052 }
1053
1054 #[test]
1055 fn builder_replays_options_and_mask_register() {
1056 let direct = asm(|a| {
1057 a.k(K1).z();
1058 a.emit_n(
1059 InstId::Vaddpd as u32,
1060 &[ZMM1.as_operand(), ZMM2.as_operand(), ZMM3.as_operand()],
1061 );
1062 });
1063
1064 let mut inst = Inst::with_arch_operands(
1065 Arch::X64,
1066 InstId::Vaddpd as u32,
1067 &[*ZMM1.as_operand(), *ZMM2.as_operand(), *ZMM3.as_operand()],
1068 )
1069 .unwrap();
1070 inst.set_options(InstOptions::X86_ZMASK);
1071 inst.set_extra_reg(*K1.as_operand());
1072 let mut builder = Builder::for_arch(Arch::X64);
1073 builder.push_inst(inst).unwrap();
1074
1075 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
1076 builder.emit_into(&mut Assembler::new(&mut buf)).unwrap();
1077 assert_eq!(buf.finish().unwrap().data(), direct);
1078 }
1079
1080 fn asm32(f: impl FnOnce(&mut Assembler)) -> std::vec::Vec<u8> {
1082 let mut buf = CodeBuffer::new(Environment::new(Arch::X86));
1083 {
1084 let mut a = Assembler::new(&mut buf);
1085 f(&mut a);
1086 assert!(a.last_error().is_none(), "{:?}", a.last_error());
1087 }
1088 buf.finish().unwrap().data().to_vec()
1089 }
1090
1091 fn asm32_err(f: impl FnOnce(&mut Assembler)) -> X86Error {
1093 let mut buf = CodeBuffer::new(Environment::new(Arch::X86));
1094 let mut a = Assembler::new(&mut buf);
1095 f(&mut a);
1096 a.last_error().expect("expected an emit error")
1097 }
1098
1099 fn asm64_err(f: impl FnOnce(&mut Assembler)) -> X86Error {
1101 let mut buf = CodeBuffer::new(Environment::new(Arch::X64));
1102 let mut a = Assembler::new(&mut buf);
1103 f(&mut a);
1104 a.last_error().expect("expected an emit error")
1105 }
1106
1107 #[test]
1108 fn emit_n_32bit_gp_forms() {
1109 use crate::x86::emitter::{AddEmitter, MovEmitter};
1110
1111 assert_eq!(asm32(|a| MovEmitter::mov(a, EAX, EBX)), [0x89, 0xD8]);
1113 assert_eq!(asm32(|a| MovEmitter::mov(a, AX, BX)), [0x66, 0x89, 0xD8]);
1115 assert_eq!(asm32(|a| MovEmitter::mov(a, AL, BL)), [0x88, 0xD8]);
1116 assert_eq!(
1118 asm32(|a| a.emit_n(InstId::Add as u32, &[ECX.as_operand(), imm(1).as_operand()])),
1119 [0x83, 0xC1, 0x01]
1120 );
1121 assert_eq!(
1122 asm32(|a| AddEmitter::add(a, EAX, 0x1234_5678i32)),
1123 [0x05, 0x78, 0x56, 0x34, 0x12]
1124 );
1125 assert_eq!(
1127 asm32(|a| MovEmitter::mov(a, EAX, 0x1234_5678i32)),
1128 [0xB8, 0x78, 0x56, 0x34, 0x12]
1129 );
1130 assert_eq!(
1131 asm32(|a| MovEmitter::mov(a, AX, 0x1234)),
1132 [0x66, 0xB8, 0x34, 0x12]
1133 );
1134 assert_eq!(asm32(|a| MovEmitter::mov(a, CL, 0x12)), [0xB1, 0x12]);
1135 }
1136
1137 #[test]
1138 fn emit_n_32bit_inc_dec_short_forms() {
1139 use crate::x86::emitter::{DecEmitter, IncEmitter};
1140
1141 assert_eq!(asm32(|a| IncEmitter::inc(a, EAX)), [0x40]);
1143 assert_eq!(asm32(|a| IncEmitter::inc(a, ECX)), [0x41]);
1144 assert_eq!(asm32(|a| IncEmitter::inc(a, AX)), [0x66, 0x40]);
1145 assert_eq!(asm32(|a| DecEmitter::dec(a, EDX)), [0x4A]);
1146 assert_eq!(asm32(|a| DecEmitter::dec(a, DX)), [0x66, 0x4A]);
1147 assert_eq!(asm32(|a| IncEmitter::inc(a, AL)), [0xFE, 0xC0]);
1149 assert_eq!(
1150 asm32(|a| IncEmitter::inc(a, dword_ptr(ECX, 0))),
1151 [0xFF, 0x01]
1152 );
1153 assert_eq!(
1155 asm(|a| a.emit_n(InstId::Inc as u32, &[EAX.as_operand()])),
1156 [0xFF, 0xC0]
1157 );
1158 }
1159
1160 #[test]
1161 fn emit_n_32bit_push_pop() {
1162 use crate::x86::emitter::{PopEmitter, PushEmitter};
1163
1164 assert_eq!(asm32(|a| PushEmitter::push(a, EAX)), [0x50]);
1165 assert_eq!(asm32(|a| PushEmitter::push(a, AX)), [0x66, 0x50]);
1166 assert_eq!(asm32(|a| PopEmitter::pop(a, ECX)), [0x59]);
1167 assert_eq!(
1168 asm32(|a| PushEmitter::push(a, 0x1234_5678i32)),
1169 [0x68, 0x78, 0x56, 0x34, 0x12]
1170 );
1171 assert_eq!(
1172 asm32(|a| PushEmitter::push(a, dword_ptr(ECX, 0))),
1173 [0xFF, 0x31]
1174 );
1175 assert_eq!(
1176 asm32(|a| PushEmitter::push(a, word_ptr(ECX, 0))),
1177 [0x66, 0xFF, 0x31]
1178 );
1179 asm32_err(|a| PushEmitter::push(a, qword_ptr(ECX, 0)));
1181 asm32_err(|a| PopEmitter::pop(a, qword_ptr(ECX, 0)));
1182 }
1183
1184 #[test]
1185 fn emit_n_32bit_far_pointer_forms() {
1186 assert_eq!(
1188 asm32(|a| a.emit_n(
1189 InstId::Lcall as u32,
1190 &[imm(0x1234).as_operand(), imm(0x1234_5678).as_operand()]
1191 )),
1192 [0x9A, 0x78, 0x56, 0x34, 0x12, 0x34, 0x12]
1193 );
1194 assert_eq!(
1195 asm32(|a| a.emit_n(
1196 InstId::Ljmp as u32,
1197 &[imm(0x10).as_operand(), imm(0x20).as_operand()]
1198 )),
1199 [0xEA, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00]
1200 );
1201 asm32_err(|a| {
1203 a.emit_n(
1204 InstId::Lcall as u32,
1205 &[imm(0x1_0000).as_operand(), imm(0).as_operand()],
1206 )
1207 });
1208 asm64_err(|a| {
1210 a.emit_n(
1211 InstId::Lcall as u32,
1212 &[imm(0x1234).as_operand(), imm(0x1234_5678).as_operand()],
1213 )
1214 });
1215 assert_eq!(
1217 asm32(|a| a.emit_n(InstId::Lcall as u32, &[fword_ptr(ECX, 0).as_operand()])),
1218 [0xFF, 0x19]
1219 );
1220 }
1221
1222 #[test]
1223 fn emit_n_32bit_movabs_and_xchg() {
1224 use crate::x86::emitter::{MovEmitter, XchgEmitter};
1225
1226 assert_eq!(
1228 asm32(|a| MovEmitter::mov(a, EAX, dword_ptr_u64(0x1234_5678))),
1229 [0xA1, 0x78, 0x56, 0x34, 0x12]
1230 );
1231 assert_eq!(
1233 asm32(|a| MovEmitter::mov(a, dword_ptr_u64(0x1234_5678), EAX)),
1234 [0xA3, 0x78, 0x56, 0x34, 0x12]
1235 );
1236 assert_eq!(asm32(|a| XchgEmitter::xchg(a, EAX, EAX)), [0x90]);
1238 assert_eq!(
1239 asm(|a| a.emit_n(InstId::Xchg as u32, &[EAX.as_operand(), EAX.as_operand()])),
1240 [0x87, 0xC0]
1241 );
1242 }
1243
1244 #[test]
1245 fn emit_n_32bit_creg_lock_extension() {
1246 assert_eq!(
1248 asm32(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), CR8.as_operand()])),
1249 [0xF0, 0x0F, 0x20, 0xC0]
1250 );
1251 assert_eq!(
1252 asm32(|a| a.emit_n(InstId::Mov as u32, &[CR8.as_operand(), EAX.as_operand()])),
1253 [0xF0, 0x0F, 0x22, 0xC0]
1254 );
1255 assert_eq!(
1257 asm32(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), CR0.as_operand()])),
1258 [0x0F, 0x20, 0xC0]
1259 );
1260 }
1261
1262 #[test]
1263 fn emit_n_32bit_mode_gating() {
1264 asm32_err(|a| a.emit_n(InstId::Mov as u32, &[RAX.as_operand(), RBX.as_operand()]));
1266 asm32_err(|a| a.emit_n(InstId::Push as u32, &[RAX.as_operand()]));
1267 asm32_err(|a| a.emit_n(InstId::Mov as u32, &[EAX.as_operand(), R8D.as_operand()]));
1269 asm32_err(|a| {
1270 a.emit_n(
1271 InstId::Paddw as u32,
1272 &[XMM0.as_operand(), XMM8.as_operand()],
1273 )
1274 });
1275 asm32_err(|a| a.emit_n(InstId::Syscall as u32, &[]));
1277 asm32_err(|a| a.emit_n(InstId::Movsxd as u32, &[EAX.as_operand(), EBX.as_operand()]));
1278 asm32_err(|a| {
1280 a.emit_n(
1281 InstId::Mov as u32,
1282 &[EAX.as_operand(), dword_ptr(RBX, 0).as_operand()],
1283 )
1284 });
1285 asm32_err(|a| {
1287 a.emit_n(
1288 InstId::Mov as u32,
1289 &[EAX.as_operand(), dword_ptr_u64(0x1_0000_0000).as_operand()],
1290 )
1291 });
1292 }
1293
1294 #[test]
1295 fn emit_n_32bit_string_ops() {
1296 assert_eq!(
1298 asm32(|a| a.emit_n(
1299 InstId::Movs as u32,
1300 &[
1301 dword_ptr(EDI, 0).as_operand(),
1302 dword_ptr(ESI, 0).as_operand()
1303 ]
1304 )),
1305 [0xA5]
1306 );
1307 assert_eq!(
1309 asm32(|a| a.emit_n(
1310 InstId::Jecxz as u32,
1311 &[CX.as_operand(), imm(-2).as_operand()],
1312 )),
1313 [0x67, 0xE3, 0xFE]
1314 );
1315 }
1316}