fix(interpreter): allocate stack on heap

This commit is contained in:
2025-07-08 17:40:57 +09:00
parent 20e45679fc
commit aea3143b4b
4 changed files with 36 additions and 35 deletions

View File

@@ -1,9 +1,7 @@
use clap::Parser;
use core::fmt; use core::fmt;
use crate::{ use crate::operands::{
Args, Byte, ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word,
operands::{Byte, ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word},
}; };
use super::{ use super::{
@@ -31,7 +29,7 @@ pub struct Computer {
} }
impl Computer { impl Computer {
pub fn new(data: Vec<Byte>) -> Self { pub fn new(data: Option<Vec<Byte>>, argv: Vec<String>) -> Self {
let mut computer = Self { let mut computer = Self {
regs: Register::new(), regs: Register::new(),
sregs: SegmentRegister::new(), sregs: SegmentRegister::new(),
@@ -39,28 +37,21 @@ impl Computer {
memory: Memory::new(), memory: Memory::new(),
}; };
log::info!("Initializing stack..."); log::info!("Initializing stack...");
computer.init_stack().unwrap(); computer.init_stack(argv).unwrap();
// Copy static data to 0x0000; // Copy static data to 0x0000;
log::info!("Initializing static data..."); log::info!("Initializing static data...");
for (addr, b) in data.iter().enumerate() { if let Some(inner) = data {
let val = ImmediateOperand::Byte(*b); for (addr, b) in inner.iter().enumerate() {
computer.write(val, (addr as Word).into()).unwrap(); let val = ImmediateOperand::Byte(*b);
computer.write(val, (addr as Word).into()).unwrap();
}
} }
computer computer
} }
fn init_stack(&mut self) -> Result<(), InterpreterError> { fn init_stack(&mut self, argv: Vec<String>) -> Result<(), InterpreterError> {
let mut args = Args::parse();
// cant panic, as we would not be here without a valid binary path...
let path = &args.path.unwrap();
// set executable name as argv[0]
let mut argv = Vec::from([path.clone()]);
// add the rest of the arguements argv[1], ...
argv.append(&mut args.argv);
// set default env // set default env
let envs = Vec::from(["PATH=/usr:/usr/bin".to_string()]); let envs = Vec::from(["PATH=/usr:/usr/bin".to_string()]);
@@ -276,7 +267,6 @@ impl Computer {
lhs - rhs lhs - rhs
}; };
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| { let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
// log::info!("{:?} {:?} {}", lhs, rhs, lhs < rhs);
flags.cf = lhs < rhs; flags.cf = lhs < rhs;
flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb(); flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb();
flags.zf = result.zero(); flags.zf = result.zero();
@@ -364,10 +354,10 @@ impl Computer {
self.op(op, flag_set, true, dest, src_with_carry) self.op(op, flag_set, true, dest, src_with_carry)
} }
/// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves /// Applies a binary operator `O` to the value of two
/// it to `dest`, if `write` is set, and sets flags, according to [`F`]. /// [`ArithmeticOperand`]s, saves it to `dest`, if `write` is set, and sets
/// A result can never be saved to an immediate Operand, so `dest` can only /// flags, according to `F`. A result can never be saved to an immediate
/// be a [`ModRmTarget`]. /// Operand, so `dest` can only be a [`ModRmTarget`].
fn op<O, F>( fn op<O, F>(
&mut self, &mut self,
op: O, op: O,
@@ -463,7 +453,7 @@ impl Computer {
Ok(imm) Ok(imm)
} }
/// Shift bits of data, pointed to by a [`ModRMTarget`]. /// Shift bits of data, pointed to by a [`ModRmTarget`].
/// SHL: Direction::Left, false /// SHL: Direction::Left, false
/// SHR: Direction::Right, false /// SHR: Direction::Right, false
/// SAR: Direction::Right, true /// SAR: Direction::Right, true
@@ -583,9 +573,11 @@ mod tests {
#[test] #[test]
fn test_push() { fn test_push() {
let mut c = Computer::new(Vec::from([0])); let mut c = Computer::new(None, vec!["foobar".to_string()]);
let val = ImmediateOperand::Word(0x1234); let val = ImmediateOperand::Word(0x1234);
println!("{}", c.regs); c.push_stack(val).unwrap();
assert_eq!(val, c.pop_stack().unwrap().into()) let popped = c.pop_stack().unwrap();
assert_eq!(val, popped.into())
} }
} }

View File

@@ -55,18 +55,25 @@ pub struct Interpreter {
impl Interpreter { impl Interpreter {
pub fn new(args: &Args) -> Self { pub fn new(args: &Args) -> Self {
let aout = Aout::new_from_args(args); let aout = Aout::new_from_args(args);
// set executable name as argv[0]
// note: cant panic, as we would not be here without a valid binary path...
let mut argv = vec![args.path.clone().unwrap()];
// add the rest of the arguements argv[1], ...
argv.append(&mut args.argv.clone());
Self { Self {
computer: Computer::new(aout.data), computer: Computer::new(Some(aout.data), argv),
disassembler: Disassembler::new(args), disassembler: Disassembler::new(args),
} }
} }
/// Sets instruction pointer in compliance with [`Register::CS`]. /// Sets instruction pointer in compliance with CS Segment Register.
pub fn set_ip(&mut self, ip: usize) { pub fn set_ip(&mut self, ip: usize) {
self.computer.regs.ip = ip + (self.computer.sregs.cs * 16) as usize self.computer.regs.ip = ip + (self.computer.sregs.cs * 16) as usize
} }
/// Gets instruction pointer in compliance with [`Register::CS`]. /// Gets instruction pointer in compliance with CS Segment Register.
pub fn get_ip(&self) -> usize { pub fn get_ip(&self) -> usize {
self.computer.regs.ip + (self.computer.sregs.cs * 16) as usize self.computer.regs.ip + (self.computer.sregs.cs * 16) as usize
} }

View File

@@ -5,15 +5,16 @@ use super::interpreter::InterpreterError;
/// 2*20 = 1MiB /// 2*20 = 1MiB
const MEMORY_SIZE: usize = 1048576; const MEMORY_SIZE: usize = 1048576;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct Memory { pub struct Memory {
pub raw: [Byte; MEMORY_SIZE as usize], pub raw: Vec<Byte>,
} }
impl Memory { impl Memory {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
raw: [0; MEMORY_SIZE as usize], // allocating is better for such bigger objects
raw: vec![0u8; MEMORY_SIZE],
} }
} }

View File

@@ -639,7 +639,8 @@ impl fmt::Display for MemoryIndex {
/// 16-bit pointer for access, usually with a [`SegmentRegister`] as segment /// 16-bit pointer for access, usually with a [`SegmentRegister`] as segment
/// and [`Pointer16`] as offset. /// and [`Pointer16`] as offset.
/// Generally, this type only gets constructed in rare scenarios, when the /// Generally, this type only gets constructed in rare scenarios, when the
/// [`Displacement`] of a parsed [`ModRmTarget`] is used as a raw pointer. /// displacement ([`MemoryIndex`]) of a parsed [`ModRmTarget`] is used as a
/// raw pointer.
pub struct Pointer16 { pub struct Pointer16 {
pub word: Word, pub word: Word,
} }