1use core::fmt;
11use core::ops::Deref;
12
13use super::error::EncodeError;
14use super::flags::FlagEffects;
15use super::form::{ATTR_NOT_R0, Form, ModRmSpec, OpcodeField, OperandKind, Slot};
16use super::inst::Inst;
17use super::operand::{Cond, Mem, Operand};
18use super::reg::{Reg, Size};
19use super::table;
20
21pub const MAX_INST_LEN: usize = 15;
23
24#[derive(Clone, Copy, PartialEq, Eq, Hash)]
40pub struct Encoded {
41 bytes: [u8; MAX_INST_LEN],
42 flags: FlagEffects,
43 form: u16,
44 len: u8,
45 disp_at: u8,
46 imm_at: u8,
47}
48
49impl Encoded {
50 #[inline]
61 #[must_use]
62 pub fn as_bytes(&self) -> &[u8] {
63 &self.bytes[..usize::from(self.len).min(MAX_INST_LEN)]
64 }
65
66 #[must_use]
78 pub fn form(&self) -> &'static Form {
79 table::form(self.form).unwrap_or(&table::FORMS[0])
82 }
83
84 #[inline]
97 #[must_use]
98 pub const fn flags(&self) -> FlagEffects {
99 self.flags
100 }
101
102 pub(crate) const fn rip_disp_at(&self) -> Option<usize> {
104 if self.disp_at == 0 {
105 None
106 } else {
107 Some(self.disp_at as usize)
108 }
109 }
110
111 pub(crate) const fn imm_at(&self) -> Option<usize> {
113 if self.imm_at == 0 {
114 None
115 } else {
116 Some(self.imm_at as usize)
117 }
118 }
119}
120
121impl Deref for Encoded {
122 type Target = [u8];
123
124 #[inline]
125 fn deref(&self) -> &[u8] {
126 self.as_bytes()
127 }
128}
129
130impl AsRef<[u8]> for Encoded {
131 #[inline]
132 fn as_ref(&self) -> &[u8] {
133 self.as_bytes()
134 }
135}
136
137impl fmt::Debug for Encoded {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 f.write_str("Encoded(")?;
140 for (i, b) in self.as_bytes().iter().enumerate() {
141 if i > 0 {
142 f.write_str(" ")?;
143 }
144 write!(f, "{b:02x}")?;
145 }
146 f.write_str(")")
147 }
148}
149
150pub fn encode(inst: &Inst) -> Result<Encoded, EncodeError> {
175 check_memory(inst)?;
176 let (op, cond) = inst.mnemonic().parts();
177 let mut best = Miss::Kind;
178 let ops = inst.operands();
179 for &id in table::by_op(op) {
180 let Some(form) = table::form(id) else {
181 continue;
182 };
183 if ops.len() != usize::from(form.count)
186 || !ops
187 .iter()
188 .zip(form.kinds.iter())
189 .all(|(&o, &k)| kind_fits(k, o))
190 {
191 continue;
192 }
193 match try_form(form, inst, cond) {
194 Ok(encoded) => return Ok(encoded),
195 Err(miss) => best = best.closer(miss),
196 }
197 }
198 Err(best.into_error(inst))
199}
200
201pub fn encode_form(form: &Form, inst: &Inst) -> Result<Encoded, EncodeError> {
224 check_memory(inst)?;
225 let (op, cond) = inst.mnemonic().parts();
226 let form = table::form(form.id).unwrap_or(form);
228 if form.op != op {
229 return Err(EncodeError::NoForm {
230 mnemonic: inst.mnemonic(),
231 });
232 }
233 try_form(form, inst, cond).map_err(|miss| miss.into_error(inst))
234}
235
236#[derive(Clone, Copy, Debug)]
238enum Miss {
239 Kind,
240 HighByte,
241 Imm(i64),
242 Target(i64),
243}
244
245impl Miss {
246 const fn rank(self) -> u8 {
247 match self {
248 Miss::Kind => 0,
249 Miss::HighByte => 1,
250 Miss::Imm(_) => 2,
251 Miss::Target(_) => 3,
252 }
253 }
254
255 fn closer(self, other: Miss) -> Miss {
256 if other.rank() > self.rank() {
257 other
258 } else {
259 self
260 }
261 }
262
263 fn into_error(self, inst: &Inst) -> EncodeError {
264 match self {
265 Miss::Kind => EncodeError::NoForm {
266 mnemonic: inst.mnemonic(),
267 },
268 Miss::HighByte => EncodeError::HighByteWithRex,
269 Miss::Imm(value) => EncodeError::ImmediateOutOfRange { value },
270 Miss::Target(offset) => EncodeError::TargetOutOfRange { offset },
271 }
272 }
273}
274
275fn check_memory(inst: &Inst) -> Result<(), EncodeError> {
277 for op in inst.operands() {
278 let Operand::Mem(m) = op else { continue };
279 if let Some(base) = m.base() {
280 if base.size() != Size::Qword {
281 return Err(EncodeError::BaseNotQword { base });
282 }
283 }
284 if let Some(index) = m.index() {
285 if m.is_rip_relative() {
286 return Err(EncodeError::RipWithIndex);
287 }
288 if index.size() != Size::Qword {
289 return Err(EncodeError::IndexNotQword { index });
290 }
291 if index.num() == 4 {
292 return Err(EncodeError::RspIndex);
293 }
294 }
295 }
296 Ok(())
297}
298
299fn kind_fits(kind: OperandKind, op: Operand) -> bool {
302 match (kind, op) {
303 (OperandKind::Reg(size), Operand::Reg(r)) => r.size() == size,
304 (OperandKind::RegMem(size), Operand::Reg(r)) => r.size() == size,
305 (OperandKind::RegMem(size) | OperandKind::Mem(size), Operand::Mem(m)) => m.size() == size,
306 (OperandKind::Fixed(reg), Operand::Reg(r)) => r == reg,
307 (OperandKind::One, Operand::Imm(v)) => v == 1,
308 (OperandKind::Imm { .. }, Operand::Imm(_)) => true,
309 (OperandKind::Rel { .. }, Operand::Rel(_)) => true,
310 _ => false,
311 }
312}
313
314pub(crate) const fn imm_fits(value: i64, bits: u8, signed: bool) -> bool {
316 if bits >= 64 {
317 return signed || value >= 0;
318 }
319 if signed {
320 let half = 1i64 << (bits - 1);
321 value >= -half && value < half
322 } else {
323 value >= 0 && value < (1i64 << bits)
324 }
325}
326
327#[derive(Clone, Copy)]
329enum Disp {
330 None,
331 Byte(i8),
332 Dword(i32),
333}
334
335impl Disp {
336 const fn len(self) -> usize {
337 match self {
338 Disp::None => 0,
339 Disp::Byte(_) => 1,
340 Disp::Dword(_) => 4,
341 }
342 }
343}
344
345struct Layout<'f> {
347 form: &'f Form,
348 rex: u8,
349 force_rex: bool,
350 high_byte: bool,
351 opcode: u8,
352 reg_field: u8,
353 md: u8,
354 rm_field: u8,
355 sib: Option<u8>,
356 disp: Disp,
357 rip: bool,
358}
359
360impl<'f> Layout<'f> {
361 fn new(form: &'f Form) -> Layout<'f> {
362 Layout {
363 form,
364 rex: if form.rex_w { 0b1000 } else { 0 },
365 force_rex: false,
366 high_byte: false,
367 opcode: form.opcode,
368 reg_field: match form.modrm {
369 ModRmSpec::Ext(n) => n,
370 ModRmSpec::Reg | ModRmSpec::Absent => 0,
371 },
372 md: 0,
373 rm_field: 0,
374 sib: None,
375 disp: Disp::None,
376 rip: false,
377 }
378 }
379
380 fn note_byte_reg(&mut self, r: Reg) {
382 if r.is_high_byte() {
383 self.high_byte = true;
384 } else if r.needs_rex() {
385 self.force_rex = true;
386 }
387 }
388
389 fn reg(&mut self, r: Reg) {
390 self.note_byte_reg(r);
391 self.reg_field = r.num() & 7;
392 self.rex |= (r.num() >> 3) << 2;
393 }
394
395 fn opcode_reg(&mut self, r: Reg) {
396 self.note_byte_reg(r);
397 self.opcode |= r.num() & 7;
398 self.rex |= r.num() >> 3;
399 }
400
401 fn rm_reg(&mut self, r: Reg) {
402 self.note_byte_reg(r);
403 self.md = 0b11;
404 self.rm_field = r.num() & 7;
405 self.rex |= r.num() >> 3;
406 }
407
408 fn rm_mem(&mut self, m: Mem) {
409 let disp = m.disp();
410 if m.is_rip_relative() {
411 self.md = 0b00;
413 self.rm_field = 0b101;
414 self.disp = Disp::Dword(disp);
415 self.rip = true;
416 return;
417 }
418 let index_bits = match m.index() {
419 Some(index) => {
420 self.rex |= (index.num() >> 3) << 1;
421 index.num() & 7
422 }
423 None => 0b100,
424 };
425 let scale = m.scale().bits() << 6;
426 match m.base() {
427 None => {
428 self.md = 0b00;
430 self.rm_field = 0b100;
431 self.sib = Some(scale | (index_bits << 3) | 0b101);
432 self.disp = Disp::Dword(disp);
433 }
434 Some(base) => {
435 self.rex |= base.num() >> 3;
436 let low = base.num() & 7;
437 (self.md, self.disp) = if disp == 0 && low != 0b101 {
440 (0b00, Disp::None)
441 } else if let Ok(d) = i8::try_from(disp) {
442 (0b01, Disp::Byte(d))
443 } else {
444 (0b10, Disp::Dword(disp))
445 };
446 if m.index().is_some() || low == 0b100 {
448 self.rm_field = 0b100;
449 self.sib = Some(scale | (index_bits << 3) | low);
450 } else {
451 self.rm_field = low;
452 }
453 }
454 }
455 }
456
457 fn needs_rex(&self) -> bool {
458 self.rex != 0 || self.force_rex
459 }
460
461 fn prefix_len(&self) -> usize {
463 let f = self.form;
464 let modrm = if matches!(f.modrm, ModRmSpec::Absent) {
465 0
466 } else {
467 1 + usize::from(self.sib.is_some()) + self.disp.len()
468 };
469 usize::from(f.p66) + usize::from(self.needs_rex()) + usize::from(f.map) + 1 + modrm
470 }
471
472 fn write(&self, imm: i64) -> Encoded {
473 let f = self.form;
474 let mut out = Encoded {
475 bytes: [0; MAX_INST_LEN],
476 flags: f.flags,
477 form: f.id,
478 len: 0,
479 disp_at: 0,
480 imm_at: 0,
481 };
482 let mut n = 0usize;
483 let mut put = |byte: u8, n: &mut usize| {
484 if let Some(slot) = out.bytes.get_mut(*n) {
485 *slot = byte;
486 }
487 *n += 1;
488 };
489 if f.p66 {
490 put(0x66, &mut n);
491 }
492 if self.needs_rex() {
493 put(0x40 | self.rex, &mut n);
494 }
495 if f.map == 1 {
496 put(0x0F, &mut n);
497 }
498 put(self.opcode, &mut n);
499 let mut disp_at = 0;
500 if !matches!(f.modrm, ModRmSpec::Absent) {
501 put(
502 (self.md << 6) | (self.reg_field << 3) | self.rm_field,
503 &mut n,
504 );
505 if let Some(sib) = self.sib {
506 put(sib, &mut n);
507 }
508 if self.rip {
509 disp_at = n;
510 }
511 match self.disp {
512 Disp::None => {}
513 Disp::Byte(d) => put(d as u8, &mut n),
514 Disp::Dword(d) => {
515 for b in d.to_le_bytes() {
516 put(b, &mut n);
517 }
518 }
519 }
520 }
521 let imm_at = if f.imm_bytes > 0 { n } else { 0 };
522 for b in imm.to_le_bytes().iter().take(usize::from(f.imm_bytes)) {
523 put(*b, &mut n);
524 }
525 out.len = n.min(MAX_INST_LEN) as u8;
527 out.disp_at = disp_at as u8;
528 out.imm_at = imm_at as u8;
529 out
530 }
531}
532
533fn try_form(form: &Form, inst: &Inst, cond: Option<Cond>) -> Result<Encoded, Miss> {
535 let ops = inst.operands();
536 if ops.len() != usize::from(form.count) {
537 return Err(Miss::Kind);
538 }
539 let mut layout = Layout::new(form);
540 if matches!(form.field, OpcodeField::Cond) {
541 layout.opcode |= cond.map_or(0, Cond::code);
542 }
543 let mut imm = 0i64;
544 let mut rel: Option<(i64, u8)> = None;
545 let mut imm_miss = None;
546 for (i, &op) in ops.iter().enumerate() {
547 let (Some(&kind), Some(&slot)) = (form.kinds.get(i), form.slots.get(i)) else {
548 return Err(Miss::Kind);
549 };
550 if !kind_fits(kind, op) {
551 return Err(Miss::Kind);
552 }
553 match (slot, op) {
554 (Slot::Implied, _) => {}
555 (Slot::Reg, Operand::Reg(r)) => layout.reg(r),
556 (Slot::Opcode, Operand::Reg(r)) => {
557 if form.attrs & ATTR_NOT_R0 != 0 && r.num() == 0 {
558 return Err(Miss::Kind);
559 }
560 layout.opcode_reg(r);
561 }
562 (Slot::Rm, Operand::Reg(r)) => layout.rm_reg(r),
563 (Slot::Rm, Operand::Mem(m)) => layout.rm_mem(m),
564 (Slot::Imm, Operand::Imm(v)) => match kind {
565 OperandKind::Imm { bits, signed } if imm_fits(v, bits, signed) => imm = v,
566 _ => imm_miss = Some(v),
567 },
568 (Slot::Imm, Operand::Rel(d)) => match kind {
569 OperandKind::Rel { bits } => rel = Some((d, bits)),
570 _ => return Err(Miss::Kind),
571 },
572 _ => return Err(Miss::Kind),
573 }
574 }
575 if layout.needs_rex() && layout.high_byte {
576 return Err(Miss::HighByte);
577 }
578 if let Some(v) = imm_miss {
579 return Err(Miss::Imm(v));
580 }
581 if let Some((target, bits)) = rel {
582 let len = (layout.prefix_len() + usize::from(form.imm_bytes)) as i64;
583 match target.checked_sub(len) {
584 Some(r) if imm_fits(r, bits, true) => imm = r,
585 _ => return Err(Miss::Target(target)),
586 }
587 }
588 let mut encoded = layout.write(imm);
589 if form.reads_cond {
590 if let Some(c) = cond {
591 encoded.flags = encoded.flags.with_read(c.reads());
592 }
593 }
594 Ok(encoded)
595}
596
597#[cfg(test)]
598mod tests {
599 use alloc::vec;
600
601 use super::*;
602 use crate::x86_64::{Mnemonic, Scale};
603
604 fn enc(m: Mnemonic, ops: &[Operand]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
605 let inst = Inst::from_slice(m, ops).ok_or(EncodeError::NoForm { mnemonic: m })?;
606 encode(&inst).map(|e| e.to_vec())
607 }
608
609 #[test]
610 fn test_imm_fits_boundaries() {
611 assert!(imm_fits(127, 8, true) && imm_fits(-128, 8, true));
612 assert!(!imm_fits(128, 8, true) && !imm_fits(-129, 8, true));
613 assert!(imm_fits(255, 8, false) && !imm_fits(256, 8, false) && !imm_fits(-1, 8, false));
614 assert!(imm_fits(i64::MIN, 64, true) && imm_fits(i64::MAX, 64, true));
615 assert!(imm_fits(i32::MIN.into(), 32, true) && !imm_fits(1 << 31, 32, true));
616 assert!(imm_fits(65535, 16, false) && !imm_fits(65536, 16, false));
617 }
618
619 #[test]
620 fn test_memory_shapes() {
621 let mov = |m: Mem| enc(Mnemonic::Mov, &[Reg::EAX.into(), m.into()]);
622 let d = Size::Dword;
623 assert_eq!(mov(Mem::new(d, Reg::RAX)), Ok(vec![0x8B, 0x00]));
625 assert_eq!(mov(Mem::new(d, Reg::RBP)), Ok(vec![0x8B, 0x45, 0x00]));
627 assert_eq!(mov(Mem::new(d, Reg::R13)), Ok(vec![0x41, 0x8B, 0x45, 0x00]));
629 assert_eq!(mov(Mem::new(d, Reg::RSP)), Ok(vec![0x8B, 0x04, 0x24]));
631 assert_eq!(mov(Mem::new(d, Reg::R12)), Ok(vec![0x41, 0x8B, 0x04, 0x24]));
633 assert_eq!(mov(Mem::rip(d, 16)), Ok(vec![0x8B, 0x05, 0x10, 0, 0, 0]));
635 assert_eq!(
637 mov(Mem::absolute(d, 16)),
638 Ok(vec![0x8B, 0x04, 0x25, 0x10, 0, 0, 0])
639 );
640 let idx = Mem::absolute(d, 16).with_index(Reg::RCX, Scale::X4);
642 assert_eq!(mov(idx), Ok(vec![0x8B, 0x04, 0x8D, 0x10, 0, 0, 0]));
643 let m = Mem::new(d, Reg::RAX)
645 .with_index(Reg::R12, Scale::X8)
646 .with_disp(-128);
647 assert_eq!(mov(m), Ok(vec![0x42, 0x8B, 0x44, 0xE0, 0x80]));
648 assert_eq!(
650 mov(Mem::new(d, Reg::RAX).with_disp(128)),
651 Ok(vec![0x8B, 0x80, 0x80, 0, 0, 0])
652 );
653 }
654
655 #[test]
656 fn test_memory_errors() {
657 let mov = |m: Mem| enc(Mnemonic::Mov, &[Reg::EAX.into(), m.into()]);
658 let d = Size::Dword;
659 assert_eq!(
660 mov(Mem::new(d, Reg::EAX)),
661 Err(EncodeError::BaseNotQword { base: Reg::EAX })
662 );
663 let bad_index = Mem::new(d, Reg::RAX).with_index(Reg::ECX, Scale::X1);
664 assert_eq!(
665 mov(bad_index),
666 Err(EncodeError::IndexNotQword { index: Reg::ECX })
667 );
668 let rsp = Mem::new(d, Reg::RAX).with_index(Reg::RSP, Scale::X1);
669 assert_eq!(mov(rsp), Err(EncodeError::RspIndex));
670 let rip = Mem::rip(d, 0).with_index(Reg::RAX, Scale::X2);
671 assert_eq!(mov(rip), Err(EncodeError::RipWithIndex));
672 }
673
674 #[test]
675 fn test_high_byte_rules() {
676 assert_eq!(
677 enc(Mnemonic::Mov, &[Reg::AH.into(), Reg::BL.into()]),
678 Ok(vec![0x88, 0xDC])
679 );
680 assert_eq!(
681 enc(Mnemonic::Mov, &[Reg::SIL.into(), Reg::AL.into()]),
682 Ok(vec![0x40, 0x88, 0xC6])
683 );
684 assert_eq!(
685 enc(Mnemonic::Mov, &[Reg::AH.into(), Reg::SIL.into()]),
686 Err(EncodeError::HighByteWithRex)
687 );
688 assert_eq!(
689 enc(Mnemonic::Movzx, &[Reg::RAX.into(), Reg::AH.into()]),
690 Err(EncodeError::HighByteWithRex)
691 );
692 assert_eq!(
693 enc(Mnemonic::Movzx, &[Reg::EAX.into(), Reg::AH.into()]),
694 Ok(vec![0x0F, 0xB6, 0xC4])
695 );
696 }
697
698 #[test]
699 fn test_branch_selection() {
700 let jmp = |d| enc(Mnemonic::Jmp, &[Operand::Rel(d)]);
701 assert_eq!(jmp(2), Ok(vec![0xEB, 0x00]));
702 assert_eq!(jmp(129), Ok(vec![0xEB, 0x7F]));
703 assert_eq!(jmp(130), Ok(vec![0xE9, 0x7D, 0, 0, 0]));
704 assert_eq!(jmp(-126), Ok(vec![0xEB, 0x80]));
705 assert_eq!(jmp(-127), Ok(vec![0xE9, 0x7C, 0xFF, 0xFF, 0xFF]));
706 let far = i64::from(i32::MAX) + 6;
707 assert_eq!(jmp(far), Err(EncodeError::TargetOutOfRange { offset: far }));
708 assert_eq!(
709 jmp(i64::MIN),
710 Err(EncodeError::TargetOutOfRange { offset: i64::MIN })
711 );
712 }
713
714 #[test]
715 fn test_not_r0_avoids_nop() {
716 assert_eq!(
717 enc(Mnemonic::Xchg, &[Reg::EBX.into(), Reg::EAX.into()]),
718 Ok(vec![0x93])
719 );
720 assert_eq!(
721 enc(Mnemonic::Xchg, &[Reg::EAX.into(), Reg::EAX.into()]),
722 Ok(vec![0x87, 0xC0])
723 );
724 assert_eq!(
725 enc(Mnemonic::Xchg, &[Reg::RAX.into(), Reg::RAX.into()]),
726 Ok(vec![0x48, 0x87, 0xC0])
727 );
728 assert_eq!(
729 enc(Mnemonic::Xchg, &[Reg::R8.into(), Reg::RAX.into()]),
730 Ok(vec![0x49, 0x90])
731 );
732 }
733
734 #[test]
735 fn test_closest_miss_wins() {
736 assert_eq!(
737 enc(Mnemonic::Shl, &[Reg::EAX.into(), Operand::Imm(256)]),
738 Err(EncodeError::ImmediateOutOfRange { value: 256 })
739 );
740 assert_eq!(
741 enc(Mnemonic::Ret, &[Reg::RAX.into()]),
742 Err(EncodeError::NoForm {
743 mnemonic: Mnemonic::Ret
744 })
745 );
746 }
747
748 #[test]
749 fn test_encode_form_rejects_other_mnemonic() {
750 let add = table::by_op(crate::x86_64::inst::Op::Add)[0];
751 let form = table::form(add).copied();
752 let inst = Inst::new(Mnemonic::Sub, [Reg::AL.into(), Operand::Imm(1)]);
753 assert_eq!(
754 form.map(|f| encode_form(&f, &inst)),
755 Some(Err(EncodeError::NoForm {
756 mnemonic: Mnemonic::Sub
757 }))
758 );
759 }
760}