fix(interpreter): allocate stack on heap
This commit is contained in:
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user