From cf9ba376aad4878a1a905c05007e0d08c707d7f9 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Tue, 11 Feb 2020 17:49:17 -0500 Subject: [PATCH] Add value directives and strings .string, .zstring, .u64, .u32, .u16, .u8 are used before an ImmValue to determine how the memory should be laid out for that value. Signed-off-by: Alek Ratzloff --- examples/strings.asm | 45 ++++++++++++++++++++++++++++++++ src/main.rs | 33 ++++++++++++++++------- src/vm/inst.rs | 6 ++--- src/vm/obj/assemble/mod.rs | 10 +++---- src/vm/obj/syn/ast.rs | 49 ++++++++++++++++++++++++++++++++++- src/vm/obj/syn/mod.rs | 11 ++++++++ src/vm/obj/syn/parser.lalrpop | 25 ++++++++++++++---- src/vm/vm.rs | 3 +++ 8 files changed, 158 insertions(+), 24 deletions(-) create mode 100644 examples/strings.asm diff --git a/examples/strings.asm b/examples/strings.asm new file mode 100644 index 0000000..216fc5c --- /dev/null +++ b/examples/strings.asm @@ -0,0 +1,45 @@ +data $0x1000 .. $0x1100 { + zstr: .zstring "This is a zero-terminated string" + + .export zstr +} + +code $0x0 { + zstr_len: + storeimm32 %r15, $0xFF + storeimm32 %r16, $1 + storeimm64 %r20, zstr_next + storeimm64 %r21, exit_zstr + + regcopy %r10, %r00 + + zstr_next: + load %r11, %r10 + and %r11, %r15 + cmpeq %r11, %null + jnz %r21 + add %r10, %r16 + jmp %r20 + + main: + storeimm64 %r05, zstr_len + storeimm64 %r00, zstr + jmp %r05 + + exit_zstr: + regcopy %status, %r10 + halt + + ineg %r00 + add %r10, %r00 + regcopy %status, %r10 + + end: + halt + + .export main +} + +meta { + entry: main +} diff --git a/src/main.rs b/src/main.rs index fc8bab5..2139285 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,7 @@ fn main() -> Result<()> { } }; let obj = vm::obj::obj::Object::try_from(&ast)?; - //dump(&obj)?; + dump(&obj)?; let mut vm = vm::vm::Vm::new(); vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb let status = vm.run()?; @@ -45,16 +45,31 @@ fn dump(obj: &vm::obj::obj::Object) -> Result<()> { use vm::visit::VisitInst; let mut stdout = io::stdout(); for section in &obj.sections { - let mut disasm = match section { - Section::Code { start, contents, .. } => { - vm::disassemble::Disassemble::new(&mut stdout, contents, *start) + match section { + Section::Data { start, contents, .. } => { + const WIDTH: usize = 4; + println!("data section at 0x{:08x}", start); + for (i, b) in contents.iter().enumerate() { + if i % WIDTH == 0 { + print!("{:08x} | ", ((*start as usize) + i)); + } + print!("{:02x} ", b); + if i % WIDTH == (WIDTH - 1) { + println!(); + } + } + println!(); } - Section::Meta { .. } | Section::Data { .. } => continue, + Section::Code { start, contents, .. } => { + println!("code section at 0x{:08x}", start); + let mut disasm = vm::disassemble::Disassemble::new(&mut stdout, contents, *start); + while !disasm.is_done() { + disasm.visit_inst()?; + } + println!(); + } + Section::Meta { .. } => continue, }; - while !disasm.is_done() { - disasm.visit_inst()?; - } - println!(); } Ok(()) } diff --git a/src/vm/inst.rs b/src/vm/inst.rs index 9c2a33e..a3012d4 100644 --- a/src/vm/inst.rs +++ b/src/vm/inst.rs @@ -50,10 +50,10 @@ instructions! { pub fn inst_len(op: InstOp) -> usize { match op { // 2 bytes - INEG | INV | NOT | HALT | NOP => 2, + HALT | NOP => 2, // 4 bytes - ADD | MUL | DIV | MOD | AND | OR | XOR | SHL | SHR | CMPEQ | CMPLT | JMP | JZ | JNZ - | LOAD | REGCOPY | MEMCOPY | STORE => 4, + ADD | MUL | DIV | INEG | INV | NOT | MOD | AND | OR | XOR | SHL | SHR | CMPEQ | CMPLT + | JMP | JZ | JNZ | LOAD | REGCOPY | MEMCOPY | STORE => 4, // Immediates - 4+ bytes STOREIMM64 => 16, STOREIMM32 => 8, diff --git a/src/vm/obj/assemble/mod.rs b/src/vm/obj/assemble/mod.rs index c5f6245..a03abba 100644 --- a/src/vm/obj/assemble/mod.rs +++ b/src/vm/obj/assemble/mod.rs @@ -68,10 +68,8 @@ impl<'a> Assemble<'a> { bytes.extend(self.assemble_inst(inst)); } Line::LabelDef(_) => { /* no-op */ } - Line::ImmValue(value) => { - let value = - self.get_value(value).expect("TODO : value label not found"); - bytes.extend(&value.to_le_bytes()); + Line::ValueDecl(decl) => { + bytes.extend(decl.to_bytes()); } Line::Export(_) => { /* no-op */ } } @@ -138,8 +136,8 @@ impl<'a> Assemble<'a> { labels.insert(label.to_string(), pos as u64); } } - Line::ImmValue(_) => { - pos += 8; + Line::ValueDecl(decl) => { + pos += decl.len(); } Line::Export(name) => { if export { diff --git a/src/vm/obj/syn/ast.rs b/src/vm/obj/syn/ast.rs index 5874cc4..0cf8f4d 100644 --- a/src/vm/obj/syn/ast.rs +++ b/src/vm/obj/syn/ast.rs @@ -25,7 +25,7 @@ pub enum SectionOrg { pub enum Line { Inst(Inst), LabelDef(String), - ImmValue(ImmValue), + ValueDecl(ValueDecl), Export(String), } @@ -35,6 +35,53 @@ pub enum ImmValue { Label(String), } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ValueDecl { + U64(u64), + U32(u64), + U16(u64), + U8(u64), + String(String), + ZString(String), +} + +impl ValueDecl { + pub fn len(&self) -> usize { + match self { + ValueDecl::U64(_) => 8, + ValueDecl::U32(_) => 4, + ValueDecl::U16(_) => 2, + ValueDecl::U8(_) => 1, + ValueDecl::String(s) => s.as_bytes().len() + 8, + ValueDecl::ZString(s) => s.as_bytes().len() + 1, + } + } + + pub fn to_bytes(&self) -> Vec { + let len = self.len(); + let bytes = match self { + ValueDecl::U64(v) => v.to_le_bytes().to_vec(), + ValueDecl::U32(v) => v.to_le_bytes()[0..4].to_vec(), + ValueDecl::U16(v) => v.to_le_bytes()[0..2].to_vec(), + ValueDecl::U8(v) => vec![(v & 0xff) as u8], + ValueDecl::String(s) => { + let mut bytes = Vec::with_capacity(self.len()); + bytes.extend(&(s.len() as u64).to_le_bytes()); + bytes.extend(s.as_bytes()); + bytes + } + ValueDecl::ZString(s) => { + let mut bytes = Vec::with_capacity(self.len()); + bytes.extend(s.as_bytes()); + bytes.push(0); + bytes + } + }; + assert_eq!(bytes.len(), len); + bytes + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum Inst { Add(Reg, Reg), diff --git a/src/vm/obj/syn/mod.rs b/src/vm/obj/syn/mod.rs index e4b69f8..a6e2101 100644 --- a/src/vm/obj/syn/mod.rs +++ b/src/vm/obj/syn/mod.rs @@ -3,3 +3,14 @@ use lalrpop_util::lalrpop_mod; lalrpop_mod!(pub parser, "/vm/obj/syn/parser.rs"); pub mod ast; pub mod error; + +pub fn unescape_string(s: impl AsRef) -> String { + let s = s.as_ref(); + s.replace(r"\\", "\\") + .replace("\\n", "\n") + .replace("\\r", "\r") + .replace("\\t", "\t") + .replace("\\t", "\t") + .replace("\\0", "\0") + .replace("\\\"", "\"") +} diff --git a/src/vm/obj/syn/parser.lalrpop b/src/vm/obj/syn/parser.lalrpop index c7b669d..73c0c3f 100644 --- a/src/vm/obj/syn/parser.lalrpop +++ b/src/vm/obj/syn/parser.lalrpop @@ -1,6 +1,6 @@ use std::str::FromStr; use crate::vm::{ - obj::syn::ast::*, + obj::syn::{unescape_string, ast::*}, reg::*, }; @@ -10,15 +10,13 @@ LabelDef: String = {