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

View File

@@ -55,18 +55,25 @@ pub struct Interpreter {
impl Interpreter {
pub fn new(args: &Args) -> Self {
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 {
computer: Computer::new(aout.data),
computer: Computer::new(Some(aout.data), argv),
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) {
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 {
self.computer.regs.ip + (self.computer.sregs.cs * 16) as usize
}

View File

@@ -5,15 +5,16 @@ use super::interpreter::InterpreterError;
/// 2*20 = 1MiB
const MEMORY_SIZE: usize = 1048576;
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone)]
pub struct Memory {
pub raw: [Byte; MEMORY_SIZE as usize],
pub raw: Vec<Byte>,
}
impl Memory {
pub fn new() -> 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
/// and [`Pointer16`] as offset.
/// 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 word: Word,
}