This commit is contained in:
2026-06-13 13:44:03 -04:00
parent bdeb0d821c
commit 1e39675c29
8 changed files with 94 additions and 46 deletions
+29 -3
View File
@@ -172,9 +172,35 @@ impl Code {
self.bytes.push(0xc3);
}
pub fn sub(&mut self) {
// sub esp 40 iirc
self.bytes.extend([0x48, 0x83, 0xec, 0x28]);
pub fn sub(&mut self, mut dst: Reg, src: impl Into<Imm>) -> ERes {
let mut src = src.into();
let mut width = src.width_signed()?;
let dst_width = dst.width().min(Width::B32);
self.prefix16(dst_width);
self.rex(dst, 0, 0, dst);
if width > dst_width {
width = src.width_unsigned()?;
if dst.width() == Width::B64 || width > dst_width {
return Err("immediate overflow".into());
}
src = src.reinterpret(dst_width);
width = src.width_signed()?;
}
if dst.width() == Width::B8 {
self.bytes.push(0x80);
} else {
if width == Width::B8 {
self.bytes.push(0x83);
} else {
self.bytes.push(0x81);
width = dst_width;
}
}
self.bytes.push(modrm(0b11, 0b101, dst.base()));
self.imm(src, width);
Ok(())
}
fn prefix16(&mut self, width: impl Into<Width>) {
+48
View File
@@ -0,0 +1,48 @@
mod setup;
use setup::*;
#[test]
fn mov() {
let c = &mut TestCtx::new("mov");
for dst in regs() {
for src in regs() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in regs() {
for src in mems() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in regs() {
for src in imms() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in mems() {
for src in regs() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in mems() {
for src in imms() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
}
#[test]
fn sub() {
let c = &mut TestCtx::new("mov");
for dst in regs() {
for src in imms() {
eq(c, format!("sub {dst}, {src}"), |c| c.sub(dst, src))
}
}
}
@@ -32,50 +32,15 @@ const IMMS: &[i128] = &[
const WIDTHS: &[Width] = &[Width::B8, Width::B16, Width::B32, Width::B64];
#[test]
fn mov() {
let c = &mut TestCtx::new("mov");
for dst in regs() {
for src in regs() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in regs() {
for src in mems() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in regs() {
for src in imms() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in mems() {
for src in regs() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
for dst in mems() {
for src in imms() {
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
}
}
}
fn imms() -> impl Iterator<Item = i128> {
pub fn imms() -> impl Iterator<Item = i128> {
IMMS.iter().cloned()
}
fn regs() -> impl Iterator<Item = Reg> {
pub fn regs() -> impl Iterator<Item = Reg> {
Reg::IMPORTANT.iter().cloned()
}
fn mems() -> impl Iterator<Item = Mem> {
pub fn mems() -> impl Iterator<Item = Mem> {
gen move {
for &reg in Reg::IMPORTANT {
for &disp in DISPS {
@@ -87,14 +52,14 @@ fn mems() -> impl Iterator<Item = Mem> {
}
}
struct TestCtx {
pub struct TestCtx {
path: String,
code: Code,
cache: HashMap<String, Result<Vec<u8>, String>>,
changed: bool,
}
fn eq(
pub fn eq(
ctx: &mut TestCtx,
asm: impl AsRef<str>,
instr: impl FnOnce(&mut Code) -> Result<(), CompilerMsg>,
@@ -176,7 +141,7 @@ fn write(path: &str, binary: &[u8]) {
const CACHE_PATH: &str = "test/nasm_cache";
impl TestCtx {
fn new(name: &str) -> Self {
pub fn new(name: &str) -> Self {
let path = CACHE_PATH.to_string() + "/" + name;
let cache = match std::fs::read(&path) {
Ok(bytes) => bitcode::decode(&bytes).unwrap_or_default(),
+1 -1
View File
@@ -11,7 +11,7 @@ fn hello() -> Result<(), CompilerMsg> {
let entry = program.func(
"main",
[Instr::Asm(encode(|c| {
c.sub();
c.sub(esp, 0x28)?;
// stdout
c.mov(ecx, -11)?;
c.call_mem(get_std_handle);
+1 -1
View File
@@ -1,2 +1,2 @@
mod full;
mod nasm;
mod asm;
+9
View File
@@ -53,6 +53,15 @@ impl Imm {
_ => return Err(Self::overflow_msg()),
})
}
pub fn reinterpret(&self, width: Width) -> Self {
Self(match width {
Width::B8 => self.0 as i8 as i128,
Width::B16 => self.0 as i16 as i128,
Width::B32 => self.0 as i32 as i128,
Width::B64 => self.0 as i64 as i128,
})
}
}
impl TryFrom<Imm> for u8 {
Binary file not shown.
Binary file not shown.