From 758f014afb8ec5c20ef2fc862fc12e80f65d3d25 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Fri, 13 Dec 2024 01:13:20 +0100 Subject: mem: make all memory operands explicit in size * remove non size explicit MemOp * introduce private Mem trait * implement Mem8, Mem16, Mem32 and Mem64 operands * implement EncodeX helpers based on explicit memory operands * fixup instructions with explicit memory operands * fixup examples --- src/asm.rs | 139 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 66 insertions(+), 73 deletions(-) (limited to 'src/asm.rs') diff --git a/src/asm.rs b/src/asm.rs index 711de8a..616ba87 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -2,6 +2,7 @@ use crate::*; use imm::Imm; +use mem::{AddrMode, Mem}; use reg::Reg; /// Encode the `REX` byte. @@ -155,24 +156,22 @@ impl Asm { } /// Encode a memory operand instruction. - pub(crate) fn encode_m(&mut self, opc: u8, opc_ext: u8, op1: T) + pub(crate) fn encode_m(&mut self, opc: u8, opc_ext: u8, op1: T) where Self: EncodeM, { - let op1 = op1.mem_op(); - // M operand encoding. // op1 -> modrm.rm - let (mode, rm) = match op1 { - MemOp::Indirect(..) => { + let (mode, rm) = match op1.mode() { + AddrMode::Indirect => { assert!(!op1.base().need_sib() && !op1.base().is_pc_rel()); (0b00, op1.base().idx()) } - MemOp::IndirectDisp(..) => { + AddrMode::IndirectDisp => { assert!(!op1.base().need_sib()); (0b10, op1.base().idx()) } - MemOp::IndirectBaseIndex(..) => { + AddrMode::IndirectBaseIndex => { assert!(!op1.base().is_pc_rel()); // Using rsp as index register is interpreted as just base w/o offset. // https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2 @@ -193,31 +192,33 @@ impl Asm { self.emit_optional(&[prefix, rex]); self.emit(&[opc, modrm]); - match op1 { - MemOp::Indirect(..) => {} - MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()), - MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]), + match op1.mode() { + AddrMode::Indirect => {} + AddrMode::IndirectDisp => self.emit(&op1.disp().to_ne_bytes()), + AddrMode::IndirectBaseIndex => { + self.emit(&[sib(0, op1.index().idx(), op1.base().idx())]) + } } } /// Encode a memory-immediate instruction. - pub(crate) fn encode_mi(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T) + pub(crate) fn encode_mi(&mut self, opc: u8, opc_ext: u8, op1: M, op2: T) where - Self: EncodeMI, + Self: EncodeMI, { // MI operand encoding. // op1 -> modrm.rm // op2 -> imm - let (mode, rm) = match op1 { - MemOp::Indirect(..) => { + let (mode, rm) = match op1.mode() { + AddrMode::Indirect => { assert!(!op1.base().need_sib() && !op1.base().is_pc_rel()); (0b00, op1.base().idx()) } - MemOp::IndirectDisp(..) => { + AddrMode::IndirectDisp => { assert!(!op1.base().need_sib()); (0b10, op1.base().idx()) } - MemOp::IndirectBaseIndex(..) => { + AddrMode::IndirectBaseIndex => { assert!(!op1.base().is_pc_rel()); // Using rsp as index register is interpreted as just base w/o offset. // https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2 @@ -233,37 +234,39 @@ impl Asm { rm, /* rm */ ); - let prefix = >::legacy_prefix(); - let rex = >::rex(&op1); + let prefix = >::legacy_prefix(); + let rex = >::rex(&op1); self.emit_optional(&[prefix, rex]); self.emit(&[opc, modrm]); - match op1 { - MemOp::Indirect(..) => {} - MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()), - MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]), + match op1.mode() { + AddrMode::Indirect => {} + AddrMode::IndirectDisp => self.emit(&op1.disp().to_ne_bytes()), + AddrMode::IndirectBaseIndex => { + self.emit(&[sib(0, op1.index().idx(), op1.base().idx())]) + } } self.emit(op2.bytes()); } /// Encode a memory-register instruction. - pub(crate) fn encode_mr(&mut self, opc: u8, op1: MemOp, op2: T) + pub(crate) fn encode_mr(&mut self, opc: u8, op1: M, op2: T) where - Self: EncodeMR, + Self: EncodeMR, { // MR operand encoding. // op1 -> modrm.rm // op2 -> modrm.reg - let (mode, rm) = match op1 { - MemOp::Indirect(..) => { + let (mode, rm) = match op1.mode() { + AddrMode::Indirect => { assert!(!op1.base().need_sib() && !op1.base().is_pc_rel()); (0b00, op1.base().idx()) } - MemOp::IndirectDisp(..) => { + AddrMode::IndirectDisp => { assert!(!op1.base().need_sib()); (0b10, op1.base().idx()) } - MemOp::IndirectBaseIndex(..) => { + AddrMode::IndirectBaseIndex => { assert!(!op1.base().is_pc_rel()); // Using rsp as index register is interpreted as just base w/o offset. // https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2 @@ -279,22 +282,24 @@ impl Asm { rm, /* rm */ ); - let prefix = >::legacy_prefix(); - let rex = >::rex(&op1, op2); + let prefix = >::legacy_prefix(); + let rex = >::rex(&op1, op2); self.emit_optional(&[prefix, rex]); self.emit(&[opc, modrm]); - match op1 { - MemOp::Indirect(..) => {} - MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()), - MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]), + match op1.mode() { + AddrMode::Indirect => {} + AddrMode::IndirectDisp => self.emit(&op1.disp().to_ne_bytes()), + AddrMode::IndirectBaseIndex => { + self.emit(&[sib(0, op1.index().idx(), op1.base().idx())]) + } } } /// Encode a register-memory instruction. - pub(crate) fn encode_rm(&mut self, opc: u8, op1: T, op2: MemOp) + pub(crate) fn encode_rm(&mut self, opc: u8, op1: T, op2: M) where - Self: EncodeMR, + Self: EncodeMR, { // RM operand encoding. // op1 -> modrm.reg @@ -370,15 +375,15 @@ impl EncodeR for Asm { impl EncodeR for Asm {} /// Encode helper for memory-register instructions. -pub(crate) trait EncodeMR { +pub(crate) trait EncodeMR { fn legacy_prefix() -> Option { None } - fn rex(op1: &MemOp, op2: T) -> Option { - if op2.need_rex() || op1.base().is_ext() || op1.index().is_ext() { + fn rex(op1: &M, op2: T) -> Option { + if M::is_64() || op2.is_ext() || op1.base().is_ext() || op1.index().is_ext() { Some(rex( - op2.rexw(), + M::is_64(), op2.idx(), op1.index().idx(), op1.base().idx(), @@ -389,71 +394,59 @@ pub(crate) trait EncodeMR { } } -impl EncodeMR for Asm {} -impl EncodeMR for Asm { +impl EncodeMR for Asm {} +impl EncodeMR for Asm { fn legacy_prefix() -> Option { Some(0x66) } } -impl EncodeMR for Asm {} -impl EncodeMR for Asm {} +impl EncodeMR for Asm {} +impl EncodeMR for Asm {} /// Encode helper for memory-immediate instructions. -pub(crate) trait EncodeMI { +pub(crate) trait EncodeMI { fn legacy_prefix() -> Option { None } - fn rex(op1: &MemOp) -> Option { - if op1.base().is_ext() || op1.index().is_ext() { - Some(rex(false, 0, op1.index().idx(), op1.base().idx())) + fn rex(op1: &M) -> Option { + if M::is_64() || op1.base().is_ext() || op1.index().is_ext() { + Some(rex(M::is_64(), 0, op1.index().idx(), op1.base().idx())) } else { None } } } -impl EncodeMI for Asm {} -impl EncodeMI for Asm { +impl EncodeMI for Asm {} +impl EncodeMI for Asm { fn legacy_prefix() -> Option { Some(0x66) } } -impl EncodeMI for Asm {} +impl EncodeMI for Asm {} +impl EncodeMI for Asm {} /// Encode helper for memory operand instructions. -pub(crate) trait EncodeM { +pub(crate) trait EncodeM { fn legacy_prefix() -> Option { None } - fn rex(op1: &MemOp) -> Option { - if op1.base().is_ext() || op1.index().is_ext() || Self::is_64bit() { - Some(rex( - Self::is_64bit(), - 0, - op1.index().idx(), - op1.base().idx(), - )) + fn rex(op1: &M) -> Option { + if M::is_64() || op1.base().is_ext() || op1.index().is_ext() { + Some(rex(M::is_64(), 0, op1.index().idx(), op1.base().idx())) } else { None } } - - fn is_64bit() -> bool { - false - } } -impl EncodeM for Asm {} -impl EncodeM for Asm { +impl EncodeM for Asm {} +impl EncodeM for Asm { fn legacy_prefix() -> Option { Some(0x66) } } -impl EncodeM for Asm {} -impl EncodeM for Asm { - fn is_64bit() -> bool { - true - } -} +impl EncodeM for Asm {} +impl EncodeM for Asm {} -- cgit v1.2.3