diff --git a/src/arch/x86_64/encode.rs b/src/arch/x86_64/encode.rs index b3674bb..1f44a7c 100644 --- a/src/arch/x86_64/encode.rs +++ b/src/arch/x86_64/encode.rs @@ -27,7 +27,7 @@ impl Code { self.prefix16(width); self.rex(width, src, 0, dst); self.bytes.push(0x88 | width.not8()); - self.bytes.push(modrm_regs(src, dst)); + self.modrm(src, dst); } RegImmMem::Imm(src) => { let src_width = src.width_unsigned()?; @@ -60,7 +60,7 @@ impl Code { self.prefix16(dst); self.rex(dst, dst, 0, src); self.bytes.push(0x8a | dst.not8()); - self.modrm_regdisp(dst, src); + self.modrm(dst, src); } }, RegMem::Mem(dst) => match src { @@ -73,9 +73,9 @@ impl Code { } self.prefix32(&dst)?; self.prefix16(src); - self.rex(src, src, 0, dst); + self.rex(dst, src, 0, dst); self.bytes.push(0x88 | src.not8()); - self.modrm_regdisp(src, dst); + self.modrm(src, dst); } RegImmMem::Imm(src) => { let encode_width = dst.width.min(Width::B32); @@ -94,7 +94,7 @@ impl Code { self.prefix16(encode_width); self.rex(dst, 0, 0, dst); self.bytes.push(0xc6 | encode_width.not8()); - self.modrm_regdisp(None, dst); + self.modrm(0, dst); self.imm(src, encode_width); } RegImmMem::Mem(_) => return Err("cannot move memory to memory".into()), @@ -145,9 +145,9 @@ impl Code { } pub fn lea(&mut self, dst: Reg, sym: Symbol) { - self.bytes - .extend([rex(1, dst, 0, 0), 0x8d, modrm_disp32(dst)]); - self.sym_offset4(sym); + self.rex(1, dst, 0, 0); + self.bytes.push(0x8d); + self.modrm(dst, sym); } pub fn int(&mut self, code: u8) { @@ -198,7 +198,7 @@ impl Code { width = dst_width; } - self.bytes.push(modrm(0b11, ext, dst.base())); + self.modrm(ext, dst); self.imm(src, width); Ok(()) } @@ -232,25 +232,25 @@ impl Code { } } - fn modrm_regdisp(&mut self, reg: impl Into>, mem: Mem) { - const I8_MIN: i32 = i8::MIN as i32; - const I8_MAX: i32 = i8::MAX as i32; - let mod_ = match mem.disp { - 0 => 0b00, - I8_MIN..=I8_MAX => 0b01, - _ => 0b10, + fn modrm(&mut self, reg: impl ModRMReg, rm: impl ModRMRM) { + let addr = rm.addr(); + let mod_ = match addr { + EffAddr::Mem0 | EffAddr::Sym(_) => 0b00, + EffAddr::Mem8(_) => 0b01, + EffAddr::Mem32(_) => 0b10, + EffAddr::None => 0b11, }; - let r = reg.into().map(|r| Reg::base(&r)).unwrap_or(0); - self.bytes.push(modrm(mod_, r, mem.reg.base())); - if mem.reg.base() == rsp.base() { + self.bytes + .push(((mod_ as u8) << 6) | (reg.val() << 3) | rm.rm()); + if !matches!(addr, EffAddr::None) && rm.rm() == 0b100 { // SIB self.bytes.push(0x24); } - match mod_ { - 0b00 => (), - 0b01 => self.bytes.push(mem.disp as u8), - 0b10 => self.bytes.extend(mem.disp.to_le_bytes()), - _ => unreachable!(), + match addr { + EffAddr::Mem8(disp) => self.bytes.push(disp as u8), + EffAddr::Mem32(disp) => self.bytes.extend(disp.to_le_bytes()), + EffAddr::Sym(sym) => self.sym_offset4(sym), + _ => (), } } diff --git a/src/arch/x86_64/util.rs b/src/arch/x86_64/util.rs index ed6fa87..156e227 100644 --- a/src/arch/x86_64/util.rs +++ b/src/arch/x86_64/util.rs @@ -1,18 +1,84 @@ +use crate::backend::Symbol; + use super::*; -#[inline(always)] -pub fn modrm_regs(reg: impl Into, reg_rm: impl Into) -> u8 { - modrm(0b11, reg.into().base(), reg_rm.into().base()) +pub trait ModRMRM { + fn rm(&self) -> u8; + fn addr(&self) -> EffAddr; } -#[inline(always)] -pub fn modrm_disp32(reg: impl Into) -> u8 { - modrm(0b00, reg.into().base(), 0b101) +pub enum EffAddr { + Mem0, + Mem8(i8), + Mem32(i32), + Sym(Symbol), + None, } -#[inline(always)] -pub fn modrm(mod_: u8, reg: u8, rm: u8) -> u8 { - (mod_ << 6) | (reg << 3) | rm +impl ModRMRM for Reg { + fn rm(&self) -> u8 { + self.base() + } + fn addr(&self) -> EffAddr { + EffAddr::None + } +} + +impl ModRMRM for Mem { + fn rm(&self) -> u8 { + self.reg.base() + } + fn addr(&self) -> EffAddr { + const I8_MIN: i32 = i8::MIN as i32; + const I8_MAX: i32 = i8::MAX as i32; + let disp = self.disp; + match disp { + 0 => { + if self.reg.base() == 0b101 { + EffAddr::Mem8(0) + } else { + EffAddr::Mem0 + } + } + I8_MIN..=I8_MAX => EffAddr::Mem8(disp as i8), + _ => EffAddr::Mem32(disp), + } + } +} + +impl ModRMRM for i32 { + fn rm(&self) -> u8 { + 0b101 + } + fn addr(&self) -> EffAddr { + EffAddr::Mem32(*self) + } +} + +impl ModRMRM for Symbol { + fn rm(&self) -> u8 { + 0b101 + } + + fn addr(&self) -> EffAddr { + EffAddr::Sym(*self) + } +} + +impl ModRMReg for u8 { + fn val(&self) -> u8 { + *self + } +} + +impl ModRMReg for Reg { + fn val(&self) -> u8 { + self.base() + } +} + +pub trait ModRMReg { + fn val(&self) -> u8; } #[inline(always)]