From 2078d2dda1dfcf1041d778754fe9536025ec1c0a Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Feb 2026 15:48:01 +0100 Subject: [PATCH 01/34] some initial stuff for interpreter. it already can do quite some stuff --- .gitignore | 4 +- interpreter/Cargo.lock | 32 +++ interpreter/Cargo.toml | 9 + interpreter/run | 8 + interpreter/src/interpreter.rs | 273 ++++++++++++++++++++++ interpreter/src/lib.rs | 2 + interpreter/src/main.rs | 28 +++ interpreter/src/memory.rs | 132 +++++++++++ interpreter/test_files/test_branching.asm | 32 +++ interpreter/test_files/test_let.asm | 14 ++ 10 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 interpreter/Cargo.lock create mode 100644 interpreter/Cargo.toml create mode 100755 interpreter/run create mode 100644 interpreter/src/interpreter.rs create mode 100644 interpreter/src/lib.rs create mode 100644 interpreter/src/main.rs create mode 100644 interpreter/src/memory.rs create mode 100644 interpreter/test_files/test_branching.asm create mode 100644 interpreter/test_files/test_let.asm diff --git a/.gitignore b/.gitignore index 98e1f88..52ad222 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ # # already existing elements were commented out -#/target +**/target /tmp /temp /interpreter/target @@ -14,3 +14,5 @@ *.asm *.core +**/tmp +**/temp diff --git a/interpreter/Cargo.lock b/interpreter/Cargo.lock new file mode 100644 index 0000000..d05ddc0 --- /dev/null +++ b/interpreter/Cargo.lock @@ -0,0 +1,32 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "Thumb2Interpreter" +version = "0.1.0" +dependencies = [ + "pretty_assertions", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml new file mode 100644 index 0000000..472d808 --- /dev/null +++ b/interpreter/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "Thumb2Interpreter" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[dev-dependencies] +pretty_assertions = "1.4" diff --git a/interpreter/run b/interpreter/run new file mode 100755 index 0000000..ca0dd81 --- /dev/null +++ b/interpreter/run @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ "$1" = "--debug" ]; then + shift + cargo run -- "$@" +else + RUSTFLAGS="-A warnings" cargo run --release -- "$@" +fi diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs new file mode 100644 index 0000000..3bf030c --- /dev/null +++ b/interpreter/src/interpreter.rs @@ -0,0 +1,273 @@ +use std::{fs::File, io::BufRead}; + +use crate::memory::EmulatorMemory; + +pub struct Interpreter { + memory: EmulatorMemory, + file: Vec, + debug: bool, +} + +impl Interpreter { + pub fn new() -> Self { + Self { + memory: EmulatorMemory::new(), + file: Vec::new(), + debug: cfg!(debug_assertions), + } + } + + pub fn set_debug(&mut self, debug: bool) { + self.debug = debug; + } + pub fn read_file(&mut self, file_path: &String) -> bool { + let file = File::open(file_path).expect("Could not open file: {file_path}"); + let lines: Vec = std::io::BufReader::new(file) + .lines() + .map(|line| line.expect("Could not read line from file")) + .collect(); + self.file = lines; + true + } + + pub fn print_registers(&self) { + if self.debug { + self.memory.print_registers(); + } + } + + pub fn print_memory(&self) { + println!("╔════════════════════════════════════════════════════════════════╗"); + println!("║ MEMORY STATE ║"); + println!("╠════════════════════════════════════════════════════════════════╣"); + + println!("║ REGISTERS: ║"); + println!("╟──────────────────────────────────────────────────────────────────╢"); + for (i, &value) in self.memory.get_registers().iter().enumerate() { + if i % 4 == 0 { + print!("║ "); + } + print!("r{:2}: {:>10} ", i, value); + if i % 4 == 3 { + println!("║"); + } + } + if 32 % 4 != 0 { + println!("║"); + } + + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!("║ STACK POINTER: ║"); + println!( + "║ SP: {:>10} (0x{:08x}) ║", + self.memory.get_sp(), + self.memory.get_sp() + ); + + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!("║ HEAP: ║"); + println!( + "║ Heap allocated: {:>6} bytes ║", + self.memory.get_heap_alloc_index() + ); + println!( + "║ Heap size: {:>6} bytes ║", + self.memory.get_heap_size() + ); + + let heap_data = self.memory.get_heap(); + if self.memory.get_heap_alloc_index() > 0 { + println!("║ Heap contents (first 256 bytes): ║"); + let display_len = std::cmp::min(256, self.memory.get_heap_alloc_index()); + for row in (0..display_len).step_by(16) { + let end = std::cmp::min(row + 16, display_len); + print!("║ {:04x}: ", row); + for i in row..end { + print!("{:02x} ", heap_data[i]); + } + for _ in end..row + 16 { + print!(" "); + } + print!(" |"); + for i in row..end { + let byte = heap_data[i]; + if byte >= 32 && byte < 127 { + print!("{}", byte as char); + } else { + print!("."); + } + } + for _ in end..row + 16 { + print!(" "); + } + println!("|║"); + } + } + + println!("╚════════════════════════════════════════════════════════════════╝"); + } + + pub fn shout_file(self) { + println!("------------------- SHOUT FILE START -------------------"); + for (idx, line_content) in self.file.iter().enumerate() { + println!("Line {idx}, Content: {line_content}"); + } + println!("-------------------- SHOUT FILE END --------------------"); + } + + fn get_start(&self) -> Result { + for (idx, content) in self.file.iter().enumerate() { + if content.contains("_start:") { + return Ok(idx); + } + } + Err("_start label not found".to_string()) + } + + fn get_start_block(&self) -> Vec { + let start = match self.get_start() { + Ok(start) => start, + _ => panic!("ERROR IN GETTING START BLOCK"), + }; + let mut res: Vec = Vec::new(); + res.push(self.file.get(start).unwrap().clone()); + for i in start..self.file.len() { + let content = self.file.get(i).unwrap(); + if content.starts_with(" ") { + res.push(content.clone()); + } + } + res + } + + fn exec_mov(&mut self, content: String) { + if self.debug { + println!("Executing mov instruction: {}", content); + } + let parts: Vec<&str> = content.split_whitespace().collect(); + let dest = parts[1].replace(",", ""); + let src = parts[2].replace(",", ""); + + let dest_idx: usize = dest[1..].parse().expect("Failed to parse register index"); + let value: u32; + + if let Some(value_str) = src.strip_prefix('#') { + value = value_str.parse().expect("Failed to parse immediate value"); + self.memory.set_reg(dest_idx, value); + if self.debug { + println!("Mock: mov r{}, #{} (stored in register)", dest_idx, value); + } + } else { + let src_idx: usize = src[1..].parse().expect("Failed to parse register index"); + value = self.memory.get_reg(src_idx); + self.memory.set_reg(dest_idx, value); + if self.debug { + println!( + "Mock: mov r{}, r{} (register to register)", + dest_idx, src_idx + ); + } + } + } + + fn exec_svc(&mut self, content: String) -> Option { + if self.debug { + println!("Executing svc instruction: {}", content); + } + + let parts: Vec<&str> = content.split_whitespace().collect(); + if let Some(svc_num) = parts.get(1) { + let svc_num = svc_num.replace("#", ""); + if svc_num == "0" { + let syscall_num = self.memory.get_reg(7); + if syscall_num == 1 { + let exit_code = self.memory.get_reg(0); + if self.debug { + println!("Exit syscall (r7=1), returning exit code: {}", exit_code); + } + return Some(exit_code); + } + } + } + None + } + + fn exec_sub(&mut self, content: String) { + let parts: Vec<&str> = content.split_whitespace().collect(); + let dest = parts[1].replace(",", ""); + let src = parts[2].replace(",", ""); + let val_or_reg = parts[3].replace(",", ""); + let sub_value: u32; + if let Some(value_str) = val_or_reg.strip_prefix('#') { + let value_str = value_str.replace("#", ""); + sub_value = value_str.parse().expect("literal"); + } else { + let value_str = val_or_reg.replace("r", ""); + let this_reg: usize = value_str.parse().expect("Failed to parse register index"); + sub_value = self.memory.get_reg(this_reg); + } + + let src_val: u32; + if let Some(src_str) = src.strip_prefix('r') { + let src_register = src_str + .replace("r", "") + .parse() + .expect("Unable to parse register"); + src_val = self.memory.get_reg(src_register); + } else { + src_val = self.memory.get_sp() as u32; + } + + if let Some(dst_str) = dest.strip_prefix('r') { + let dst_register = dst_str + .replace("r", "") + .parse() + .expect("Unable to parse register"); + let dst_val = self.memory.get_reg(dst_register); + } else if src == "sp" { + self.memory.set_sp((src_val - sub_value) as usize); + } + } + + pub fn execute(&mut self) -> u32 { + let start_block = self.get_start_block(); + for (i, content) in start_block.into_iter().enumerate() { + if i == 0 { + if self.debug { + println!("RUNNING {content}"); + } + continue; + } + match content.split_whitespace().next() { + Some("mov") => { + self.exec_mov(content); + } + Some("svc") => { + if let Some(exit_code) = self.exec_svc(content) { + return exit_code; + } + } + Some("sub") => { + let mut sp = self.memory.get_sp(); + println!("StackPointer = {sp}"); + self.exec_sub(content); + sp = self.memory.get_sp(); + println!("StackPointer = {sp}"); + } + Some(other) => { + panic!("Unknown instruction: {}", other); + } + None => { + panic!("Empty line encountered"); + } + } + } + 0 + } +} + +impl Default for Interpreter { + fn default() -> Self { + Self::new() + } +} diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs new file mode 100644 index 0000000..becf5da --- /dev/null +++ b/interpreter/src/lib.rs @@ -0,0 +1,2 @@ +pub mod interpreter; +pub mod memory; diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs new file mode 100644 index 0000000..85be995 --- /dev/null +++ b/interpreter/src/main.rs @@ -0,0 +1,28 @@ +use std::env; +use Thumb2Interpreter::interpreter::Interpreter; + +fn main() { + let args: Vec = env::args().collect(); + + if args.len() < 2 { + eprintln!("Error: Please provide a Trivilang Thumb2 Source Code File"); + std::process::exit(1); + } + + let debug = if args.iter().any(|a| a == "--debug" || a == "-d") { + true + } else if args.iter().any(|a| a == "--release-debug" || a == "-r") { + false + } else { + cfg!(debug_assertions) + }; + + let file_path = &args[1]; + let mut interpreter = Interpreter::default(); + interpreter.set_debug(debug); + interpreter.read_file(file_path); + interpreter.print_memory(); + let return_code = interpreter.execute(); + interpreter.print_memory(); + println!("Execution returned with return_code {return_code}") +} diff --git a/interpreter/src/memory.rs b/interpreter/src/memory.rs new file mode 100644 index 0000000..32358b6 --- /dev/null +++ b/interpreter/src/memory.rs @@ -0,0 +1,132 @@ +const STACK_SIZE: usize = 1024 * 1024; +const HEAP_SIZE: usize = 1024 * 1024; +const NUM_REGISTERS: usize = 32; + +pub struct EmulatorMemory { + registers: [u32; NUM_REGISTERS], + pc: u32, + stack: Vec, + heap: Vec, + heap_alloc_index: usize, + stack_pointer: usize, +} + +impl EmulatorMemory { + pub fn new() -> Self { + Self { + registers: [0; NUM_REGISTERS], + pc: 0, + stack: vec![0; STACK_SIZE], + heap: vec![0; HEAP_SIZE], + heap_alloc_index: 0, + stack_pointer: STACK_SIZE, + } + } + + pub fn push32(&mut self, value: u32) { + self.stack_pointer -= 4; + let bytes = value.to_le_bytes(); + self.stack[self.stack_pointer..self.stack_pointer + 4].copy_from_slice(&bytes); + } + + pub fn pop32(&mut self) -> u32 { + let bytes = [ + self.stack[self.stack_pointer], + self.stack[self.stack_pointer + 1], + self.stack[self.stack_pointer + 2], + self.stack[self.stack_pointer + 3], + ]; + self.stack_pointer += 4; + u32::from_le_bytes(bytes) + } + + pub fn push16(&mut self, value: u16) { + self.stack_pointer -= 2; + let bytes = value.to_le_bytes(); + self.stack[self.stack_pointer..self.stack_pointer + 2].copy_from_slice(&bytes); + } + + pub fn pop16(&mut self) -> u16 { + let bytes = [ + self.stack[self.stack_pointer], + self.stack[self.stack_pointer + 1], + ]; + self.stack_pointer += 2; + u16::from_le_bytes(bytes) + } + + pub fn alloc(&mut self, size: usize) -> Result { + if self.heap_alloc_index + size > HEAP_SIZE { + return Err("Out of heap memory".to_string()); + } + let addr = self.heap_alloc_index; + self.heap_alloc_index += size; + Ok(addr) + } + + pub fn read32(&self, addr: usize) -> u32 { + let bytes = [ + self.heap[addr], + self.heap[addr + 1], + self.heap[addr + 2], + self.heap[addr + 3], + ]; + u32::from_le_bytes(bytes) + } + + pub fn write32(&mut self, addr: usize, value: u32) { + self.heap[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); + } + + pub fn get_sp(&self) -> usize { + self.stack_pointer + } + + pub fn set_sp(&mut self, sp: usize) { + self.stack_pointer = sp; + } + + pub fn get_pc(&self) -> u32 { + self.pc + } + + pub fn set_pc(&mut self, pc: u32) { + self.pc = pc; + } + + pub fn get_reg(&self, index: usize) -> u32 { + self.registers[index] + } + + pub fn set_reg(&mut self, index: usize, value: u32) { + self.registers[index] = value; + } + + pub fn get_registers(&self) -> &[u32; NUM_REGISTERS] { + &self.registers + } + + pub fn get_heap_alloc_index(&self) -> usize { + self.heap_alloc_index + } + + pub fn get_heap_size(&self) -> usize { + self.heap.len() + } + + pub fn get_heap(&self) -> &Vec { + &self.heap + } + + pub fn print_registers(&self) { + for (i, &value) in self.registers.iter().enumerate() { + println!("r{}: {}", i, value); + } + } +} + +impl Default for EmulatorMemory { + fn default() -> Self { + Self::new() + } +} diff --git a/interpreter/test_files/test_branching.asm b/interpreter/test_files/test_branching.asm new file mode 100644 index 0000000..16ec6ff --- /dev/null +++ b/interpreter/test_files/test_branching.asm @@ -0,0 +1,32 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + mov r0, #11 + str r0, [sp, #0] + b endif_0 +else_0: + mov r0, #12 + str r0, [sp, #0] +endif_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_files/test_let.asm b/interpreter/test_files/test_let.asm new file mode 100644 index 0000000..4d4f96c --- /dev/null +++ b/interpreter/test_files/test_let.asm @@ -0,0 +1,14 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r4, #27 + mov r0, r4 + mov r7, #1 + svc #0 + +.size _start, .-_start From 1c563129699fb5d97a17389e2a0e06607d8fb540 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Feb 2026 22:57:54 +0100 Subject: [PATCH 02/34] pretty print fixes --- interpreter/src/interpreter.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 3bf030c..e9bbd42 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -37,9 +37,9 @@ impl Interpreter { } pub fn print_memory(&self) { - println!("╔════════════════════════════════════════════════════════════════╗"); + println!("╔══════════════════════════════════════════════════════════════════╗"); println!("║ MEMORY STATE ║"); - println!("╠════════════════════════════════════════════════════════════════╣"); + println!("╠══════════════════════════════════════════════════════════════════╣"); println!("║ REGISTERS: ║"); println!("╟──────────────────────────────────────────────────────────────────╢"); @@ -49,7 +49,7 @@ impl Interpreter { } print!("r{:2}: {:>10} ", i, value); if i % 4 == 3 { - println!("║"); + println!(" ║"); } } if 32 % 4 != 0 { @@ -59,7 +59,7 @@ impl Interpreter { println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ STACK POINTER: ║"); println!( - "║ SP: {:>10} (0x{:08x}) ║", + "║ SP: {:>10} (0x{:08x}) ║", self.memory.get_sp(), self.memory.get_sp() ); @@ -67,11 +67,11 @@ impl Interpreter { println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ HEAP: ║"); println!( - "║ Heap allocated: {:>6} bytes ║", + "║ Heap allocated: {:>6} bytes ║", self.memory.get_heap_alloc_index() ); println!( - "║ Heap size: {:>6} bytes ║", + "║ Heap size: {:>6} bytes ║", self.memory.get_heap_size() ); @@ -104,7 +104,7 @@ impl Interpreter { } } - println!("╚════════════════════════════════════════════════════════════════╝"); + println!("╚══════════════════════════════════════════════════════════════════╝"); } pub fn shout_file(self) { From b4b0e7bb36c03401ec9424c97c0c81f0245185c1 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Feb 2026 23:07:37 +0100 Subject: [PATCH 03/34] updates --- interpreter/src/interpreter.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index e9bbd42..e7df904 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -37,6 +37,9 @@ impl Interpreter { } pub fn print_memory(&self) { + if !self.debug { + return; + } println!("╔══════════════════════════════════════════════════════════════════╗"); println!("║ MEMORY STATE ║"); println!("╠══════════════════════════════════════════════════════════════════╣"); @@ -47,7 +50,11 @@ impl Interpreter { if i % 4 == 0 { print!("║ "); } - print!("r{:2}: {:>10} ", i, value); + if i < 10 { + print!("r{} : {:<10} ", i, value); + } else { + print!("r{}: {:<10} ", i, value); + } if i % 4 == 3 { println!(" ║"); } @@ -255,7 +262,7 @@ impl Interpreter { println!("StackPointer = {sp}"); } Some(other) => { - panic!("Unknown instruction: {}", other); + println!("Instruction not implemented!: {}", other); } None => { panic!("Empty line encountered"); From 8b71bb850c14be25256c696cd41393e9d5dd7c23 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Feb 2026 23:29:12 +0100 Subject: [PATCH 04/34] perchance str works? --- interpreter/src/interpreter.rs | 115 +++++++++++++++++++++++++- interpreter/src/memory.rs | 13 ++- interpreter/test_files/test_stack.asm | 17 ++++ 3 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 interpreter/test_files/test_stack.asm diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index e7df904..47b4c38 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -111,6 +111,49 @@ impl Interpreter { } } + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!("║ STACK: ║"); + println!( + "║ Stack size: {:>6} bytes ║", + self.memory.get_stack().len() + ); + println!( + "║ SP: {:>10} (0x{:08x}) ║", + self.memory.get_sp(), + self.memory.get_sp() + ); + + let stack_data = self.memory.get_stack(); + let sp = self.memory.get_sp(); + let display_start = sp.saturating_sub(64); + let display_end = std::cmp::min(sp + 64, stack_data.len()); + if display_end > 0 { + println!("║ Stack contents (from sp-64 to sp+64): ║"); + for row in (display_start..display_end).step_by(16) { + let end = std::cmp::min(row + 16, display_end); + print!("║ {:04x}: ", row); + for i in row..end { + print!("{:02x} ", stack_data[i]); + } + for _ in end..row + 16 { + print!(" "); + } + print!(" |"); + for i in row..end { + let byte = stack_data[i]; + if byte >= 32 && byte < 127 { + print!("{}", byte as char); + } else { + print!("."); + } + } + for _ in end..row + 16 { + print!(" "); + } + println!("|║"); + } + } + println!("╚══════════════════════════════════════════════════════════════════╝"); } @@ -236,6 +279,71 @@ impl Interpreter { } } + fn exec_str(&mut self, content: String) { + if self.debug { + println!("Executing str instruction: {}", content); + } + let parts: Vec<&str> = content.split_whitespace().collect(); + let dest_reg = parts[1].replace(",", ""); + let dest_idx: usize = dest_reg[1..] + .parse() + .expect("Failed to parse register index"); + let value = self.memory.get_reg(dest_idx); + + let addr_part = parts[2]; + let addr_part = addr_part.replace("[", "").replace("]", ""); + + let mut base_addr: usize = 0; + let mut offset: i32 = 0; + let mut base_reg_name = String::new(); + + for part in addr_part.split(",") { + let part = part.trim(); + if part.starts_with("r") { + base_reg_name = part.to_string(); + } else if part == "sp" { + base_reg_name = "sp".to_string(); + } else if part.starts_with("#") { + offset = part + .replace("#", "") + .parse() + .expect("Failed to parse offset"); + } + } + + if base_reg_name == "sp" { + base_addr = self.memory.get_sp(); + } else if base_reg_name.starts_with("r") { + let reg_idx: usize = base_reg_name[1..] + .parse() + .expect("Failed to parse register index"); + base_addr = self.memory.get_reg(reg_idx) as usize; + } + + let offset_from_sp = (base_addr as i32 - self.memory.get_sp() as i32 + offset) as usize; + self.memory.write_stack32(offset_from_sp, value); + + if self.debug { + println!("Stored value {} at stack offset {}", value, offset_from_sp); + let stack_data = self.memory.get_stack(); + let sp = self.memory.get_sp(); + println!( + " SP: {:>10}, stack[SP]: {:02x} {:02x} {:02x} {:02x} = {}", + sp, + stack_data[sp], + stack_data[sp + 1], + stack_data[sp + 2], + stack_data[sp + 3], + u32::from_le_bytes([ + stack_data[sp], + stack_data[sp + 1], + stack_data[sp + 2], + stack_data[sp + 3] + ]) + ); + } + } + pub fn execute(&mut self) -> u32 { let start_block = self.get_start_block(); for (i, content) in start_block.into_iter().enumerate() { @@ -255,11 +363,10 @@ impl Interpreter { } } Some("sub") => { - let mut sp = self.memory.get_sp(); - println!("StackPointer = {sp}"); self.exec_sub(content); - sp = self.memory.get_sp(); - println!("StackPointer = {sp}"); + } + Some("str") => { + self.exec_str(content); } Some(other) => { println!("Instruction not implemented!: {}", other); diff --git a/interpreter/src/memory.rs b/interpreter/src/memory.rs index 32358b6..9b5f6d9 100644 --- a/interpreter/src/memory.rs +++ b/interpreter/src/memory.rs @@ -24,7 +24,6 @@ impl EmulatorMemory { } pub fn push32(&mut self, value: u32) { - self.stack_pointer -= 4; let bytes = value.to_le_bytes(); self.stack[self.stack_pointer..self.stack_pointer + 4].copy_from_slice(&bytes); } @@ -36,12 +35,10 @@ impl EmulatorMemory { self.stack[self.stack_pointer + 2], self.stack[self.stack_pointer + 3], ]; - self.stack_pointer += 4; u32::from_le_bytes(bytes) } pub fn push16(&mut self, value: u16) { - self.stack_pointer -= 2; let bytes = value.to_le_bytes(); self.stack[self.stack_pointer..self.stack_pointer + 2].copy_from_slice(&bytes); } @@ -51,7 +48,6 @@ impl EmulatorMemory { self.stack[self.stack_pointer], self.stack[self.stack_pointer + 1], ]; - self.stack_pointer += 2; u16::from_le_bytes(bytes) } @@ -78,6 +74,11 @@ impl EmulatorMemory { self.heap[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); } + pub fn write_stack32(&mut self, offset: usize, value: u32) { + let addr = self.stack_pointer + offset; + self.stack[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); + } + pub fn get_sp(&self) -> usize { self.stack_pointer } @@ -118,6 +119,10 @@ impl EmulatorMemory { &self.heap } + pub fn get_stack(&self) -> &Vec { + &self.stack + } + pub fn print_registers(&self) { for (i, &value) in self.registers.iter().enumerate() { println!("r{}: {}", i, value); diff --git a/interpreter/test_files/test_stack.asm b/interpreter/test_files/test_stack.asm new file mode 100644 index 0000000..5a2bca2 --- /dev/null +++ b/interpreter/test_files/test_stack.asm @@ -0,0 +1,17 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #42 + str r0, [sp] + ldr r1, [sp] + mov r0, r1 + mov r7, #1 + svc #0 + +.size _start, .-_start From 837ad4f344b298268c353b9c89788ae8a1aae2a2 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Sun, 1 Mar 2026 14:39:17 +0100 Subject: [PATCH 05/34] progress --- interpreter/src/interpreter.rs | 298 +++++++++++++++++++++++++++++---- interpreter/src/lib.rs | 48 ++++++ interpreter/src/memory.rs | 17 ++ 3 files changed, 331 insertions(+), 32 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 47b4c38..d2542ce 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1,4 +1,4 @@ -use std::{fs::File, io::BufRead}; +use std::{collections::HashMap, fs::File, io::BufRead}; use crate::memory::EmulatorMemory; @@ -13,7 +13,7 @@ impl Interpreter { Self { memory: EmulatorMemory::new(), file: Vec::new(), - debug: cfg!(debug_assertions), + debug: false, } } @@ -165,29 +165,30 @@ impl Interpreter { println!("-------------------- SHOUT FILE END --------------------"); } - fn get_start(&self) -> Result { - for (idx, content) in self.file.iter().enumerate() { - if content.contains("_start:") { - return Ok(idx); + fn get_asm_branches(&self) -> HashMap> { + let mut branches: HashMap> = HashMap::new(); + let mut current_branch: Option = None; + let mut current_instructions: Vec = Vec::new(); + + for line in &self.file { + let trimmed = line.trim(); + + if trimmed.ends_with(":") && !trimmed.starts_with(" ") { + if let Some(branch_name) = current_branch { + branches.insert(branch_name, current_instructions.clone()); + current_instructions.clear(); + } + current_branch = Some(trimmed.trim_end_matches(':').to_string()); + } else if current_branch.is_some() && line.starts_with(" ") { + current_instructions.push(trimmed.to_string()); } } - Err("_start label not found".to_string()) - } - fn get_start_block(&self) -> Vec { - let start = match self.get_start() { - Ok(start) => start, - _ => panic!("ERROR IN GETTING START BLOCK"), - }; - let mut res: Vec = Vec::new(); - res.push(self.file.get(start).unwrap().clone()); - for i in start..self.file.len() { - let content = self.file.get(i).unwrap(); - if content.starts_with(" ") { - res.push(content.clone()); - } + if let Some(branch_name) = current_branch { + branches.insert(branch_name, current_instructions); } - res + + branches } fn exec_mov(&mut self, content: String) { @@ -344,29 +345,100 @@ impl Interpreter { } } + fn exec_ldr(&mut self, content: String) { + if self.debug { + println!("Executing ldr instruction: {}", content); + } + + // 1. Parse the parts (e.g., "ldr", "r0,", "[sp, #0]") + let parts: Vec<&str> = content.split_whitespace().collect(); + + // 2. Identify the destination register (e.g., "r0") + let dest_reg = parts[1].replace(",", ""); + let dest_idx: usize = dest_reg[1..] + .parse() + .expect("Failed to parse destination register index"); + + // 3. Clean up the address part (e.g., "[sp, #0]" -> "sp, #0") + let addr_part = parts[2].replace("[", "").replace("]", ""); + + let mut base_addr: usize = 0; + let mut offset: i32 = 0; + let mut base_reg_name = String::new(); + + // 4. Parse the base register and the offset + for part in addr_part.split(",") { + let part = part.trim(); + if part.starts_with("r") || part == "sp" { + base_reg_name = part.to_string(); + } else if part.starts_with("#") { + offset = part + .replace("#", "") + .parse() + .expect("Failed to parse offset"); + } + } + + // 5. Calculate the actual base address from the register + if base_reg_name == "sp" { + base_addr = self.memory.get_sp(); + } else if base_reg_name.starts_with("r") { + let reg_idx: usize = base_reg_name[1..] + .parse() + .expect("Failed to parse base register index"); + base_addr = self.memory.get_reg(reg_idx) as usize; + } + + // 6. Calculate the effective offset relative to the stack start + // Note: This logic assumes your memory model treats stack offsets relative to SP + let effective_offset = (base_addr as i32 - self.memory.get_sp() as i32 + offset) as usize; + + // 7. Load the value from memory and update the register + let value = self.memory.read_stack32(effective_offset); + self.memory.set_reg(dest_idx, value); + + if self.debug { + println!( + "Loaded value {} from stack offset {} into r{}", + value, effective_offset, dest_idx + ); + } + } + + fn exec_cmp(&self, content: String) { + //NOTE: We need to implement Z, N, C, V Flags for this + } + pub fn execute(&mut self) -> u32 { - let start_block = self.get_start_block(); - for (i, content) in start_block.into_iter().enumerate() { - if i == 0 { - if self.debug { - println!("RUNNING {content}"); - } - continue; + let branches = self.get_asm_branches(); + + if !branches.contains_key("_start") { + panic!("_start label not found"); + } + + let start_block = branches.get("_start").unwrap(); + + for content in start_block.iter() { + if self.debug { + println!("RUNNING {content}"); } match content.split_whitespace().next() { Some("mov") => { - self.exec_mov(content); + self.exec_mov(content.clone()); } Some("svc") => { - if let Some(exit_code) = self.exec_svc(content) { + if let Some(exit_code) = self.exec_svc(content.clone()) { return exit_code; } } Some("sub") => { - self.exec_sub(content); + self.exec_sub(content.clone()); } Some("str") => { - self.exec_str(content); + self.exec_str(content.clone()); + } + Some("ldr") => { + self.exec_ldr(content.clone()); } Some(other) => { println!("Instruction not implemented!: {}", other); @@ -385,3 +457,165 @@ impl Default for Interpreter { Self::new() } } + +#[cfg(test)] +mod tests { + use super::*; + + fn create_interpreter() -> Interpreter { + Interpreter::new() + } + + #[test] + fn test_mov_immediate() { + let mut interp = create_interpreter(); + interp.exec_mov("mov r0, #42".to_string()); + assert_eq!(interp.memory.get_reg(0), 42); + } + + #[test] + fn test_mov_register_to_register() { + let mut interp = create_interpreter(); + interp.memory.set_reg(1, 99); + interp.exec_mov("mov r0, r1".to_string()); + assert_eq!(interp.memory.get_reg(0), 99); + } + + #[test] + fn test_mov_zero() { + let mut interp = create_interpreter(); + interp.memory.set_reg(0, 42); + interp.exec_mov("mov r0, #0".to_string()); + assert_eq!(interp.memory.get_reg(0), 0); + } + + #[test] + fn test_sub_sp() { + let mut interp = create_interpreter(); + let initial_sp = interp.memory.get_sp(); + interp.exec_sub("sub sp, sp, #4".to_string()); + assert_eq!(interp.memory.get_sp(), initial_sp - 4); + } + + #[test] + fn test_sub_with_register() { + let mut interp = create_interpreter(); + interp.memory.set_reg(1, 8); + let initial_sp = interp.memory.get_sp(); + interp.exec_sub("sub sp, sp, r1".to_string()); + assert_eq!(interp.memory.get_sp(), initial_sp - 8); + } + + #[test] + fn test_str_store_to_stack() { + let mut interp = create_interpreter(); + interp.memory.set_reg(0, 42); + let initial_sp = interp.memory.get_sp(); + interp.memory.set_sp(initial_sp - 4); + + interp.exec_str("str r0, [sp]".to_string()); + + let value = interp.memory.read_stack32(0); + assert_eq!(value, 42); + } + + #[test] + fn test_ldr_load_from_stack() { + let mut interp = create_interpreter(); + let initial_sp = interp.memory.get_sp(); + interp.memory.set_sp(initial_sp - 4); + interp.memory.write_stack32(0, 123); + + interp.exec_ldr("ldr r0, [sp]".to_string()); + + assert_eq!(interp.memory.get_reg(0), 123); + } + + #[test] + fn test_svc_exit_with_code() { + let mut interp = create_interpreter(); + interp.memory.set_reg(7, 1); + interp.memory.set_reg(0, 42); + + let result = interp.exec_svc("svc #0".to_string()); + + assert_eq!(result, Some(42)); + } + + #[test] + fn test_svc_ignores_other_syscalls() { + let mut interp = create_interpreter(); + interp.memory.set_reg(7, 2); + + let result = interp.exec_svc("svc #0".to_string()); + + assert_eq!(result, None); + } + + #[test] + fn test_get_asm_branches_single_function() { + let mut interp = create_interpreter(); + interp.file = vec![ + "_start:".to_string(), + " mov r0, #1".to_string(), + " svc #0".to_string(), + ]; + + let branches = interp.get_asm_branches(); + + assert!(branches.contains_key("_start")); + assert_eq!(branches["_start"].len(), 2); + } + + #[test] + fn test_get_asm_branches_multiple_functions() { + let mut interp = create_interpreter(); + interp.file = vec![ + "_start:".to_string(), + " mov r0, #1".to_string(), + " b else_block".to_string(), + "else_block:".to_string(), + " mov r0, #2".to_string(), + " svc #0".to_string(), + ]; + + let branches = interp.get_asm_branches(); + + assert!(branches.contains_key("_start")); + assert!(branches.contains_key("else_block")); + } + + #[test] + fn test_execute_simple_program() { + let mut interp = create_interpreter(); + interp.file = vec![ + "_start:".to_string(), + " mov r0, #10".to_string(), + " mov r7, #1".to_string(), + " svc #0".to_string(), + ]; + + let exit_code = interp.execute(); + + assert_eq!(exit_code, 10); + } + + #[test] + fn test_execute_with_stack_operations() { + let mut interp = create_interpreter(); + interp.file = vec![ + "_start:".to_string(), + " sub sp, sp, #4".to_string(), + " mov r0, #42".to_string(), + " str r0, [sp]".to_string(), + " ldr r1, [sp]".to_string(), + " mov r0, r1".to_string(), + " mov r7, #1".to_string(), + " svc #0".to_string(), + ]; + + let exit_code = interp.execute(); + + assert_eq!(exit_code, 42); + } +} diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index becf5da..ebb1327 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -1,2 +1,50 @@ pub mod interpreter; pub mod memory; + +#[cfg(test)] +mod tests { + use super::interpreter::Interpreter; + use std::path::PathBuf; + + fn get_test_file_path(filename: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("test_files") + .join(filename) + } + + #[test] + fn test_interpret_test_let() { + let mut interp = Interpreter::new(); + interp.read_file( + &mut get_test_file_path("test_let.asm") + .to_string_lossy() + .to_string(), + ); + let exit_code = interp.execute(); + assert_eq!(exit_code, 27, "test_let.asm should exit with 27"); + } + + #[test] + fn test_interpret_test_stack() { + let mut interp = Interpreter::new(); + interp.read_file( + &mut get_test_file_path("test_stack.asm") + .to_string_lossy() + .to_string(), + ); + let exit_code = interp.execute(); + assert_eq!(exit_code, 42, "test_stack.asm should exit with 42"); + } + + #[test] + fn test_interpret_test_branching() { + let mut interp = Interpreter::new(); + interp.read_file( + &mut get_test_file_path("test_branching.asm") + .to_string_lossy() + .to_string(), + ); + let exit_code = interp.execute(); + assert_eq!(exit_code, 12, "test_branching.asm should exit with 12"); + } +} diff --git a/interpreter/src/memory.rs b/interpreter/src/memory.rs index 9b5f6d9..c73d895 100644 --- a/interpreter/src/memory.rs +++ b/interpreter/src/memory.rs @@ -79,6 +79,23 @@ impl EmulatorMemory { self.stack[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); } + pub fn read_stack32(&self, offset: usize) -> u32 { + let addr = self.stack_pointer + offset; + + // Ensure we don't read past the end of the stack array + if addr + 4 > self.stack.len() { + panic!("Stack out of bounds read at offset {}", offset); + } + + // Grab 4 bytes and convert them from Little Endian to u32 + u32::from_le_bytes([ + self.stack[addr], + self.stack[addr + 1], + self.stack[addr + 2], + self.stack[addr + 3], + ]) + } + pub fn get_sp(&self) -> usize { self.stack_pointer } From 00357485c56ca628aa17b2dbdc9ef2de85049124 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Tue, 3 Mar 2026 16:05:14 +0100 Subject: [PATCH 06/34] udpates --- interpreter/src/interpreter.rs | 391 ++++++++++++++++--- interpreter/src/lib.rs | 31 ++ interpreter/src/memory.rs | 33 -- interpreter/test_files/test_ite_false.asm | 18 + interpreter/test_files/test_ite_true.asm | 18 + interpreter/test_files/test_ittete_false.asm | 21 + interpreter/test_files/test_ittete_true.asm | 21 + 7 files changed, 448 insertions(+), 85 deletions(-) create mode 100644 interpreter/test_files/test_ite_false.asm create mode 100644 interpreter/test_files/test_ite_true.asm create mode 100644 interpreter/test_files/test_ittete_false.asm create mode 100644 interpreter/test_files/test_ittete_true.asm diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index d2542ce..0d25781 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1,9 +1,75 @@ -use std::{collections::HashMap, fs::File, io::BufRead}; +use std::collections::HashMap; +use std::fs::File; +use std::io::BufRead; use crate::memory::EmulatorMemory; +const NUM_REGISTERS: usize = 32; + +#[derive(Clone, Debug, PartialEq, Default)] +pub struct ItState { + pub is_active: bool, + pub base_cond: String, + pub mask: Vec, + pub current_instr: usize, +} + +#[derive(Clone, Debug, PartialEq, Default)] +pub struct Cpsr { + pub n: bool, + pub z: bool, + pub c: bool, + pub v: bool, + pub it_state: ItState, +} +impl Cpsr { +pub fn evaluate_condition(&self, cond: &str) -> bool { + match cond.to_uppercase().as_str() { + "EQ" => self.z, + "NE" => !self.z, + "HS" | "CS" => self.c, + "LO" | "CC" => !self.c, + "MI" => self.n, + "PL" => !self.n, + "VS" => self.v, + "VC" => !self.v, + "HI" => self.c && !self.z, + "LS" => !self.c || self.z, + "GE" => self.n == self.v, + "LT" => self.n != self.v, + "GT" => !self.z && (self.n == self.v), + "LE" => self.z || (self.n != self.v), + "AL" => true, + _ => true, // Default to true if unknown + } +} + pub fn should_execute(&mut self) -> bool { + if !self.it_state.is_active { + return true; + } + + let step_idx = self.it_state.current_instr; + let is_then = self.it_state.mask[step_idx] == 't'; + let condition_met = self.evaluate_condition(&self.it_state.base_cond); + + let execute = if is_then { condition_met } else { !condition_met }; + + // Advance or Reset + self.it_state.current_instr += 1; + if self.it_state.current_instr >= self.it_state.mask.len() { + self.it_state.is_active = false; + self.it_state.mask.clear(); + } + + execute + } +} + pub struct Interpreter { memory: EmulatorMemory, + registers: [u32; NUM_REGISTERS], + pc: u32, + cpsr: Cpsr, file: Vec, debug: bool, } @@ -12,6 +78,9 @@ impl Interpreter { pub fn new() -> Self { Self { memory: EmulatorMemory::new(), + registers: [0; NUM_REGISTERS], + pc: 0, + cpsr: Cpsr::default(), file: Vec::new(), debug: false, } @@ -20,6 +89,22 @@ impl Interpreter { pub fn set_debug(&mut self, debug: bool) { self.debug = debug; } + + pub fn get_reg(&self, index: usize) -> u32 { + self.registers[index] + } + + pub fn set_reg(&mut self, index: usize, value: u32) { + self.registers[index] = value; + } + + pub fn get_pc(&self) -> u32 { + self.pc + } + + pub fn set_pc(&mut self, pc: u32) { + self.pc = pc; + } pub fn read_file(&mut self, file_path: &String) -> bool { let file = File::open(file_path).expect("Could not open file: {file_path}"); let lines: Vec = std::io::BufReader::new(file) @@ -32,10 +117,16 @@ impl Interpreter { pub fn print_registers(&self) { if self.debug { - self.memory.print_registers(); + for (i, &value) in self.registers.iter().enumerate() { + println!("r{}: {}", i, value); + } } } + pub fn get_registers(&self) -> &[u32; NUM_REGISTERS] { + &self.registers + } + pub fn print_memory(&self) { if !self.debug { return; @@ -46,7 +137,7 @@ impl Interpreter { println!("║ REGISTERS: ║"); println!("╟──────────────────────────────────────────────────────────────────╢"); - for (i, &value) in self.memory.get_registers().iter().enumerate() { + for (i, &value) in self.registers.iter().enumerate() { if i % 4 == 0 { print!("║ "); } @@ -63,6 +154,33 @@ impl Interpreter { println!("║"); } + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!("║ CPSR FLAGS: ║"); + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!( + "║ Z (Zero): {:<5} ║", + self.cpsr.z + ); + println!( + "║ N (Negative): {:<5} ║", + self.cpsr.n + ); + println!( + "║ C (Carry): {:<5} ║", + self.cpsr.c + ); + println!( + "║ V (Overflow): {:<5} ║", + self.cpsr.v + ); + + println!("╟──────────────────────────────────────────────────────────────────╢"); + println!("║ PROGRAM COUNTER: ║"); + println!( + "║ PC: {:>10} (0x{:08x}) ║", + self.pc, self.pc + ); + println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ STACK POINTER: ║"); println!( @@ -98,7 +216,7 @@ impl Interpreter { print!(" |"); for i in row..end { let byte = heap_data[i]; - if byte >= 32 && byte < 127 { + if (32..127).contains(&byte) { print!("{}", byte as char); } else { print!("."); @@ -141,7 +259,7 @@ impl Interpreter { print!(" |"); for i in row..end { let byte = stack_data[i]; - if byte >= 32 && byte < 127 { + if (32..127).contains(&byte) { print!("{}", byte as char); } else { print!("."); @@ -204,14 +322,14 @@ impl Interpreter { if let Some(value_str) = src.strip_prefix('#') { value = value_str.parse().expect("Failed to parse immediate value"); - self.memory.set_reg(dest_idx, value); + self.set_reg(dest_idx, value); if self.debug { println!("Mock: mov r{}, #{} (stored in register)", dest_idx, value); } } else { let src_idx: usize = src[1..].parse().expect("Failed to parse register index"); - value = self.memory.get_reg(src_idx); - self.memory.set_reg(dest_idx, value); + value = self.get_reg(src_idx); + self.set_reg(dest_idx, value); if self.debug { println!( "Mock: mov r{}, r{} (register to register)", @@ -230,9 +348,9 @@ impl Interpreter { if let Some(svc_num) = parts.get(1) { let svc_num = svc_num.replace("#", ""); if svc_num == "0" { - let syscall_num = self.memory.get_reg(7); + let syscall_num = self.get_reg(7); if syscall_num == 1 { - let exit_code = self.memory.get_reg(0); + let exit_code = self.get_reg(0); if self.debug { println!("Exit syscall (r7=1), returning exit code: {}", exit_code); } @@ -255,7 +373,7 @@ impl Interpreter { } else { let value_str = val_or_reg.replace("r", ""); let this_reg: usize = value_str.parse().expect("Failed to parse register index"); - sub_value = self.memory.get_reg(this_reg); + sub_value = self.get_reg(this_reg); } let src_val: u32; @@ -264,7 +382,7 @@ impl Interpreter { .replace("r", "") .parse() .expect("Unable to parse register"); - src_val = self.memory.get_reg(src_register); + src_val = self.get_reg(src_register); } else { src_val = self.memory.get_sp() as u32; } @@ -274,7 +392,7 @@ impl Interpreter { .replace("r", "") .parse() .expect("Unable to parse register"); - let dst_val = self.memory.get_reg(dst_register); + let dst_val = self.get_reg(dst_register); } else if src == "sp" { self.memory.set_sp((src_val - sub_value) as usize); } @@ -289,7 +407,7 @@ impl Interpreter { let dest_idx: usize = dest_reg[1..] .parse() .expect("Failed to parse register index"); - let value = self.memory.get_reg(dest_idx); + let value = self.get_reg(dest_idx); let addr_part = parts[2]; let addr_part = addr_part.replace("[", "").replace("]", ""); @@ -318,7 +436,7 @@ impl Interpreter { let reg_idx: usize = base_reg_name[1..] .parse() .expect("Failed to parse register index"); - base_addr = self.memory.get_reg(reg_idx) as usize; + base_addr = self.get_reg(reg_idx) as usize; } let offset_from_sp = (base_addr as i32 - self.memory.get_sp() as i32 + offset) as usize; @@ -386,7 +504,7 @@ impl Interpreter { let reg_idx: usize = base_reg_name[1..] .parse() .expect("Failed to parse base register index"); - base_addr = self.memory.get_reg(reg_idx) as usize; + base_addr = self.get_reg(reg_idx) as usize; } // 6. Calculate the effective offset relative to the stack start @@ -395,7 +513,7 @@ impl Interpreter { // 7. Load the value from memory and update the register let value = self.memory.read_stack32(effective_offset); - self.memory.set_reg(dest_idx, value); + self.set_reg(dest_idx, value); if self.debug { println!( @@ -405,8 +523,74 @@ impl Interpreter { } } - fn exec_cmp(&self, content: String) { - //NOTE: We need to implement Z, N, C, V Flags for this + fn exec_cmp(&mut self, content: String) { + if self.debug { + println!("Executing cmp instruction: {}", content); + } + + let parts: Vec<&str> = content + .split(|c: char| c == ',' || c.is_whitespace()) + .filter(|s| !s.is_empty()) + .collect(); + + if parts.len() < 3 { + return; + } + + let rn_idx: usize = parts[1][1..].parse().expect("Failed to parse Rn index"); + let val_n = self.get_reg(rn_idx); + + let val_op2 = if let Some(imm_str) = parts[2].strip_prefix('#') { + imm_str.parse::().expect("Failed to parse immediate") + } else { + let rm_idx: usize = parts[2][1..].parse().expect("Failed to parse Rm index"); + self.get_reg(rm_idx) + }; + let res_u64 = (val_n as u64).wrapping_sub(val_op2 as u64); + let result = res_u64 as u32; + + self.cpsr.z = result == 0; + self.cpsr.n = (result >> 31) == 1; + self.cpsr.c = val_n >= val_op2; + + let rn_i = val_n as i32; + let op2_i = val_op2 as i32; + let (_, overflow) = rn_i.overflowing_sub(op2_i); + self.cpsr.v = overflow; + + if self.debug { + println!( + "CMP Result: {:#x} - {:#x} = {:#x} | Flags: N:{} Z:{} C:{} V:{}", + val_n, val_op2, result, self.cpsr.n, self.cpsr.z, self.cpsr.c, self.cpsr.v + ); + } + } + + fn exec_itx(&mut self, content: String) { + let parts: Vec<&str> = content.split_whitespace().collect(); + let mnemonic = parts[0].to_lowercase(); // e.g., "itete" + let cond = parts[1].to_uppercase(); // e.g., "GT" + + self.cpsr.it_state.is_active = true; + self.cpsr.it_state.base_cond = cond; + self.cpsr.it_state.current_instr = 0; + + // Convert "itete" into ['T', 'E', 'T', 'E'] + self.cpsr.it_state.mask = mnemonic.chars().skip(1).collect(); + } + + //NOTE: Maybe we could just use one single exec_b, and have it check if the instruction is beq + //or ble etc. and use the cpsr register to do stuff instead of a million branch function for + //each conditional version + fn exec_b(&self, content: String) { + //TODO: implement the branch function + println!("Instruction B Is Not Implemented yet."); + } + + + fn exec_beq(&self, content: String) { + //TODO: implement the function + println!("Instruction BEQ Is Not Implemented yet."); } pub fn execute(&mut self) -> u32 { @@ -419,33 +603,30 @@ impl Interpreter { let start_block = branches.get("_start").unwrap(); for content in start_block.iter() { - if self.debug { - println!("RUNNING {content}"); - } - match content.split_whitespace().next() { - Some("mov") => { - self.exec_mov(content.clone()); + let instruction = content.split_whitespace().next().unwrap_or(""); + + if !self.cpsr.should_execute() { + if self.debug { + println!(" -> Condition not met, skipping."); } - Some("svc") => { + continue; // Skip the match logic entirely + } + + match instruction { + f if f.starts_with("mov") => self.exec_mov(content.clone()), + f if f.starts_with("svc") => { if let Some(exit_code) = self.exec_svc(content.clone()) { return exit_code; } } - Some("sub") => { - self.exec_sub(content.clone()); - } - Some("str") => { - self.exec_str(content.clone()); - } - Some("ldr") => { - self.exec_ldr(content.clone()); - } - Some(other) => { - println!("Instruction not implemented!: {}", other); - } - None => { - panic!("Empty line encountered"); - } + f if f.starts_with("sub") => self.exec_sub(content.clone()), + f if f.starts_with("str") => self.exec_str(content.clone()), + f if f.starts_with("ldr") => self.exec_ldr(content.clone()), + f if f.starts_with("cmp") => self.exec_cmp(content.clone()), + f if f.starts_with("it") => self.exec_itx(content.clone()), + f if instruction == "b" => self.exec_b(content.clone()), + f if instruction == "beq" => self.exec_beq(content.clone()), + _ => panic!("Invalid instruction") } } 0 @@ -470,23 +651,23 @@ mod tests { fn test_mov_immediate() { let mut interp = create_interpreter(); interp.exec_mov("mov r0, #42".to_string()); - assert_eq!(interp.memory.get_reg(0), 42); + assert_eq!(interp.get_reg(0), 42); } #[test] fn test_mov_register_to_register() { let mut interp = create_interpreter(); - interp.memory.set_reg(1, 99); + interp.set_reg(1, 99); interp.exec_mov("mov r0, r1".to_string()); - assert_eq!(interp.memory.get_reg(0), 99); + assert_eq!(interp.get_reg(0), 99); } #[test] fn test_mov_zero() { let mut interp = create_interpreter(); - interp.memory.set_reg(0, 42); + interp.set_reg(0, 42); interp.exec_mov("mov r0, #0".to_string()); - assert_eq!(interp.memory.get_reg(0), 0); + assert_eq!(interp.get_reg(0), 0); } #[test] @@ -500,7 +681,7 @@ mod tests { #[test] fn test_sub_with_register() { let mut interp = create_interpreter(); - interp.memory.set_reg(1, 8); + interp.set_reg(1, 8); let initial_sp = interp.memory.get_sp(); interp.exec_sub("sub sp, sp, r1".to_string()); assert_eq!(interp.memory.get_sp(), initial_sp - 8); @@ -509,7 +690,7 @@ mod tests { #[test] fn test_str_store_to_stack() { let mut interp = create_interpreter(); - interp.memory.set_reg(0, 42); + interp.set_reg(0, 42); let initial_sp = interp.memory.get_sp(); interp.memory.set_sp(initial_sp - 4); @@ -528,14 +709,14 @@ mod tests { interp.exec_ldr("ldr r0, [sp]".to_string()); - assert_eq!(interp.memory.get_reg(0), 123); + assert_eq!(interp.get_reg(0), 123); } #[test] fn test_svc_exit_with_code() { let mut interp = create_interpreter(); - interp.memory.set_reg(7, 1); - interp.memory.set_reg(0, 42); + interp.set_reg(7, 1); + interp.set_reg(0, 42); let result = interp.exec_svc("svc #0".to_string()); @@ -545,7 +726,7 @@ mod tests { #[test] fn test_svc_ignores_other_syscalls() { let mut interp = create_interpreter(); - interp.memory.set_reg(7, 2); + interp.set_reg(7, 2); let result = interp.exec_svc("svc #0".to_string()); @@ -618,4 +799,110 @@ mod tests { assert_eq!(exit_code, 42); } + + #[test] + fn test_cmp_logic() { + let mut interp = create_interpreter(); + + // 1. Test Equality (Z flag) + interp.set_reg(1, 100); + interp.exec_cmp("cmp r1, #100".to_string()); + assert!(interp.cpsr.z, "Z should be true when values are equal"); + assert!(!interp.cpsr.n, "N should be false when values are equal"); + assert!(interp.cpsr.c, "C should be true (no borrow) when equal"); + + // 2. Test Less Than (N flag) + interp.set_reg(1, 50); + interp.exec_cmp("cmp r1, #100".to_string()); + assert!(!interp.cpsr.z, "Z should be false when not equal"); + assert!( + interp.cpsr.n, + "N should be true because 50 - 100 is negative" + ); + assert!( + !interp.cpsr.c, + "C should be false because 50 < 100 (borrow occurred)" + ); + + // 3. Test Greater Than (Positive result) + interp.set_reg(1, 200); + interp.exec_cmp("cmp r1, #100".to_string()); + assert!(!interp.cpsr.z); + assert!(!interp.cpsr.n); + assert!(interp.cpsr.c, "C should be true because 200 >= 100"); + + // 4. Test Signed Overflow (V flag) + // Large positive minus a large negative results in a value + // too big for 32-bit signed integer (wraps around) + interp.set_reg(1, 0x7FFFFFFF); // Max Positive i32 + interp.set_reg(2, 0xFFFFFFFF); // -1 in two's complement + // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) + interp.exec_cmp("cmp r1, r2".to_string()); + assert!(interp.cpsr.v, "V should be true due to signed overflow"); + assert!( + interp.cpsr.n, + "N should be true because result wrapped to 0x80000000" + ); + } + #[test] + fn test_it_block_execution_logic() { + let mut interp = create_interpreter(); + + // 1. Setup the IT block: ITE GT (3 instructions total) + // First 'T' = GT, second 'E' = LE (Not GT), third 'E' = LE + interp.exec_itx("iteee gt".to_string()); + + assert!(interp.cpsr.it_state.is_active); + assert_eq!(interp.cpsr.it_state.base_cond, "GT"); + assert_eq!(interp.cpsr.it_state.mask, vec!['t', 'e', 'e', 'e']); + + // 2. Scenario A: Condition is TRUE (R1 > R0) + interp.set_reg(1, 100); + interp.set_reg(0, 50); + interp.exec_cmp("cmp r1, r0".to_string()); // Sets flags for GT + + // We expect: Step 0 (T) -> Execute, Step 1 (E) -> Skip + assert!(interp.cpsr.evaluate_condition("GT"), "GT should be true"); + + // Test Instruction 1 (T) + let should_run_1 = interp.cpsr.should_execute(); + assert!(should_run_1, "Instruction 1 (T) should run when GT is true"); + assert_eq!(interp.cpsr.it_state.current_instr, 1); + + // Test Instruction 2 (E) + let should_run_2 = interp.cpsr.should_execute(); + assert!( + !should_run_2, + "Instruction 2 (E) should NOT run when GT is true" + ); + assert_eq!(interp.cpsr.it_state.current_instr, 2); + + // 3. Reset and Scenario B: Condition is FALSE (R1 < R0) + interp.exec_itx("ite gt".to_string()); // 2 instructions + interp.set_reg(1, 10); + interp.set_reg(0, 50); + interp.exec_cmp("cmp r1, r0".to_string()); // Sets flags for LT (Not GT) + + assert!(!interp.cpsr.evaluate_condition("GT"), "GT should be false"); + + // Test Instruction 1 (T) + let should_run_1_f = interp.cpsr.should_execute(); + assert!( + !should_run_1_f, + "Instruction 1 (T) should NOT run when GT is false" + ); + + // Test Instruction 2 (E) + let should_run_2_f = interp.cpsr.should_execute(); + assert!( + should_run_2_f, + "Instruction 2 (E) SHOULD run when GT is false (Else case)" + ); + + // Verify block auto-deactivates + assert!( + !interp.cpsr.it_state.is_active, + "IT block should be inactive after last instruction" + ); + } } diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index ebb1327..daaef51 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -47,4 +47,35 @@ mod tests { let exit_code = interp.execute(); assert_eq!(exit_code, 12, "test_branching.asm should exit with 12"); } + #[test] + fn test_ite_condition_true() { + let mut interp = Interpreter::new(); + interp.read_file(&get_test_file_path("test_ite_true.asm").to_string_lossy().to_string()); + let exit_code = interp.execute(); + assert_eq!(exit_code, 1, "ITE True: T should have run, result 1"); + } + + #[test] + fn test_ite_condition_false() { + let mut interp = Interpreter::new(); + interp.read_file(&get_test_file_path("test_ite_false.asm").to_string_lossy().to_string()); + let exit_code = interp.execute(); + assert_eq!(exit_code, 2, "ITE False: E should have run, result 2"); + } + + #[test] + fn test_ittete_condition_true() { + let mut interp = Interpreter::new(); + interp.read_file(&get_test_file_path("test_ittete_true.asm").to_string_lossy().to_string()); + let exit_code = interp.execute(); + assert_eq!(exit_code, 1011, "ITTETE True: Only T instructions should sum"); + } + + #[test] + fn test_ittete_condition_false() { + let mut interp = Interpreter::new(); + interp.read_file(&get_test_file_path("test_ittete_false.asm").to_string_lossy().to_string()); + let exit_code = interp.execute(); + assert_eq!(exit_code, 10100, "ITTETE False: Only E instructions should sum"); + } } diff --git a/interpreter/src/memory.rs b/interpreter/src/memory.rs index c73d895..5750bea 100644 --- a/interpreter/src/memory.rs +++ b/interpreter/src/memory.rs @@ -1,10 +1,7 @@ const STACK_SIZE: usize = 1024 * 1024; const HEAP_SIZE: usize = 1024 * 1024; -const NUM_REGISTERS: usize = 32; pub struct EmulatorMemory { - registers: [u32; NUM_REGISTERS], - pc: u32, stack: Vec, heap: Vec, heap_alloc_index: usize, @@ -14,8 +11,6 @@ pub struct EmulatorMemory { impl EmulatorMemory { pub fn new() -> Self { Self { - registers: [0; NUM_REGISTERS], - pc: 0, stack: vec![0; STACK_SIZE], heap: vec![0; HEAP_SIZE], heap_alloc_index: 0, @@ -82,12 +77,10 @@ impl EmulatorMemory { pub fn read_stack32(&self, offset: usize) -> u32 { let addr = self.stack_pointer + offset; - // Ensure we don't read past the end of the stack array if addr + 4 > self.stack.len() { panic!("Stack out of bounds read at offset {}", offset); } - // Grab 4 bytes and convert them from Little Endian to u32 u32::from_le_bytes([ self.stack[addr], self.stack[addr + 1], @@ -104,26 +97,6 @@ impl EmulatorMemory { self.stack_pointer = sp; } - pub fn get_pc(&self) -> u32 { - self.pc - } - - pub fn set_pc(&mut self, pc: u32) { - self.pc = pc; - } - - pub fn get_reg(&self, index: usize) -> u32 { - self.registers[index] - } - - pub fn set_reg(&mut self, index: usize, value: u32) { - self.registers[index] = value; - } - - pub fn get_registers(&self) -> &[u32; NUM_REGISTERS] { - &self.registers - } - pub fn get_heap_alloc_index(&self) -> usize { self.heap_alloc_index } @@ -139,12 +112,6 @@ impl EmulatorMemory { pub fn get_stack(&self) -> &Vec { &self.stack } - - pub fn print_registers(&self) { - for (i, &value) in self.registers.iter().enumerate() { - println!("r{}: {}", i, value); - } - } } impl Default for EmulatorMemory { diff --git a/interpreter/test_files/test_ite_false.asm b/interpreter/test_files/test_ite_false.asm new file mode 100644 index 0000000..24b253b --- /dev/null +++ b/interpreter/test_files/test_ite_false.asm @@ -0,0 +1,18 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r1, #5 + cmp r1, #10 @ 5 < 10, so GT is False + mov r0, #0 + ite gt + movgt r0, #1 @ Should Skip + movle r0, #2 @ Should Run + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_files/test_ite_true.asm b/interpreter/test_files/test_ite_true.asm new file mode 100644 index 0000000..e243405 --- /dev/null +++ b/interpreter/test_files/test_ite_true.asm @@ -0,0 +1,18 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r1, #10 + cmp r1, #5 @ 10 > 5, so GT is True + mov r0, #0 + ite gt + movgt r0, #1 @ Should Run + movle r0, #2 @ Should Skip + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_files/test_ittete_false.asm b/interpreter/test_files/test_ittete_false.asm new file mode 100644 index 0000000..75f3fa9 --- /dev/null +++ b/interpreter/test_files/test_ittete_false.asm @@ -0,0 +1,21 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r1, #5 + cmp r1, #10 @ GT is False + mov r0, #0 + ittete gt + addgt r0, r0, #1 @ T: Skip + addgt r0, r0, #10 @ T: Skip + addle r0, r0, #100 @ E: Run (+100) + addgt r0, r0, #1000 @ T: Skip + addle r0, r0, #10000 @ E: Run (+10000) + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_files/test_ittete_true.asm b/interpreter/test_files/test_ittete_true.asm new file mode 100644 index 0000000..e3ba38e --- /dev/null +++ b/interpreter/test_files/test_ittete_true.asm @@ -0,0 +1,21 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r1, #10 + cmp r1, #5 @ GT is True + mov r0, #0 + ittete gt + addgt r0, r0, #1 @ T: Run (+1) + addgt r0, r0, #10 @ T: Run (+10) + addle r0, r0, #100 @ E: Skip + addgt r0, r0, #1000 @ T: Run (+1000) + addle r0, r0, #10000 @ E: Skip + mov r7, #1 + svc #0 + +.size _start, .-_start From 1b083ceb8c2876fa993bbe7bf1f215fa5b1f761e Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 5 Mar 2026 10:28:24 +0100 Subject: [PATCH 07/34] exec b og exec add --- interpreter/src/interpreter.rs | 215 +++++++++++++++++---------------- 1 file changed, 109 insertions(+), 106 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 0d25781..b0f2a22 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -23,26 +23,26 @@ pub struct Cpsr { pub it_state: ItState, } impl Cpsr { -pub fn evaluate_condition(&self, cond: &str) -> bool { - match cond.to_uppercase().as_str() { - "EQ" => self.z, - "NE" => !self.z, - "HS" | "CS" => self.c, - "LO" | "CC" => !self.c, - "MI" => self.n, - "PL" => !self.n, - "VS" => self.v, - "VC" => !self.v, - "HI" => self.c && !self.z, - "LS" => !self.c || self.z, - "GE" => self.n == self.v, - "LT" => self.n != self.v, - "GT" => !self.z && (self.n == self.v), - "LE" => self.z || (self.n != self.v), - "AL" => true, - _ => true, // Default to true if unknown + pub fn evaluate_condition(&self, cond: &str) -> bool { + match cond.to_uppercase().as_str() { + "EQ" => self.z, + "NE" => !self.z, + "HS" | "CS" => self.c, + "LO" | "CC" => !self.c, + "MI" => self.n, + "PL" => !self.n, + "VS" => self.v, + "VC" => !self.v, + "HI" => self.c && !self.z, + "LS" => !self.c || self.z, + "GE" => self.n == self.v, + "LT" => self.n != self.v, + "GT" => !self.z && self.n == self.v, + "LE" => self.z || self.n != self.v, + "AL" => true, + _ => true, // Default to true if unknown + } } -} pub fn should_execute(&mut self) -> bool { if !self.it_state.is_active { return true; @@ -107,7 +107,8 @@ impl Interpreter { } pub fn read_file(&mut self, file_path: &String) -> bool { let file = File::open(file_path).expect("Could not open file: {file_path}"); - let lines: Vec = std::io::BufReader::new(file) + let lines: Vec = std::io::BufReader + ::new(file) .lines() .map(|line| line.expect("Could not read line from file")) .collect(); @@ -157,28 +158,17 @@ impl Interpreter { println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ CPSR FLAGS: ║"); println!("╟──────────────────────────────────────────────────────────────────╢"); - println!( - "║ Z (Zero): {:<5} ║", - self.cpsr.z - ); - println!( - "║ N (Negative): {:<5} ║", - self.cpsr.n - ); - println!( - "║ C (Carry): {:<5} ║", - self.cpsr.c - ); - println!( - "║ V (Overflow): {:<5} ║", - self.cpsr.v - ); + println!("║ Z (Zero): {:<5} ║", self.cpsr.z); + println!("║ N (Negative): {:<5} ║", self.cpsr.n); + println!("║ C (Carry): {:<5} ║", self.cpsr.c); + println!("║ V (Overflow): {:<5} ║", self.cpsr.v); println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ PROGRAM COUNTER: ║"); println!( "║ PC: {:>10} (0x{:08x}) ║", - self.pc, self.pc + self.pc, + self.pc ); println!("╟──────────────────────────────────────────────────────────────────╢"); @@ -331,10 +321,7 @@ impl Interpreter { value = self.get_reg(src_idx); self.set_reg(dest_idx, value); if self.debug { - println!( - "Mock: mov r{}, r{} (register to register)", - dest_idx, src_idx - ); + println!("Mock: mov r{}, r{} (register to register)", dest_idx, src_idx); } } } @@ -378,20 +365,14 @@ impl Interpreter { let src_val: u32; if let Some(src_str) = src.strip_prefix('r') { - let src_register = src_str - .replace("r", "") - .parse() - .expect("Unable to parse register"); + let src_register = src_str.replace("r", "").parse().expect("Unable to parse register"); src_val = self.get_reg(src_register); } else { src_val = self.memory.get_sp() as u32; } if let Some(dst_str) = dest.strip_prefix('r') { - let dst_register = dst_str - .replace("r", "") - .parse() - .expect("Unable to parse register"); + let dst_register = dst_str.replace("r", "").parse().expect("Unable to parse register"); let dst_val = self.get_reg(dst_register); } else if src == "sp" { self.memory.set_sp((src_val - sub_value) as usize); @@ -404,9 +385,7 @@ impl Interpreter { } let parts: Vec<&str> = content.split_whitespace().collect(); let dest_reg = parts[1].replace(",", ""); - let dest_idx: usize = dest_reg[1..] - .parse() - .expect("Failed to parse register index"); + let dest_idx: usize = dest_reg[1..].parse().expect("Failed to parse register index"); let value = self.get_reg(dest_idx); let addr_part = parts[2]; @@ -423,10 +402,7 @@ impl Interpreter { } else if part == "sp" { base_reg_name = "sp".to_string(); } else if part.starts_with("#") { - offset = part - .replace("#", "") - .parse() - .expect("Failed to parse offset"); + offset = part.replace("#", "").parse().expect("Failed to parse offset"); } } @@ -439,7 +415,7 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - let offset_from_sp = (base_addr as i32 - self.memory.get_sp() as i32 + offset) as usize; + let offset_from_sp = ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; self.memory.write_stack32(offset_from_sp, value); if self.debug { @@ -457,7 +433,7 @@ impl Interpreter { stack_data[sp], stack_data[sp + 1], stack_data[sp + 2], - stack_data[sp + 3] + stack_data[sp + 3], ]) ); } @@ -490,10 +466,7 @@ impl Interpreter { if part.starts_with("r") || part == "sp" { base_reg_name = part.to_string(); } else if part.starts_with("#") { - offset = part - .replace("#", "") - .parse() - .expect("Failed to parse offset"); + offset = part.replace("#", "").parse().expect("Failed to parse offset"); } } @@ -509,7 +482,9 @@ impl Interpreter { // 6. Calculate the effective offset relative to the stack start // Note: This logic assumes your memory model treats stack offsets relative to SP - let effective_offset = (base_addr as i32 - self.memory.get_sp() as i32 + offset) as usize; + let effective_offset = ((base_addr as i32) - + (self.memory.get_sp() as i32) + + offset) as usize; // 7. Load the value from memory and update the register let value = self.memory.read_stack32(effective_offset); @@ -518,7 +493,9 @@ impl Interpreter { if self.debug { println!( "Loaded value {} from stack offset {} into r{}", - value, effective_offset, dest_idx + value, + effective_offset, + dest_idx ); } } @@ -529,7 +506,7 @@ impl Interpreter { } let parts: Vec<&str> = content - .split(|c: char| c == ',' || c.is_whitespace()) + .split(|c: char| (c == ',' || c.is_whitespace())) .filter(|s| !s.is_empty()) .collect(); @@ -561,7 +538,13 @@ impl Interpreter { if self.debug { println!( "CMP Result: {:#x} - {:#x} = {:#x} | Flags: N:{} Z:{} C:{} V:{}", - val_n, val_op2, result, self.cpsr.n, self.cpsr.z, self.cpsr.c, self.cpsr.v + val_n, + val_op2, + result, + self.cpsr.n, + self.cpsr.z, + self.cpsr.c, + self.cpsr.v ); } } @@ -582,15 +565,53 @@ impl Interpreter { //NOTE: Maybe we could just use one single exec_b, and have it check if the instruction is beq //or ble etc. and use the cpsr register to do stuff instead of a million branch function for //each conditional version - fn exec_b(&self, content: String) { - //TODO: implement the branch function - println!("Instruction B Is Not Implemented yet."); + fn exec_b(&mut self, content: String) { + let parts: Vec<&str> = content.split_whitespace().collect(); + let instruction = parts[0]; // b / beq / bgt + let label = parts[1]; + + // Extract condition + let cond = if instruction.len() > 1 { + &instruction[1..] // eq, gt, etc + } else { + "AL" + }; + + if !self.cpsr.evaluate_condition(cond) { + return; + } + + // Jump + let branches = self.get_asm_branches(); + if let Some(target) = branches.get(label) { + for line in target { + println!("Executing from branch {} -> {}", label, line); + } + } } - - fn exec_beq(&self, content: String) { - //TODO: implement the function - println!("Instruction BEQ Is Not Implemented yet."); + fn exec_add(&mut self, content: String) { + let parts: Vec<&str> = content.split_whitespace().collect(); + + let dest = parts[1].replace(",", ""); + let src = parts[2].replace(",", ""); + let op2 = parts[3].replace(",", ""); + + let dest_idx: usize = dest[1..].parse().unwrap(); + let src_idx: usize = src[1..].parse().unwrap(); + + let src_val = self.get_reg(src_idx); + + let value = if let Some(imm) = op2.strip_prefix('#') { + imm.parse::().unwrap() + } else { + let reg_idx: usize = op2[1..].parse().unwrap(); + self.get_reg(reg_idx) + }; + + let result = src_val.wrapping_add(value); + + self.set_reg(dest_idx, result); } pub fn execute(&mut self) -> u32 { @@ -624,9 +645,9 @@ impl Interpreter { f if f.starts_with("ldr") => self.exec_ldr(content.clone()), f if f.starts_with("cmp") => self.exec_cmp(content.clone()), f if f.starts_with("it") => self.exec_itx(content.clone()), - f if instruction == "b" => self.exec_b(content.clone()), - f if instruction == "beq" => self.exec_beq(content.clone()), - _ => panic!("Invalid instruction") + f if f.starts_with("b") => self.exec_b(content.clone()), + f if f.starts_with("add") => self.exec_add(content.clone()), + Invalid => panic!("Invalid instruction: {Invalid}"), } } 0 @@ -739,7 +760,7 @@ mod tests { interp.file = vec![ "_start:".to_string(), " mov r0, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let branches = interp.get_asm_branches(); @@ -757,7 +778,7 @@ mod tests { " b else_block".to_string(), "else_block:".to_string(), " mov r0, #2".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let branches = interp.get_asm_branches(); @@ -773,7 +794,7 @@ mod tests { "_start:".to_string(), " mov r0, #10".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let exit_code = interp.execute(); @@ -792,7 +813,7 @@ mod tests { " ldr r1, [sp]".to_string(), " mov r0, r1".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let exit_code = interp.execute(); @@ -815,14 +836,8 @@ mod tests { interp.set_reg(1, 50); interp.exec_cmp("cmp r1, #100".to_string()); assert!(!interp.cpsr.z, "Z should be false when not equal"); - assert!( - interp.cpsr.n, - "N should be true because 50 - 100 is negative" - ); - assert!( - !interp.cpsr.c, - "C should be false because 50 < 100 (borrow occurred)" - ); + assert!(interp.cpsr.n, "N should be true because 50 - 100 is negative"); + assert!(!interp.cpsr.c, "C should be false because 50 < 100 (borrow occurred)"); // 3. Test Greater Than (Positive result) interp.set_reg(1, 200); @@ -834,15 +849,12 @@ mod tests { // 4. Test Signed Overflow (V flag) // Large positive minus a large negative results in a value // too big for 32-bit signed integer (wraps around) - interp.set_reg(1, 0x7FFFFFFF); // Max Positive i32 - interp.set_reg(2, 0xFFFFFFFF); // -1 in two's complement + interp.set_reg(1, 0x7fffffff); // Max Positive i32 + interp.set_reg(2, 0xffffffff); // -1 in two's complement // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) interp.exec_cmp("cmp r1, r2".to_string()); assert!(interp.cpsr.v, "V should be true due to signed overflow"); - assert!( - interp.cpsr.n, - "N should be true because result wrapped to 0x80000000" - ); + assert!(interp.cpsr.n, "N should be true because result wrapped to 0x80000000"); } #[test] fn test_it_block_execution_logic() { @@ -871,10 +883,7 @@ mod tests { // Test Instruction 2 (E) let should_run_2 = interp.cpsr.should_execute(); - assert!( - !should_run_2, - "Instruction 2 (E) should NOT run when GT is true" - ); + assert!(!should_run_2, "Instruction 2 (E) should NOT run when GT is true"); assert_eq!(interp.cpsr.it_state.current_instr, 2); // 3. Reset and Scenario B: Condition is FALSE (R1 < R0) @@ -887,17 +896,11 @@ mod tests { // Test Instruction 1 (T) let should_run_1_f = interp.cpsr.should_execute(); - assert!( - !should_run_1_f, - "Instruction 1 (T) should NOT run when GT is false" - ); + assert!(!should_run_1_f, "Instruction 1 (T) should NOT run when GT is false"); // Test Instruction 2 (E) let should_run_2_f = interp.cpsr.should_execute(); - assert!( - should_run_2_f, - "Instruction 2 (E) SHOULD run when GT is false (Else case)" - ); + assert!(should_run_2_f, "Instruction 2 (E) SHOULD run when GT is false (Else case)"); // Verify block auto-deactivates assert!( From 4e0dd1b6b34a999270aecfa6c39bea3b6d5a8a36 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 5 Mar 2026 10:29:00 +0100 Subject: [PATCH 08/34] adds compiled tests files for while loops --- interpreter/test_codes_compiled/simple.asm | 46 +++++++++++++++ .../test_codes_compiled/test_main_let.asm | 16 ++++++ .../test_codes_compiled/test_main_return.asm | 13 +++++ .../test_codes_compiled/test_while.asm | 33 +++++++++++ .../test_codes_compiled/test_while_nested.asm | 54 ++++++++++++++++++ .../test_codes_compiled/test_while_simple.asm | 33 +++++++++++ .../test_while_two_loops.asm | 56 +++++++++++++++++++ main.asm | 54 ++++++++++++++++++ 8 files changed, 305 insertions(+) create mode 100644 interpreter/test_codes_compiled/simple.asm create mode 100644 interpreter/test_codes_compiled/test_main_let.asm create mode 100644 interpreter/test_codes_compiled/test_main_return.asm create mode 100644 interpreter/test_codes_compiled/test_while.asm create mode 100644 interpreter/test_codes_compiled/test_while_nested.asm create mode 100644 interpreter/test_codes_compiled/test_while_simple.asm create mode 100644 interpreter/test_codes_compiled/test_while_two_loops.asm create mode 100644 main.asm diff --git a/interpreter/test_codes_compiled/simple.asm b/interpreter/test_codes_compiled/simple.asm new file mode 100644 index 0000000..6070b1c --- /dev/null +++ b/interpreter/test_codes_compiled/simple.asm @@ -0,0 +1,46 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + mov r0, #11 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_1 + mov r0, #11 + str r0, [sp] + b endif_1 +else_1: + mov r0, #11 + str r0, [sp] +endif_1: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_main_let.asm b/interpreter/test_codes_compiled/test_main_let.asm new file mode 100644 index 0000000..890e947 --- /dev/null +++ b/interpreter/test_codes_compiled/test_main_let.asm @@ -0,0 +1,16 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #27 + str r0, [sp] + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_main_return.asm b/interpreter/test_codes_compiled/test_main_return.asm new file mode 100644 index 0000000..01167be --- /dev/null +++ b/interpreter/test_codes_compiled/test_main_return.asm @@ -0,0 +1,13 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r0, #69 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_while.asm b/interpreter/test_codes_compiled/test_while.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/interpreter/test_codes_compiled/test_while.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_while_nested.asm b/interpreter/test_codes_compiled/test_while_nested.asm new file mode 100644 index 0000000..e8ede92 --- /dev/null +++ b/interpreter/test_codes_compiled/test_while_nested.asm @@ -0,0 +1,54 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #2 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + add sp, sp, #4 + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_while_simple.asm b/interpreter/test_codes_compiled/test_while_simple.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/interpreter/test_codes_compiled/test_while_simple.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/test_codes_compiled/test_while_two_loops.asm b/interpreter/test_codes_compiled/test_while_two_loops.asm new file mode 100644 index 0000000..18d6895 --- /dev/null +++ b/interpreter/test_codes_compiled/test_while_two_loops.asm @@ -0,0 +1,56 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #4 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #0] + add r0, r1, r0 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/main.asm b/main.asm new file mode 100644 index 0000000..e8ede92 --- /dev/null +++ b/main.asm @@ -0,0 +1,54 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #2 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + add sp, sp, #4 + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start From b43592f1eb9bd2c3b03cca3092854c94990ead66 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 5 Mar 2026 10:49:22 +0100 Subject: [PATCH 09/34] test for the qemu vs interpreter status codes --- interpreter/src/interpreter.rs | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index b0f2a22..90d4649 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -667,7 +667,68 @@ mod tests { fn create_interpreter() -> Interpreter { Interpreter::new() } + use std::fs; + use std::path::Path; + use std::process::Command; + fn run_qemu(asm_path: &str) -> i32 { + let path = Path::new(asm_path); + let stem = path.file_stem().unwrap().to_str().unwrap(); + + let obj = format!("/tmp/{}.o", stem); + let bin = format!("/tmp/{}", stem); + + // Assemble + let status = Command::new("arm-none-eabi-as") + .args(["-mthumb", "-o", &obj, asm_path]) + .status() + .expect("Failed to run assembler"); + + assert!(status.success(), "Assembler failed for {}", asm_path); + + // Link + let status = Command::new("arm-none-eabi-ld") + .args(["-o", &bin, &obj]) + .status() + .expect("Failed to run linker"); + + assert!(status.success(), "Linker failed for {}", asm_path); + + // Run in qemu + let status = Command::new("qemu-arm").arg(&bin).status().expect("Failed to run qemu"); + + status.code().unwrap_or(-1) + } + + #[test] + fn test_qemu_vs_interpreter() { + let test_dir = Path::new("test_codes_compiled"); + + for entry in fs::read_dir(test_dir).expect("Failed to read test directory") { + let entry = entry.unwrap(); + let path = entry.path(); + + if path.extension().and_then(|s| s.to_str()) != Some("asm") { + continue; + } + + let file_path = path.to_str().unwrap(); + + println!("Testing file: {}", file_path); + + // Run qemu + let qemu_exit = run_qemu(file_path); + + // Run interpreter + let mut interp = Interpreter::new(); + interp.read_file(&file_path.to_string()); + let interp_exit = interp.execute(); + + println!("Result -> qemu: {}, interpreter: {}", qemu_exit, interp_exit); + + assert_eq!(qemu_exit as u32, interp_exit, "Mismatch for {}", file_path); + } + } #[test] fn test_mov_immediate() { let mut interp = create_interpreter(); From b014c0f12c4262bdb884af3b4a8abaa057621192 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 5 Mar 2026 13:14:58 +0100 Subject: [PATCH 10/34] stuff --- interpreter/src/interpreter.rs | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 90d4649..bae48e2 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -566,39 +566,18 @@ impl Interpreter { //or ble etc. and use the cpsr register to do stuff instead of a million branch function for //each conditional version fn exec_b(&mut self, content: String) { - let parts: Vec<&str> = content.split_whitespace().collect(); - let instruction = parts[0]; // b / beq / bgt - let label = parts[1]; - - // Extract condition - let cond = if instruction.len() > 1 { - &instruction[1..] // eq, gt, etc - } else { - "AL" - }; - - if !self.cpsr.evaluate_condition(cond) { - return; - } - - // Jump - let branches = self.get_asm_branches(); - if let Some(target) = branches.get(label) { - for line in target { - println!("Executing from branch {} -> {}", label, line); - } - } + } fn exec_add(&mut self, content: String) { let parts: Vec<&str> = content.split_whitespace().collect(); let dest = parts[1].replace(",", ""); - let src = parts[2].replace(",", ""); + let op1 = parts[2].replace(",", ""); let op2 = parts[3].replace(",", ""); let dest_idx: usize = dest[1..].parse().unwrap(); - let src_idx: usize = src[1..].parse().unwrap(); + let src_idx: usize = op1[1..].parse().unwrap(); let src_val = self.get_reg(src_idx); @@ -623,7 +602,7 @@ impl Interpreter { let start_block = branches.get("_start").unwrap(); - for content in start_block.iter() { + for content in start_block.iter().enumerate() { let instruction = content.split_whitespace().next().unwrap_or(""); if !self.cpsr.should_execute() { @@ -649,6 +628,7 @@ impl Interpreter { f if f.starts_with("add") => self.exec_add(content.clone()), Invalid => panic!("Invalid instruction: {Invalid}"), } + self.set_pc(self.pc + 1); } 0 } From 5ff2aaa94d24a9ed2d449c6e8e585afc06b94ab6 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 5 Mar 2026 14:18:31 +0100 Subject: [PATCH 11/34] pooshe --- interpreter/src/interpreter.rs | 134 ++++++++++++++++++++++----------- interpreter/src/main.rs | 5 +- 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index bae48e2..2a1a52d 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -69,6 +69,8 @@ pub struct Interpreter { memory: EmulatorMemory, registers: [u32; NUM_REGISTERS], pc: u32, + branch_map: HashMap, + eof_pc: u32, cpsr: Cpsr, file: Vec, debug: bool, @@ -80,6 +82,8 @@ impl Interpreter { memory: EmulatorMemory::new(), registers: [0; NUM_REGISTERS], pc: 0, + branch_map: HashMap::new(), + eof_pc: 0, cpsr: Cpsr::default(), file: Vec::new(), debug: false, @@ -90,6 +94,10 @@ impl Interpreter { self.debug = debug; } + pub fn set_branch_map(&mut self, map: HashMap) { + self.branch_map = map; + } + pub fn get_reg(&self, index: usize) -> u32 { self.registers[index] } @@ -105,6 +113,10 @@ impl Interpreter { pub fn set_pc(&mut self, pc: u32) { self.pc = pc; } + + pub fn set_eof_pc(&mut self, pc: u32) { + self.eof_pc = pc; + } pub fn read_file(&mut self, file_path: &String) -> bool { let file = File::open(file_path).expect("Could not open file: {file_path}"); let lines: Vec = std::io::BufReader @@ -273,30 +285,37 @@ impl Interpreter { println!("-------------------- SHOUT FILE END --------------------"); } - fn get_asm_branches(&self) -> HashMap> { - let mut branches: HashMap> = HashMap::new(); - let mut current_branch: Option = None; - let mut current_instructions: Vec = Vec::new(); + fn get_start(&mut self) -> Vec { + let mut result = Vec::new(); + let mut branch_map : HashMap = HashMap::new(); + let mut found_start = false; for line in &self.file { - let trimmed = line.trim(); - - if trimmed.ends_with(":") && !trimmed.starts_with(" ") { - if let Some(branch_name) = current_branch { - branches.insert(branch_name, current_instructions.clone()); - current_instructions.clear(); + match line.starts_with("_start:") { + true => { + found_start = true; + let label = line.trim_start().to_string(); + result.push(label.clone()); + branch_map.insert(label, (result.len() - 1) as u32); + } + false => { + if found_start { + if line.starts_with(".size _start") { + result.pop(); + } else { + result.push(line.trim_start().to_string()); + if line.contains(":") { + branch_map.insert(line.trim_start().to_string(), (result.len() - 1) as u32); + } + } + } } - current_branch = Some(trimmed.trim_end_matches(':').to_string()); - } else if current_branch.is_some() && line.starts_with(" ") { - current_instructions.push(trimmed.to_string()); } } - - if let Some(branch_name) = current_branch { - branches.insert(branch_name, current_instructions); - } - - branches + + self.set_eof_pc(result.len() as u32); + self.set_branch_map(branch_map); + result } fn exec_mov(&mut self, content: String) { @@ -542,7 +561,6 @@ impl Interpreter { val_op2, result, self.cpsr.n, - self.cpsr.z, self.cpsr.c, self.cpsr.v ); @@ -562,11 +580,22 @@ impl Interpreter { self.cpsr.it_state.mask = mnemonic.chars().skip(1).collect(); } + fn exec_do_branch(&mut self, content: String) { + + } + //NOTE: Maybe we could just use one single exec_b, and have it check if the instruction is beq //or ble etc. and use the cpsr register to do stuff instead of a million branch function for //each conditional version fn exec_b(&mut self, content: String) { - + // trim instruction to branch or branch + condition + // if condition: + // if condition true: + // branch + // else + // return + // else + self.exec_do_branch(content); } fn exec_add(&mut self, content: String) { @@ -576,35 +605,44 @@ impl Interpreter { let op1 = parts[2].replace(",", ""); let op2 = parts[3].replace(",", ""); - let dest_idx: usize = dest[1..].parse().unwrap(); - let src_idx: usize = op1[1..].parse().unwrap(); + let dest_idx: usize = if dest == "sp" { + 13 + } else { + dest[1..].parse().unwrap() + }; - let src_val = self.get_reg(src_idx); + let src_val: u32 = if op1 == "sp" { + self.memory.get_sp() as u32 + } else { + let src_idx: usize = op1[1..].parse().unwrap(); + self.get_reg(src_idx) + }; let value = if let Some(imm) = op2.strip_prefix('#') { imm.parse::().unwrap() } else { - let reg_idx: usize = op2[1..].parse().unwrap(); + let reg_idx: usize = if op2 == "sp" { + 13 + } else { + op2[1..].parse().unwrap() + }; self.get_reg(reg_idx) }; let result = src_val.wrapping_add(value); - self.set_reg(dest_idx, result); + if dest == "sp" { + self.memory.set_sp(result as usize); + } else { + self.set_reg(dest_idx, result); + } } pub fn execute(&mut self) -> u32 { - let branches = self.get_asm_branches(); - - if !branches.contains_key("_start") { - panic!("_start label not found"); - } - - let start_block = branches.get("_start").unwrap(); - - for content in start_block.iter().enumerate() { - let instruction = content.split_whitespace().next().unwrap_or(""); - + let start_block = self.get_start(); + while self.pc < self.eof_pc { + let instruction = start_block.get(self.pc as usize).unwrap(); + let pc = self.pc; if !self.cpsr.should_execute() { if self.debug { println!(" -> Condition not met, skipping."); @@ -613,19 +651,23 @@ impl Interpreter { } match instruction { - f if f.starts_with("mov") => self.exec_mov(content.clone()), + f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { - if let Some(exit_code) = self.exec_svc(content.clone()) { + if let Some(exit_code) = self.exec_svc(instruction.clone()) { return exit_code; } } - f if f.starts_with("sub") => self.exec_sub(content.clone()), - f if f.starts_with("str") => self.exec_str(content.clone()), - f if f.starts_with("ldr") => self.exec_ldr(content.clone()), - f if f.starts_with("cmp") => self.exec_cmp(content.clone()), - f if f.starts_with("it") => self.exec_itx(content.clone()), - f if f.starts_with("b") => self.exec_b(content.clone()), - f if f.starts_with("add") => self.exec_add(content.clone()), + f if f.starts_with("sub") => self.exec_sub(instruction.clone()), + f if f.starts_with("str") => self.exec_str(instruction.clone()), + f if f.starts_with("ldr") => self.exec_ldr(instruction.clone()), + f if f.starts_with("cmp") => self.exec_cmp(instruction.clone()), + f if f.starts_with("it") => self.exec_itx(instruction.clone()), + f if f.starts_with("b") => self.exec_b(instruction.clone()), + f if f.starts_with("add") => self.exec_add(instruction.clone()), + f if f.contains(":") => { + self.set_pc(self.pc + 1); + continue; + } Invalid => panic!("Invalid instruction: {Invalid}"), } self.set_pc(self.pc + 1); diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 85be995..0d8e9b3 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -11,12 +11,9 @@ fn main() { let debug = if args.iter().any(|a| a == "--debug" || a == "-d") { true - } else if args.iter().any(|a| a == "--release-debug" || a == "-r") { + } else { false - } else { - cfg!(debug_assertions) }; - let file_path = &args[1]; let mut interpreter = Interpreter::default(); interpreter.set_debug(debug); From b8c9a4c130b6391ae76b38f4d85023bfd1705e8d Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 5 Mar 2026 15:50:06 +0100 Subject: [PATCH 12/34] stuff --- interpreter/src/interpreter.rs | 76 ++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 2a1a52d..fea69f9 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -287,7 +287,7 @@ impl Interpreter { fn get_start(&mut self) -> Vec { let mut result = Vec::new(); - let mut branch_map : HashMap = HashMap::new(); + let mut branch_map: HashMap = HashMap::new(); let mut found_start = false; for line in &self.file { @@ -296,23 +296,33 @@ impl Interpreter { found_start = true; let label = line.trim_start().to_string(); result.push(label.clone()); - branch_map.insert(label, (result.len() - 1) as u32); + branch_map.insert( + label[0..label.len() - 1].to_string(), + (result.len() - 1) as u32 + ); } false => { if found_start { if line.starts_with(".size _start") { result.pop(); } else { + let label = line.trim_start().to_string(); result.push(line.trim_start().to_string()); if line.contains(":") { - branch_map.insert(line.trim_start().to_string(), (result.len() - 1) as u32); + branch_map.insert( + label[0..label.len() - 1].to_string(), + (result.len() - 1) as u32 + ); } } } } } } - + for (k, v) in branch_map.clone() { + println!("label: {k}, pc: {v}"); + } + self.set_eof_pc(result.len() as u32); self.set_branch_map(branch_map); result @@ -561,6 +571,7 @@ impl Interpreter { val_op2, result, self.cpsr.n, + self.cpsr.z, self.cpsr.c, self.cpsr.v ); @@ -580,22 +591,23 @@ impl Interpreter { self.cpsr.it_state.mask = mnemonic.chars().skip(1).collect(); } - fn exec_do_branch(&mut self, content: String) { - - } - //NOTE: Maybe we could just use one single exec_b, and have it check if the instruction is beq //or ble etc. and use the cpsr register to do stuff instead of a million branch function for //each conditional version fn exec_b(&mut self, content: String) { // trim instruction to branch or branch + condition - // if condition: - // if condition true: - // branch - // else - // return - // else - self.exec_do_branch(content); + let parts: Vec<&str> = content.split_whitespace().collect(); + if parts[0].len() > 1 { + let cond = &parts[0][1..]; + let is_cond = self.cpsr.evaluate_condition(cond); + if is_cond { + self.set_pc(self.branch_map.get(parts[1]).unwrap().clone()); + } else { + return; + } + } else { + self.set_pc(self.branch_map.get(parts[1]).unwrap().clone()); + } } fn exec_add(&mut self, content: String) { @@ -605,11 +617,7 @@ impl Interpreter { let op1 = parts[2].replace(",", ""); let op2 = parts[3].replace(",", ""); - let dest_idx: usize = if dest == "sp" { - 13 - } else { - dest[1..].parse().unwrap() - }; + let dest_idx: usize = if dest == "sp" { 13 } else { dest[1..].parse().unwrap() }; let src_val: u32 = if op1 == "sp" { self.memory.get_sp() as u32 @@ -621,11 +629,7 @@ impl Interpreter { let value = if let Some(imm) = op2.strip_prefix('#') { imm.parse::().unwrap() } else { - let reg_idx: usize = if op2 == "sp" { - 13 - } else { - op2[1..].parse().unwrap() - }; + let reg_idx: usize = if op2 == "sp" { 13 } else { op2[1..].parse().unwrap() }; self.get_reg(reg_idx) }; @@ -647,9 +651,9 @@ impl Interpreter { if self.debug { println!(" -> Condition not met, skipping."); } + self.set_pc(self.pc + 1); continue; // Skip the match logic entirely } - match instruction { f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { @@ -740,11 +744,11 @@ mod tests { // Run qemu let qemu_exit = run_qemu(file_path); - // Run interpreter let mut interp = Interpreter::new(); interp.read_file(&file_path.to_string()); let interp_exit = interp.execute(); + println!("file executed"); println!("Result -> qemu: {}, interpreter: {}", qemu_exit, interp_exit); @@ -838,7 +842,7 @@ mod tests { } #[test] - fn test_get_asm_branches_single_function() { + fn test_get_start_single_function() { let mut interp = create_interpreter(); interp.file = vec![ "_start:".to_string(), @@ -846,10 +850,10 @@ mod tests { " svc #0".to_string() ]; - let branches = interp.get_asm_branches(); - - assert!(branches.contains_key("_start")); - assert_eq!(branches["_start"].len(), 2); + let start_block = interp.get_start(); + let test_label = "_start:".to_string(); + assert!(start_block.contains(&test_label)); + assert_eq!(start_block.len(), 3); } #[test] @@ -864,10 +868,10 @@ mod tests { " svc #0".to_string() ]; - let branches = interp.get_asm_branches(); - - assert!(branches.contains_key("_start")); - assert!(branches.contains_key("else_block")); + let start_block = interp.get_start(); + + assert!(start_block.contains(&"_start".to_string())); + assert!(start_block.contains(&"else_block".to_string())); } #[test] From 5e0488c5430dccacbd75d5def0ba5189ff9fc452 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 5 Mar 2026 18:48:29 +0100 Subject: [PATCH 13/34] some stuff i tried, progress i think --- interpreter/main.asm | 54 +++++++++++++++++++ interpreter/src/interpreter.rs | 19 ++++--- interpreter/test_codes/simple.trv | 13 +++++ interpreter/test_codes/simple.trv.output | 1 + interpreter/test_codes/test_if_else.trv | 9 ++++ .../test_codes/test_if_else.trv.output | 1 + interpreter/test_codes/test_main_let.trv | 4 ++ .../test_codes/test_main_let.trv.output | 1 + interpreter/test_codes/test_main_return.trv | 3 ++ .../test_codes/test_main_return.trv.output | 1 + interpreter/test_codes/test_while.trv | 7 +++ interpreter/test_codes/test_while.trv.output | 1 + interpreter/test_codes/test_while_nested.trv | 11 ++++ .../test_codes/test_while_nested.trv.output | 1 + interpreter/test_codes/test_while_simple.trv | 7 +++ .../test_codes/test_while_simple.trv.output | 1 + .../test_codes/test_while_two_loops.trv | 11 ++++ .../test_while_two_loops.trv.output | 1 + 18 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 interpreter/main.asm create mode 100644 interpreter/test_codes/simple.trv create mode 100644 interpreter/test_codes/simple.trv.output create mode 100644 interpreter/test_codes/test_if_else.trv create mode 100644 interpreter/test_codes/test_if_else.trv.output create mode 100644 interpreter/test_codes/test_main_let.trv create mode 100644 interpreter/test_codes/test_main_let.trv.output create mode 100644 interpreter/test_codes/test_main_return.trv create mode 100644 interpreter/test_codes/test_main_return.trv.output create mode 100644 interpreter/test_codes/test_while.trv create mode 100644 interpreter/test_codes/test_while.trv.output create mode 100644 interpreter/test_codes/test_while_nested.trv create mode 100644 interpreter/test_codes/test_while_nested.trv.output create mode 100644 interpreter/test_codes/test_while_simple.trv create mode 100644 interpreter/test_codes/test_while_simple.trv.output create mode 100644 interpreter/test_codes/test_while_two_loops.trv create mode 100644 interpreter/test_codes/test_while_two_loops.trv.output diff --git a/interpreter/main.asm b/interpreter/main.asm new file mode 100644 index 0000000..e8ede92 --- /dev/null +++ b/interpreter/main.asm @@ -0,0 +1,54 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #2 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + add sp, sp, #4 + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index fea69f9..daf7c07 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::BufRead; +use std::process::exit; use crate::memory::EmulatorMemory; @@ -319,12 +320,14 @@ impl Interpreter { } } } + for (k, v) in branch_map.clone() { - println!("label: {k}, pc: {v}"); + println!("label: {k} at {v}"); } self.set_eof_pc(result.len() as u32); self.set_branch_map(branch_map); + exit(1); result } @@ -600,9 +603,13 @@ impl Interpreter { if parts[0].len() > 1 { let cond = &parts[0][1..]; let is_cond = self.cpsr.evaluate_condition(cond); + println!("is_cond: {is_cond}"); if is_cond { - self.set_pc(self.branch_map.get(parts[1]).unwrap().clone()); + let branch_pc = self.branch_map.get(parts[1]).unwrap().clone(); + println!("branching to {branch_pc}"); + self.set_pc(branch_pc); } else { + self.set_pc(self.get_pc() + 1); return; } } else { @@ -646,7 +653,6 @@ impl Interpreter { let start_block = self.get_start(); while self.pc < self.eof_pc { let instruction = start_block.get(self.pc as usize).unwrap(); - let pc = self.pc; if !self.cpsr.should_execute() { if self.debug { println!(" -> Condition not met, skipping."); @@ -666,11 +672,12 @@ impl Interpreter { f if f.starts_with("ldr") => self.exec_ldr(instruction.clone()), f if f.starts_with("cmp") => self.exec_cmp(instruction.clone()), f if f.starts_with("it") => self.exec_itx(instruction.clone()), - f if f.starts_with("b") => self.exec_b(instruction.clone()), + f if f.starts_with("b") => { + self.exec_b(instruction.clone()); + continue; + } f if f.starts_with("add") => self.exec_add(instruction.clone()), f if f.contains(":") => { - self.set_pc(self.pc + 1); - continue; } Invalid => panic!("Invalid instruction: {Invalid}"), } diff --git a/interpreter/test_codes/simple.trv b/interpreter/test_codes/simple.trv new file mode 100644 index 0000000..62abea2 --- /dev/null +++ b/interpreter/test_codes/simple.trv @@ -0,0 +1,13 @@ +func main() -> Integer { + let num : Integer = 0; + + while num < 10 do { + num = 11; + } + if num > 10 { + num = 12; + } else { + num = 11; + } + return num; +} diff --git a/interpreter/test_codes/simple.trv.output b/interpreter/test_codes/simple.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/interpreter/test_codes/simple.trv.output @@ -0,0 +1 @@ +12 diff --git a/interpreter/test_codes/test_if_else.trv b/interpreter/test_codes/test_if_else.trv new file mode 100644 index 0000000..3b984ea --- /dev/null +++ b/interpreter/test_codes/test_if_else.trv @@ -0,0 +1,9 @@ +func main() -> Integer { + let num : Integer = 9; + if num > 10 { + num = 11; + } else { + num = 12; + } + return num; +} diff --git a/interpreter/test_codes/test_if_else.trv.output b/interpreter/test_codes/test_if_else.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/interpreter/test_codes/test_if_else.trv.output @@ -0,0 +1 @@ +12 diff --git a/interpreter/test_codes/test_main_let.trv b/interpreter/test_codes/test_main_let.trv new file mode 100644 index 0000000..fdc57cb --- /dev/null +++ b/interpreter/test_codes/test_main_let.trv @@ -0,0 +1,4 @@ +func main() -> Integer { + let num : Integer = 27; + return num; +} diff --git a/interpreter/test_codes/test_main_let.trv.output b/interpreter/test_codes/test_main_let.trv.output new file mode 100644 index 0000000..f64f5d8 --- /dev/null +++ b/interpreter/test_codes/test_main_let.trv.output @@ -0,0 +1 @@ +27 diff --git a/interpreter/test_codes/test_main_return.trv b/interpreter/test_codes/test_main_return.trv new file mode 100644 index 0000000..c66bbb3 --- /dev/null +++ b/interpreter/test_codes/test_main_return.trv @@ -0,0 +1,3 @@ +func main() -> Integer { + return 69; +} diff --git a/interpreter/test_codes/test_main_return.trv.output b/interpreter/test_codes/test_main_return.trv.output new file mode 100644 index 0000000..b5489e5 --- /dev/null +++ b/interpreter/test_codes/test_main_return.trv.output @@ -0,0 +1 @@ +69 diff --git a/interpreter/test_codes/test_while.trv b/interpreter/test_codes/test_while.trv new file mode 100644 index 0000000..db54eef --- /dev/null +++ b/interpreter/test_codes/test_while.trv @@ -0,0 +1,7 @@ +func main() -> Integer { + let num : Integer = 9; + while num < 12 { + num = num + 1; + } + return num; +} diff --git a/interpreter/test_codes/test_while.trv.output b/interpreter/test_codes/test_while.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/interpreter/test_codes/test_while.trv.output @@ -0,0 +1 @@ +12 diff --git a/interpreter/test_codes/test_while_nested.trv b/interpreter/test_codes/test_while_nested.trv new file mode 100644 index 0000000..7102f7f --- /dev/null +++ b/interpreter/test_codes/test_while_nested.trv @@ -0,0 +1,11 @@ +func main() -> Integer { + let a : Integer = 0; + while a < 3 { + let b : Integer = 0; + while b < 2 { + b = b + 1; + } + a = a + 1; + } + return a; +} diff --git a/interpreter/test_codes/test_while_nested.trv.output b/interpreter/test_codes/test_while_nested.trv.output new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/interpreter/test_codes/test_while_nested.trv.output @@ -0,0 +1 @@ +3 diff --git a/interpreter/test_codes/test_while_simple.trv b/interpreter/test_codes/test_while_simple.trv new file mode 100644 index 0000000..db54eef --- /dev/null +++ b/interpreter/test_codes/test_while_simple.trv @@ -0,0 +1,7 @@ +func main() -> Integer { + let num : Integer = 9; + while num < 12 { + num = num + 1; + } + return num; +} diff --git a/interpreter/test_codes/test_while_simple.trv.output b/interpreter/test_codes/test_while_simple.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/interpreter/test_codes/test_while_simple.trv.output @@ -0,0 +1 @@ +12 diff --git a/interpreter/test_codes/test_while_two_loops.trv b/interpreter/test_codes/test_while_two_loops.trv new file mode 100644 index 0000000..629c22c --- /dev/null +++ b/interpreter/test_codes/test_while_two_loops.trv @@ -0,0 +1,11 @@ +func main() -> Integer { + let a : Integer = 0; + let b : Integer = 0; + while a < 3 { + a = a + 1; + } + while b < 4 { + b = b + 1; + } + return a+b; +} diff --git a/interpreter/test_codes/test_while_two_loops.trv.output b/interpreter/test_codes/test_while_two_loops.trv.output new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/interpreter/test_codes/test_while_two_loops.trv.output @@ -0,0 +1 @@ +7 From 2fefcedbac4f45bfe952c69d0906c958495b0108 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 6 Mar 2026 09:02:59 +0100 Subject: [PATCH 14/34] fixed --- interpreter/Cargo.lock | 14 ++--- interpreter/Cargo.toml | 2 +- interpreter/src/interpreter.rs | 99 +++++++++++++--------------------- interpreter/src/main.rs | 2 +- 4 files changed, 45 insertions(+), 72 deletions(-) diff --git a/interpreter/Cargo.lock b/interpreter/Cargo.lock index d05ddc0..7d4ed1d 100644 --- a/interpreter/Cargo.lock +++ b/interpreter/Cargo.lock @@ -2,13 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Thumb2Interpreter" -version = "0.1.0" -dependencies = [ - "pretty_assertions", -] - [[package]] name = "diff" version = "0.1.13" @@ -25,6 +18,13 @@ dependencies = [ "yansi", ] +[[package]] +name = "thumb2_interpreter" +version = "0.1.0" +dependencies = [ + "pretty_assertions", +] + [[package]] name = "yansi" version = "1.0.1" diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml index 472d808..d27b37e 100644 --- a/interpreter/Cargo.toml +++ b/interpreter/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "Thumb2Interpreter" +name = "thumb2_interpreter" version = "0.1.0" edition = "2024" diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index daf7c07..7219ed2 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::fs::File; use std::io::BufRead; -use std::process::exit; use crate::memory::EmulatorMemory; @@ -321,13 +320,9 @@ impl Interpreter { } } - for (k, v) in branch_map.clone() { - println!("label: {k} at {v}"); - } self.set_eof_pc(result.len() as u32); self.set_branch_map(branch_map); - exit(1); result } @@ -405,7 +400,7 @@ impl Interpreter { if let Some(dst_str) = dest.strip_prefix('r') { let dst_register = dst_str.replace("r", "").parse().expect("Unable to parse register"); - let dst_val = self.get_reg(dst_register); + let _dst_val = self.get_reg(dst_register); } else if src == "sp" { self.memory.set_sp((src_val - sub_value) as usize); } @@ -420,34 +415,34 @@ impl Interpreter { let dest_idx: usize = dest_reg[1..].parse().expect("Failed to parse register index"); let value = self.get_reg(dest_idx); - let addr_part = parts[2]; - let addr_part = addr_part.replace("[", "").replace("]", ""); + let addr_part = content + .split_once('[') + .and_then(|(_, rest)| rest.split_once(']')) + .map(|(inside, _)| inside) + .unwrap_or(""); let mut base_addr: usize = 0; let mut offset: i32 = 0; let mut base_reg_name = String::new(); - for part in addr_part.split(",") { + for part in addr_part.split(',') { let part = part.trim(); - if part.starts_with("r") { + if part == "sp" || part.starts_with('r') { base_reg_name = part.to_string(); - } else if part == "sp" { - base_reg_name = "sp".to_string(); - } else if part.starts_with("#") { - offset = part.replace("#", "").parse().expect("Failed to parse offset"); + } else if let Some(imm) = part.strip_prefix('#') { + offset = imm.parse().expect("Failed to parse offset"); } } if base_reg_name == "sp" { base_addr = self.memory.get_sp(); - } else if base_reg_name.starts_with("r") { - let reg_idx: usize = base_reg_name[1..] - .parse() - .expect("Failed to parse register index"); + } else if let Some(reg_num) = base_reg_name.strip_prefix('r') { + let reg_idx: usize = reg_num.parse().expect("Failed to parse register index"); base_addr = self.get_reg(reg_idx) as usize; } - let offset_from_sp = ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; + let offset_from_sp = + ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; self.memory.write_stack32(offset_from_sp, value); if self.debug { @@ -485,38 +480,39 @@ impl Interpreter { .parse() .expect("Failed to parse destination register index"); - // 3. Clean up the address part (e.g., "[sp, #0]" -> "sp, #0") - let addr_part = parts[2].replace("[", "").replace("]", ""); + // 3. Extract the address contents between '[' and ']' + // Handles forms like: [sp], [sp,#4], [sp, #4] + let addr_part = content + .split_once('[') + .and_then(|(_, rest)| rest.split_once(']')) + .map(|(inside, _)| inside) + .unwrap_or(""); let mut base_addr: usize = 0; let mut offset: i32 = 0; let mut base_reg_name = String::new(); - // 4. Parse the base register and the offset - for part in addr_part.split(",") { + // 4. Parse the base register and optional immediate offset + for part in addr_part.split(',') { let part = part.trim(); - if part.starts_with("r") || part == "sp" { + if part == "sp" || part.starts_with('r') { base_reg_name = part.to_string(); - } else if part.starts_with("#") { - offset = part.replace("#", "").parse().expect("Failed to parse offset"); + } else if let Some(imm) = part.strip_prefix('#') { + offset = imm.parse().expect("Failed to parse offset"); } } // 5. Calculate the actual base address from the register if base_reg_name == "sp" { base_addr = self.memory.get_sp(); - } else if base_reg_name.starts_with("r") { - let reg_idx: usize = base_reg_name[1..] - .parse() - .expect("Failed to parse base register index"); + } else if let Some(reg_num) = base_reg_name.strip_prefix('r') { + let reg_idx: usize = reg_num.parse().expect("Failed to parse base register index"); base_addr = self.get_reg(reg_idx) as usize; } - // 6. Calculate the effective offset relative to the stack start - // Note: This logic assumes your memory model treats stack offsets relative to SP - let effective_offset = ((base_addr as i32) - - (self.memory.get_sp() as i32) + - offset) as usize; + // 6. Calculate the effective offset relative to the current SP + let effective_offset = + ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; // 7. Load the value from memory and update the register let value = self.memory.read_stack32(effective_offset); @@ -538,7 +534,7 @@ impl Interpreter { } let parts: Vec<&str> = content - .split(|c: char| (c == ',' || c.is_whitespace())) + .split(|c: char| c == ',' || c.is_whitespace()) .filter(|s| !s.is_empty()) .collect(); @@ -555,8 +551,7 @@ impl Interpreter { let rm_idx: usize = parts[2][1..].parse().expect("Failed to parse Rm index"); self.get_reg(rm_idx) }; - let res_u64 = (val_n as u64).wrapping_sub(val_op2 as u64); - let result = res_u64 as u32; + let result = (val_n).wrapping_sub(val_op2); self.cpsr.z = result == 0; self.cpsr.n = (result >> 31) == 1; @@ -603,17 +598,16 @@ impl Interpreter { if parts[0].len() > 1 { let cond = &parts[0][1..]; let is_cond = self.cpsr.evaluate_condition(cond); - println!("is_cond: {is_cond}"); if is_cond { let branch_pc = self.branch_map.get(parts[1]).unwrap().clone(); - println!("branching to {branch_pc}"); self.set_pc(branch_pc); } else { self.set_pc(self.get_pc() + 1); return; } } else { - self.set_pc(self.branch_map.get(parts[1]).unwrap().clone()); + let branch_pc = self.branch_map.get(parts[1]).unwrap().clone(); + self.set_pc(branch_pc); } } @@ -679,7 +673,7 @@ impl Interpreter { f if f.starts_with("add") => self.exec_add(instruction.clone()), f if f.contains(":") => { } - Invalid => panic!("Invalid instruction: {Invalid}"), + invalid => panic!("Invalid instruction: {invalid}"), } self.set_pc(self.pc + 1); } @@ -747,7 +741,6 @@ mod tests { let file_path = path.to_str().unwrap(); - println!("Testing file: {}", file_path); // Run qemu let qemu_exit = run_qemu(file_path); @@ -755,9 +748,7 @@ mod tests { let mut interp = Interpreter::new(); interp.read_file(&file_path.to_string()); let interp_exit = interp.execute(); - println!("file executed"); - println!("Result -> qemu: {}, interpreter: {}", qemu_exit, interp_exit); assert_eq!(qemu_exit as u32, interp_exit, "Mismatch for {}", file_path); } @@ -863,24 +854,6 @@ mod tests { assert_eq!(start_block.len(), 3); } - #[test] - fn test_get_asm_branches_multiple_functions() { - let mut interp = create_interpreter(); - interp.file = vec![ - "_start:".to_string(), - " mov r0, #1".to_string(), - " b else_block".to_string(), - "else_block:".to_string(), - " mov r0, #2".to_string(), - " svc #0".to_string() - ]; - - let start_block = interp.get_start(); - - assert!(start_block.contains(&"_start".to_string())); - assert!(start_block.contains(&"else_block".to_string())); - } - #[test] fn test_execute_simple_program() { let mut interp = create_interpreter(); diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 0d8e9b3..08a433f 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -1,5 +1,5 @@ use std::env; -use Thumb2Interpreter::interpreter::Interpreter; +use thumb2_interpreter::interpreter::Interpreter; fn main() { let args: Vec = env::args().collect(); From c2083dc1a1c5106d047d8da7b1924936eee62093 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 6 Mar 2026 10:13:56 +0100 Subject: [PATCH 15/34] infinite loop detection --- interpreter/src/interpreter.rs | 148 +++++++++++++++++++++++---------- interpreter/src/main.rs | 4 +- 2 files changed, 105 insertions(+), 47 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 7219ed2..a1bad87 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::BufRead; +use std::process::exit; use crate::memory::EmulatorMemory; @@ -52,7 +53,11 @@ impl Cpsr { let is_then = self.it_state.mask[step_idx] == 't'; let condition_met = self.evaluate_condition(&self.it_state.base_cond); - let execute = if is_then { condition_met } else { !condition_met }; + let execute = if is_then { + condition_met + } else { + !condition_met + }; // Advance or Reset self.it_state.current_instr += 1; @@ -74,6 +79,8 @@ pub struct Interpreter { cpsr: Cpsr, file: Vec, debug: bool, + start_time: std::time::Instant, + max_time: std::time::Duration, } impl Interpreter { @@ -87,6 +94,8 @@ impl Interpreter { cpsr: Cpsr::default(), file: Vec::new(), debug: false, + start_time: std::time::Instant::now(), + max_time: std::time::Duration::from_millis(10), } } @@ -94,6 +103,10 @@ impl Interpreter { self.debug = debug; } + pub fn set_max_time(&mut self, nanoseconds: u128) { + self.max_time = std::time::Duration::from_nanos_u128(nanoseconds); + } + pub fn set_branch_map(&mut self, map: HashMap) { self.branch_map = map; } @@ -119,8 +132,7 @@ impl Interpreter { } pub fn read_file(&mut self, file_path: &String) -> bool { let file = File::open(file_path).expect("Could not open file: {file_path}"); - let lines: Vec = std::io::BufReader - ::new(file) + let lines: Vec = std::io::BufReader::new(file) .lines() .map(|line| line.expect("Could not read line from file")) .collect(); @@ -170,17 +182,28 @@ impl Interpreter { println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ CPSR FLAGS: ║"); println!("╟──────────────────────────────────────────────────────────────────╢"); - println!("║ Z (Zero): {:<5} ║", self.cpsr.z); - println!("║ N (Negative): {:<5} ║", self.cpsr.n); - println!("║ C (Carry): {:<5} ║", self.cpsr.c); - println!("║ V (Overflow): {:<5} ║", self.cpsr.v); + println!( + "║ Z (Zero): {:<5} ║", + self.cpsr.z + ); + println!( + "║ N (Negative): {:<5} ║", + self.cpsr.n + ); + println!( + "║ C (Carry): {:<5} ║", + self.cpsr.c + ); + println!( + "║ V (Overflow): {:<5} ║", + self.cpsr.v + ); println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ PROGRAM COUNTER: ║"); println!( "║ PC: {:>10} (0x{:08x}) ║", - self.pc, - self.pc + self.pc, self.pc ); println!("╟──────────────────────────────────────────────────────────────────╢"); @@ -298,7 +321,7 @@ impl Interpreter { result.push(label.clone()); branch_map.insert( label[0..label.len() - 1].to_string(), - (result.len() - 1) as u32 + (result.len() - 1) as u32, ); } false => { @@ -311,7 +334,7 @@ impl Interpreter { if line.contains(":") { branch_map.insert( label[0..label.len() - 1].to_string(), - (result.len() - 1) as u32 + (result.len() - 1) as u32, ); } } @@ -320,7 +343,6 @@ impl Interpreter { } } - self.set_eof_pc(result.len() as u32); self.set_branch_map(branch_map); result @@ -348,7 +370,10 @@ impl Interpreter { value = self.get_reg(src_idx); self.set_reg(dest_idx, value); if self.debug { - println!("Mock: mov r{}, r{} (register to register)", dest_idx, src_idx); + println!( + "Mock: mov r{}, r{} (register to register)", + dest_idx, src_idx + ); } } } @@ -392,14 +417,20 @@ impl Interpreter { let src_val: u32; if let Some(src_str) = src.strip_prefix('r') { - let src_register = src_str.replace("r", "").parse().expect("Unable to parse register"); + let src_register = src_str + .replace("r", "") + .parse() + .expect("Unable to parse register"); src_val = self.get_reg(src_register); } else { src_val = self.memory.get_sp() as u32; } if let Some(dst_str) = dest.strip_prefix('r') { - let dst_register = dst_str.replace("r", "").parse().expect("Unable to parse register"); + let dst_register = dst_str + .replace("r", "") + .parse() + .expect("Unable to parse register"); let _dst_val = self.get_reg(dst_register); } else if src == "sp" { self.memory.set_sp((src_val - sub_value) as usize); @@ -412,7 +443,9 @@ impl Interpreter { } let parts: Vec<&str> = content.split_whitespace().collect(); let dest_reg = parts[1].replace(",", ""); - let dest_idx: usize = dest_reg[1..].parse().expect("Failed to parse register index"); + let dest_idx: usize = dest_reg[1..] + .parse() + .expect("Failed to parse register index"); let value = self.get_reg(dest_idx); let addr_part = content @@ -441,8 +474,7 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - let offset_from_sp = - ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; + let offset_from_sp = ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; self.memory.write_stack32(offset_from_sp, value); if self.debug { @@ -506,7 +538,9 @@ impl Interpreter { if base_reg_name == "sp" { base_addr = self.memory.get_sp(); } else if let Some(reg_num) = base_reg_name.strip_prefix('r') { - let reg_idx: usize = reg_num.parse().expect("Failed to parse base register index"); + let reg_idx: usize = reg_num + .parse() + .expect("Failed to parse base register index"); base_addr = self.get_reg(reg_idx) as usize; } @@ -521,9 +555,7 @@ impl Interpreter { if self.debug { println!( "Loaded value {} from stack offset {} into r{}", - value, - effective_offset, - dest_idx + value, effective_offset, dest_idx ); } } @@ -565,13 +597,7 @@ impl Interpreter { if self.debug { println!( "CMP Result: {:#x} - {:#x} = {:#x} | Flags: N:{} Z:{} C:{} V:{}", - val_n, - val_op2, - result, - self.cpsr.n, - self.cpsr.z, - self.cpsr.c, - self.cpsr.v + val_n, val_op2, result, self.cpsr.n, self.cpsr.z, self.cpsr.c, self.cpsr.v ); } } @@ -618,7 +644,11 @@ impl Interpreter { let op1 = parts[2].replace(",", ""); let op2 = parts[3].replace(",", ""); - let dest_idx: usize = if dest == "sp" { 13 } else { dest[1..].parse().unwrap() }; + let dest_idx: usize = if dest == "sp" { + 13 + } else { + dest[1..].parse().unwrap() + }; let src_val: u32 = if op1 == "sp" { self.memory.get_sp() as u32 @@ -630,7 +660,11 @@ impl Interpreter { let value = if let Some(imm) = op2.strip_prefix('#') { imm.parse::().unwrap() } else { - let reg_idx: usize = if op2 == "sp" { 13 } else { op2[1..].parse().unwrap() }; + let reg_idx: usize = if op2 == "sp" { + 13 + } else { + op2[1..].parse().unwrap() + }; self.get_reg(reg_idx) }; @@ -647,6 +681,10 @@ impl Interpreter { let start_block = self.get_start(); while self.pc < self.eof_pc { let instruction = start_block.get(self.pc as usize).unwrap(); + if self.start_time.elapsed().as_nanos() > self.max_time.as_nanos() { + println!("Detected Infinite Loop"); + exit(88) + } if !self.cpsr.should_execute() { if self.debug { println!(" -> Condition not met, skipping."); @@ -671,8 +709,7 @@ impl Interpreter { continue; } f if f.starts_with("add") => self.exec_add(instruction.clone()), - f if f.contains(":") => { - } + f if f.contains(":") => {} invalid => panic!("Invalid instruction: {invalid}"), } self.set_pc(self.pc + 1); @@ -722,7 +759,10 @@ mod tests { assert!(status.success(), "Linker failed for {}", asm_path); // Run in qemu - let status = Command::new("qemu-arm").arg(&bin).status().expect("Failed to run qemu"); + let status = Command::new("qemu-arm") + .arg(&bin) + .status() + .expect("Failed to run qemu"); status.code().unwrap_or(-1) } @@ -741,7 +781,6 @@ mod tests { let file_path = path.to_str().unwrap(); - // Run qemu let qemu_exit = run_qemu(file_path); // Run interpreter @@ -749,7 +788,6 @@ mod tests { interp.read_file(&file_path.to_string()); let interp_exit = interp.execute(); - assert_eq!(qemu_exit as u32, interp_exit, "Mismatch for {}", file_path); } } @@ -845,7 +883,7 @@ mod tests { interp.file = vec![ "_start:".to_string(), " mov r0, #1".to_string(), - " svc #0".to_string() + " svc #0".to_string(), ]; let start_block = interp.get_start(); @@ -861,7 +899,7 @@ mod tests { "_start:".to_string(), " mov r0, #10".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string() + " svc #0".to_string(), ]; let exit_code = interp.execute(); @@ -880,7 +918,7 @@ mod tests { " ldr r1, [sp]".to_string(), " mov r0, r1".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string() + " svc #0".to_string(), ]; let exit_code = interp.execute(); @@ -903,8 +941,14 @@ mod tests { interp.set_reg(1, 50); interp.exec_cmp("cmp r1, #100".to_string()); assert!(!interp.cpsr.z, "Z should be false when not equal"); - assert!(interp.cpsr.n, "N should be true because 50 - 100 is negative"); - assert!(!interp.cpsr.c, "C should be false because 50 < 100 (borrow occurred)"); + assert!( + interp.cpsr.n, + "N should be true because 50 - 100 is negative" + ); + assert!( + !interp.cpsr.c, + "C should be false because 50 < 100 (borrow occurred)" + ); // 3. Test Greater Than (Positive result) interp.set_reg(1, 200); @@ -918,10 +962,13 @@ mod tests { // too big for 32-bit signed integer (wraps around) interp.set_reg(1, 0x7fffffff); // Max Positive i32 interp.set_reg(2, 0xffffffff); // -1 in two's complement - // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) + // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) interp.exec_cmp("cmp r1, r2".to_string()); assert!(interp.cpsr.v, "V should be true due to signed overflow"); - assert!(interp.cpsr.n, "N should be true because result wrapped to 0x80000000"); + assert!( + interp.cpsr.n, + "N should be true because result wrapped to 0x80000000" + ); } #[test] fn test_it_block_execution_logic() { @@ -950,7 +997,10 @@ mod tests { // Test Instruction 2 (E) let should_run_2 = interp.cpsr.should_execute(); - assert!(!should_run_2, "Instruction 2 (E) should NOT run when GT is true"); + assert!( + !should_run_2, + "Instruction 2 (E) should NOT run when GT is true" + ); assert_eq!(interp.cpsr.it_state.current_instr, 2); // 3. Reset and Scenario B: Condition is FALSE (R1 < R0) @@ -963,11 +1013,17 @@ mod tests { // Test Instruction 1 (T) let should_run_1_f = interp.cpsr.should_execute(); - assert!(!should_run_1_f, "Instruction 1 (T) should NOT run when GT is false"); + assert!( + !should_run_1_f, + "Instruction 1 (T) should NOT run when GT is false" + ); // Test Instruction 2 (E) let should_run_2_f = interp.cpsr.should_execute(); - assert!(should_run_2_f, "Instruction 2 (E) SHOULD run when GT is false (Else case)"); + assert!( + should_run_2_f, + "Instruction 2 (E) SHOULD run when GT is false (Else case)" + ); // Verify block auto-deactivates assert!( diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 08a433f..7fd79d6 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -1,4 +1,4 @@ -use std::env; +use std::{env, time}; use thumb2_interpreter::interpreter::Interpreter; fn main() { @@ -14,9 +14,11 @@ fn main() { } else { false }; + let file_path = &args[1]; let mut interpreter = Interpreter::default(); interpreter.set_debug(debug); + interpreter.set_max_time(std::time::Duration::from_micros(2).as_nanos()); interpreter.read_file(file_path); interpreter.print_memory(); let return_code = interpreter.execute(); From 241de55d4477047627e40e1fe0bebd2a070ec34b Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 6 Mar 2026 10:28:56 +0100 Subject: [PATCH 16/34] better argument handling --- interpreter/Cargo.lock | 177 ++++++++++++++++++++++++++++++++++++++++ interpreter/Cargo.toml | 5 +- interpreter/src/main.rs | 48 +++++++---- 3 files changed, 211 insertions(+), 19 deletions(-) diff --git a/interpreter/Cargo.lock b/interpreter/Cargo.lock index 7d4ed1d..2dd1dd9 100644 --- a/interpreter/Cargo.lock +++ b/interpreter/Cargo.lock @@ -2,12 +2,126 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -18,13 +132,76 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thumb2_interpreter" version = "0.1.0" dependencies = [ + "clap", "pretty_assertions", ] +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "yansi" version = "1.0.1" diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml index d27b37e..02732e6 100644 --- a/interpreter/Cargo.toml +++ b/interpreter/Cargo.toml @@ -3,7 +3,8 @@ name = "thumb2_interpreter" version = "0.1.0" edition = "2024" -[dependencies] - [dev-dependencies] pretty_assertions = "1.4" + +[dependencies] +clap = { version = "4.5.60", features = ["derive"] } diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 7fd79d6..a2e6c32 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -1,27 +1,41 @@ -use std::{env, time}; +use clap::Parser; use thumb2_interpreter::interpreter::Interpreter; -fn main() { - let args: Vec = env::args().collect(); +/// A Thumb2 interpreter +#[derive(Parser, Debug, Clone, PartialEq, Eq)] +#[command(version, about, long_about = None)] +struct Args { + /// The file path to read + file_path: String, - if args.len() < 2 { - eprintln!("Error: Please provide a Trivilang Thumb2 Source Code File"); - std::process::exit(1); - } + /// Enable debug output + #[arg(short, long)] + debug: bool, + + /// Stop execution after N nanoseconds + #[arg(long)] + max_time: Option, +} - let debug = if args.iter().any(|a| a == "--debug" || a == "-d") { - true - } else { - false - }; +fn main() { + // clap's Parser trait provides the parse() method. + // If the user passes invalid args or -h/--help, clap automatically + // prints the error/help message and exits the program safely. + let args = Args::parse(); - let file_path = &args[1]; let mut interpreter = Interpreter::default(); - interpreter.set_debug(debug); - interpreter.set_max_time(std::time::Duration::from_micros(2).as_nanos()); - interpreter.read_file(file_path); + + interpreter.set_debug(args.debug); + + if let Some(time) = args.max_time { + interpreter.set_max_time(time); + } + + interpreter.read_file(&args.file_path); interpreter.print_memory(); + let return_code = interpreter.execute(); + interpreter.print_memory(); - println!("Execution returned with return_code {return_code}") + println!("Execution returned with return_code {return_code}"); } From dc1446792ae7e0a9d55d839130a11a06385bf129 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Tue, 10 Mar 2026 14:52:00 +0100 Subject: [PATCH 17/34] main.asm --- interpreter/main.asm | 425 +++++++++++++++++++++++++++++++++++++++++-- main.asm | 425 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 826 insertions(+), 24 deletions(-) diff --git a/interpreter/main.asm b/interpreter/main.asm index e8ede92..7613098 100644 --- a/interpreter/main.asm +++ b/interpreter/main.asm @@ -9,46 +9,447 @@ _start: sub sp, sp, #4 mov r0, #0 str r0, [sp] + sub sp, sp, #4 + mov r0, #11413 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3533 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #113 + str r0, [sp] + sub sp, sp, #4 + mov r0, #59 + str r0, [sp] + sub sp, sp, #4 + mov r0, #97 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #-1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #23 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #76] + str r0, [sp, #44] + ldr r0, [sp, #88] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] while_0: - ldr r0, [sp, #0] + ldr r0, [sp, #4] mov r1, r0 - mov r0, #3 + ldr r0, [sp, #44] cmp r1, r0 mov r0, #0 it lt movlt r0, #1 cmp r0, #0 beq end_while_0 - sub sp, sp, #4 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] mov r0, #0 - str r0, [sp] + str r0, [sp, #16] while_1: - ldr r0, [sp, #0] + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_2: + ldr r0, [sp, #16] mov r1, r0 - mov r0, #2 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_2 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_2 +end_while_2: +while_3: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 cmp r1, r0 mov r0, #0 it lt movlt r0, #1 cmp r0, #0 - beq end_while_1 - ldr r0, [sp, #0] + beq end_while_3 + ldr r0, [sp, #16] mov r1, r0 - mov r0, #1 + ldr r0, [sp, #20] add r0, r1, r0 - str r0, [sp] + str r0, [sp, #16] + b while_3 +end_while_3: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp, #16] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] b while_1 end_while_1: + ldr r0, [sp, #16] + str r0, [sp, #36] ldr r0, [sp, #4] mov r1, r0 mov r0, #1 add r0, r1, r0 str r0, [sp, #4] - add sp, sp, #4 b while_0 end_while_0: - ldr r0, [sp, #0] + ldr r0, [sp, #36] + str r0, [sp, #60] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #72] + str r0, [sp, #44] + ldr r0, [sp, #84] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_5: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_5 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_6: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_6 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_7: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_7 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_7 +end_while_7: +while_8: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_8 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_8 +end_while_8: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_9 + mov r0, #0 + str r0, [sp, #16] + b endif_9 +else_9: +endif_9: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_6 +end_while_6: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_5 +end_while_5: + ldr r0, [sp, #36] + str r0, [sp, #56] + ldr r0, [sp, #60] + mov r1, r0 + ldr r0, [sp, #56] + sub r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #28] + ldr r0, [sp, #80] + str r0, [sp, #24] + ldr r0, [sp, #88] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_10: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_10 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_11: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_11 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_11 +end_while_11: +while_12: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_12 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_12 +end_while_12: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_13 + mov r0, #0 + str r0, [sp, #16] + b endif_13 +else_13: +endif_13: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_10 +end_while_10: + ldr r0, [sp, #16] + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #84] + mul r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #56] + add r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #68] + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #12 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_14 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_14 +print_int_loop_14: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_14 +print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] mov r7, #1 svc #0 .size _start, .-_start + +.section .data +.Lstr0: + .ascii "gang_sign = " +newline: + .ascii "\n" +num_buf: + .space 16 diff --git a/main.asm b/main.asm index e8ede92..7613098 100644 --- a/main.asm +++ b/main.asm @@ -9,46 +9,447 @@ _start: sub sp, sp, #4 mov r0, #0 str r0, [sp] + sub sp, sp, #4 + mov r0, #11413 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3533 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #113 + str r0, [sp] + sub sp, sp, #4 + mov r0, #59 + str r0, [sp] + sub sp, sp, #4 + mov r0, #97 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #-1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #23 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #76] + str r0, [sp, #44] + ldr r0, [sp, #88] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] while_0: - ldr r0, [sp, #0] + ldr r0, [sp, #4] mov r1, r0 - mov r0, #3 + ldr r0, [sp, #44] cmp r1, r0 mov r0, #0 it lt movlt r0, #1 cmp r0, #0 beq end_while_0 - sub sp, sp, #4 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] mov r0, #0 - str r0, [sp] + str r0, [sp, #16] while_1: - ldr r0, [sp, #0] + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_2: + ldr r0, [sp, #16] mov r1, r0 - mov r0, #2 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_2 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_2 +end_while_2: +while_3: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 cmp r1, r0 mov r0, #0 it lt movlt r0, #1 cmp r0, #0 - beq end_while_1 - ldr r0, [sp, #0] + beq end_while_3 + ldr r0, [sp, #16] mov r1, r0 - mov r0, #1 + ldr r0, [sp, #20] add r0, r1, r0 - str r0, [sp] + str r0, [sp, #16] + b while_3 +end_while_3: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp, #16] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] b while_1 end_while_1: + ldr r0, [sp, #16] + str r0, [sp, #36] ldr r0, [sp, #4] mov r1, r0 mov r0, #1 add r0, r1, r0 str r0, [sp, #4] - add sp, sp, #4 b while_0 end_while_0: - ldr r0, [sp, #0] + ldr r0, [sp, #36] + str r0, [sp, #60] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #72] + str r0, [sp, #44] + ldr r0, [sp, #84] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_5: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_5 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_6: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_6 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_7: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_7 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_7 +end_while_7: +while_8: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_8 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_8 +end_while_8: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_9 + mov r0, #0 + str r0, [sp, #16] + b endif_9 +else_9: +endif_9: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_6 +end_while_6: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_5 +end_while_5: + ldr r0, [sp, #36] + str r0, [sp, #56] + ldr r0, [sp, #60] + mov r1, r0 + ldr r0, [sp, #56] + sub r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #28] + ldr r0, [sp, #80] + str r0, [sp, #24] + ldr r0, [sp, #88] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_10: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_10 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_11: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_11 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_11 +end_while_11: +while_12: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_12 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_12 +end_while_12: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_13 + mov r0, #0 + str r0, [sp, #16] + b endif_13 +else_13: +endif_13: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_10 +end_while_10: + ldr r0, [sp, #16] + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #84] + mul r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #56] + add r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #68] + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #12 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_14 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_14 +print_int_loop_14: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_14 +print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] mov r7, #1 svc #0 .size _start, .-_start + +.section .data +.Lstr0: + .ascii "gang_sign = " +newline: + .ascii "\n" +num_buf: + .space 16 From 054702afefd07cebb99077dd069b75b7296f2773 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 08:51:55 +0100 Subject: [PATCH 18/34] added default value for compiler output --- fissc/crt-rsa.trv | 2 -- src/main.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fissc/crt-rsa.trv b/fissc/crt-rsa.trv index 0073216..fd74984 100644 --- a/fissc/crt-rsa.trv +++ b/fissc/crt-rsa.trv @@ -113,7 +113,5 @@ func main() -> Integer { g_sign = tmp; - print("gang_sign = ", g_sign); - return g_sign; } diff --git a/src/main.rs b/src/main.rs index ee14323..432415c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ struct Args { /// The source file to compile filename: String, - #[arg(short, long)] + #[arg(short, long, default_value = "out.asm")] output: String, #[arg(long)] From f2d372bf02009430e04032ac24c2ec7dbb3be764 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 09:17:02 +0100 Subject: [PATCH 19/34] crt-rsa works? now we just need prints maybe? --- .gitignore | 1 - interpreter/out.asm | 406 +++++++++++++++++++ interpreter/src/interpreter.rs | 84 ++-- interpreter/src/lib.rs | 4 +- interpreter/test_files/test_ittete_false.asm | 10 +- interpreter/test_files/test_ittete_true.asm | 4 +- out.asm | 406 +++++++++++++++++++ 7 files changed, 877 insertions(+), 38 deletions(-) create mode 100644 interpreter/out.asm create mode 100644 out.asm diff --git a/.gitignore b/.gitignore index 52ad222..c3cf292 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ /interpreter/tmp /playground -*.asm *.core **/tmp **/temp diff --git a/interpreter/out.asm b/interpreter/out.asm new file mode 100644 index 0000000..825bed9 --- /dev/null +++ b/interpreter/out.asm @@ -0,0 +1,406 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #11413 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3533 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #113 + str r0, [sp] + sub sp, sp, #4 + mov r0, #59 + str r0, [sp] + sub sp, sp, #4 + mov r0, #97 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #-1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #23 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #76] + str r0, [sp, #44] + ldr r0, [sp, #88] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_1: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_2: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_2 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_2 +end_while_2: +while_3: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_3 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_3 +end_while_3: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp, #16] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_1 +end_while_1: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: + ldr r0, [sp, #36] + str r0, [sp, #60] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #72] + str r0, [sp, #44] + ldr r0, [sp, #84] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_5: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_5 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_6: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_6 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_7: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_7 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_7 +end_while_7: +while_8: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_8 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_8 +end_while_8: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_9 + mov r0, #0 + str r0, [sp, #16] + b endif_9 +else_9: +endif_9: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_6 +end_while_6: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_5 +end_while_5: + ldr r0, [sp, #36] + str r0, [sp, #56] + ldr r0, [sp, #60] + mov r1, r0 + ldr r0, [sp, #56] + sub r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #28] + ldr r0, [sp, #80] + str r0, [sp, #24] + ldr r0, [sp, #88] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_10: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_10 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_11: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_11 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_11 +end_while_11: +while_12: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_12 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_12 +end_while_12: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_13 + mov r0, #0 + str r0, [sp, #16] + b endif_13 +else_13: +endif_13: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_10 +end_while_10: + ldr r0, [sp, #16] + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #84] + mul r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #56] + add r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #68] + ldr r0, [sp, #68] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index a1bad87..858a29f 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -72,7 +72,7 @@ impl Cpsr { pub struct Interpreter { memory: EmulatorMemory, - registers: [u32; NUM_REGISTERS], + registers: [i32; NUM_REGISTERS], pc: u32, branch_map: HashMap, eof_pc: u32, @@ -95,7 +95,7 @@ impl Interpreter { file: Vec::new(), debug: false, start_time: std::time::Instant::now(), - max_time: std::time::Duration::from_millis(10), + max_time: std::time::Duration::from_millis(500), } } @@ -111,11 +111,11 @@ impl Interpreter { self.branch_map = map; } - pub fn get_reg(&self, index: usize) -> u32 { + pub fn get_reg(&self, index: usize) -> i32 { self.registers[index] } - pub fn set_reg(&mut self, index: usize, value: u32) { + pub fn set_reg(&mut self, index: usize, value: i32) { self.registers[index] = value; } @@ -148,7 +148,7 @@ impl Interpreter { } } - pub fn get_registers(&self) -> &[u32; NUM_REGISTERS] { + pub fn get_registers(&self) -> &[i32; NUM_REGISTERS] { &self.registers } @@ -357,17 +357,16 @@ impl Interpreter { let src = parts[2].replace(",", ""); let dest_idx: usize = dest[1..].parse().expect("Failed to parse register index"); - let value: u32; if let Some(value_str) = src.strip_prefix('#') { - value = value_str.parse().expect("Failed to parse immediate value"); + let value: i32 = value_str.parse().expect("Failed to parse immediate value"); self.set_reg(dest_idx, value); if self.debug { println!("Mock: mov r{}, #{} (stored in register)", dest_idx, value); } } else { let src_idx: usize = src[1..].parse().expect("Failed to parse register index"); - value = self.get_reg(src_idx); + let value = self.get_reg(src_idx); self.set_reg(dest_idx, value); if self.debug { println!( @@ -378,7 +377,7 @@ impl Interpreter { } } - fn exec_svc(&mut self, content: String) -> Option { + fn exec_svc(&mut self, content: String) -> Option { if self.debug { println!("Executing svc instruction: {}", content); } @@ -405,7 +404,7 @@ impl Interpreter { let dest = parts[1].replace(",", ""); let src = parts[2].replace(",", ""); let val_or_reg = parts[3].replace(",", ""); - let sub_value: u32; + let sub_value: i32; if let Some(value_str) = val_or_reg.strip_prefix('#') { let value_str = value_str.replace("#", ""); sub_value = value_str.parse().expect("literal"); @@ -415,7 +414,7 @@ impl Interpreter { sub_value = self.get_reg(this_reg); } - let src_val: u32; + let src_val: i32; if let Some(src_str) = src.strip_prefix('r') { let src_register = src_str .replace("r", "") @@ -423,7 +422,7 @@ impl Interpreter { .expect("Unable to parse register"); src_val = self.get_reg(src_register); } else { - src_val = self.memory.get_sp() as u32; + src_val = self.memory.get_sp() as i32; } if let Some(dst_str) = dest.strip_prefix('r') { @@ -431,7 +430,8 @@ impl Interpreter { .replace("r", "") .parse() .expect("Unable to parse register"); - let _dst_val = self.get_reg(dst_register); + let result = src_val - sub_value; + self.set_reg(dst_register, result); } else if src == "sp" { self.memory.set_sp((src_val - sub_value) as usize); } @@ -475,7 +475,7 @@ impl Interpreter { } let offset_from_sp = ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; - self.memory.write_stack32(offset_from_sp, value); + self.memory.write_stack32(offset_from_sp, value as u32); if self.debug { println!("Stored value {} at stack offset {}", value, offset_from_sp); @@ -550,7 +550,7 @@ impl Interpreter { // 7. Load the value from memory and update the register let value = self.memory.read_stack32(effective_offset); - self.set_reg(dest_idx, value); + self.set_reg(dest_idx, value as i32); if self.debug { println!( @@ -574,11 +574,11 @@ impl Interpreter { return; } - let rn_idx: usize = parts[1][1..].parse().expect("Failed to parse Rn index"); + let rn_idx: usize = parts[1][1..].parse().expect("Failed to Rn index"); let val_n = self.get_reg(rn_idx); let val_op2 = if let Some(imm_str) = parts[2].strip_prefix('#') { - imm_str.parse::().expect("Failed to parse immediate") + imm_str.parse::().expect("Failed to parse immediate") } else { let rm_idx: usize = parts[2][1..].parse().expect("Failed to parse Rm index"); self.get_reg(rm_idx) @@ -586,12 +586,10 @@ impl Interpreter { let result = (val_n).wrapping_sub(val_op2); self.cpsr.z = result == 0; - self.cpsr.n = (result >> 31) == 1; - self.cpsr.c = val_n >= val_op2; + self.cpsr.n = result < 0; + self.cpsr.c = (val_n as u32) >= (val_op2 as u32); - let rn_i = val_n as i32; - let op2_i = val_op2 as i32; - let (_, overflow) = rn_i.overflowing_sub(op2_i); + let (_, overflow) = val_n.overflowing_sub(val_op2); self.cpsr.v = overflow; if self.debug { @@ -650,15 +648,15 @@ impl Interpreter { dest[1..].parse().unwrap() }; - let src_val: u32 = if op1 == "sp" { - self.memory.get_sp() as u32 + let src_val: i32 = if op1 == "sp" { + self.memory.get_sp() as i32 } else { let src_idx: usize = op1[1..].parse().unwrap(); self.get_reg(src_idx) }; let value = if let Some(imm) = op2.strip_prefix('#') { - imm.parse::().unwrap() + imm.parse::().unwrap() } else { let reg_idx: usize = if op2 == "sp" { 13 @@ -677,10 +675,39 @@ impl Interpreter { } } + fn exec_mul(&mut self, content: String) { + let parts: Vec<&str> = content.split_whitespace().collect(); + + let dest = parts[1].replace(",", ""); + let op1 = parts[2].replace(",", ""); + let op2 = parts[3].replace(",", ""); + + let dest_idx: usize = dest[1..].parse().unwrap(); + + let src_val: i32 = { + let src_idx: usize = op1[1..].parse().unwrap(); + self.get_reg(src_idx) + }; + + let value: i32 = { + let reg_idx: usize = op2[1..].parse().unwrap(); + self.get_reg(reg_idx) + }; + + let result = src_val.wrapping_mul(value); + self.set_reg(dest_idx, result); + } + pub fn execute(&mut self) -> u32 { let start_block = self.get_start(); + if self.debug { + eprintln!("DEBUG: start_block = {:?}", start_block); + } while self.pc < self.eof_pc { let instruction = start_block.get(self.pc as usize).unwrap(); + if self.debug { + eprintln!("DEBUG: PC={}, instruction={}", self.pc, instruction); + } if self.start_time.elapsed().as_nanos() > self.max_time.as_nanos() { println!("Detected Infinite Loop"); exit(88) @@ -696,7 +723,7 @@ impl Interpreter { f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { if let Some(exit_code) = self.exec_svc(instruction.clone()) { - return exit_code; + return (exit_code as u32) & 0xFF; } } f if f.starts_with("sub") => self.exec_sub(instruction.clone()), @@ -709,6 +736,7 @@ impl Interpreter { continue; } f if f.starts_with("add") => self.exec_add(instruction.clone()), + f if f.starts_with("mul") => self.exec_mul(instruction.clone()), f if f.contains(":") => {} invalid => panic!("Invalid instruction: {invalid}"), } @@ -961,8 +989,8 @@ mod tests { // Large positive minus a large negative results in a value // too big for 32-bit signed integer (wraps around) interp.set_reg(1, 0x7fffffff); // Max Positive i32 - interp.set_reg(2, 0xffffffff); // -1 in two's complement - // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) + interp.set_reg(2, -1); // -1 in two's complement + // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) interp.exec_cmp("cmp r1, r2".to_string()); assert!(interp.cpsr.v, "V should be true due to signed overflow"); assert!( diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index daaef51..5ae9f96 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -68,7 +68,7 @@ mod tests { let mut interp = Interpreter::new(); interp.read_file(&get_test_file_path("test_ittete_true.asm").to_string_lossy().to_string()); let exit_code = interp.execute(); - assert_eq!(exit_code, 1011, "ITTETE True: Only T instructions should sum"); + assert_eq!(exit_code, 211, "ITTETE True: Only T instructions should sum"); } #[test] @@ -76,6 +76,6 @@ mod tests { let mut interp = Interpreter::new(); interp.read_file(&get_test_file_path("test_ittete_false.asm").to_string_lossy().to_string()); let exit_code = interp.execute(); - assert_eq!(exit_code, 10100, "ITTETE False: Only E instructions should sum"); + assert_eq!(exit_code, 103, "ITTETE False: Only E instructions should sum"); } } diff --git a/interpreter/test_files/test_ittete_false.asm b/interpreter/test_files/test_ittete_false.asm index 75f3fa9..1c4525f 100644 --- a/interpreter/test_files/test_ittete_false.asm +++ b/interpreter/test_files/test_ittete_false.asm @@ -10,11 +10,11 @@ _start: cmp r1, #10 @ GT is False mov r0, #0 ittete gt - addgt r0, r0, #1 @ T: Skip - addgt r0, r0, #10 @ T: Skip - addle r0, r0, #100 @ E: Run (+100) - addgt r0, r0, #1000 @ T: Skip - addle r0, r0, #10000 @ E: Run (+10000) + addgt r0, r0, #1 @ T: Run (+1) + addgt r0, r0, #10 @ T: Run (+10) + addle r0, r0, #100 @ E: Skip + addgt r0, r0, #200 @ T: Run (+1000) + addle r0, r0, #3 @ E: Skip mov r7, #1 svc #0 diff --git a/interpreter/test_files/test_ittete_true.asm b/interpreter/test_files/test_ittete_true.asm index e3ba38e..2b783cb 100644 --- a/interpreter/test_files/test_ittete_true.asm +++ b/interpreter/test_files/test_ittete_true.asm @@ -13,8 +13,8 @@ _start: addgt r0, r0, #1 @ T: Run (+1) addgt r0, r0, #10 @ T: Run (+10) addle r0, r0, #100 @ E: Skip - addgt r0, r0, #1000 @ T: Run (+1000) - addle r0, r0, #10000 @ E: Skip + addgt r0, r0, #200 @ T: Run (+1000) + addle r0, r0, #3 @ E: Skip mov r7, #1 svc #0 diff --git a/out.asm b/out.asm new file mode 100644 index 0000000..825bed9 --- /dev/null +++ b/out.asm @@ -0,0 +1,406 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #11413 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3533 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #113 + str r0, [sp] + sub sp, sp, #4 + mov r0, #59 + str r0, [sp] + sub sp, sp, #4 + mov r0, #97 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #-1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #23 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #76] + str r0, [sp, #44] + ldr r0, [sp, #88] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_1: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_2: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_2 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_2 +end_while_2: +while_3: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_3 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_3 +end_while_3: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp, #16] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_1 +end_while_1: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: + ldr r0, [sp, #36] + str r0, [sp, #60] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #72] + str r0, [sp, #44] + ldr r0, [sp, #84] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_5: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_5 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_6: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_6 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_7: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_7 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_7 +end_while_7: +while_8: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_8 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_8 +end_while_8: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_9 + mov r0, #0 + str r0, [sp, #16] + b endif_9 +else_9: +endif_9: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_6 +end_while_6: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_5 +end_while_5: + ldr r0, [sp, #36] + str r0, [sp, #56] + ldr r0, [sp, #60] + mov r1, r0 + ldr r0, [sp, #56] + sub r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #28] + ldr r0, [sp, #80] + str r0, [sp, #24] + ldr r0, [sp, #88] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_10: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_10 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_11: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_11 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_11 +end_while_11: +while_12: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_12 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_12 +end_while_12: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_13 + mov r0, #0 + str r0, [sp, #16] + b endif_13 +else_13: +endif_13: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_10 +end_while_10: + ldr r0, [sp, #16] + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #84] + mul r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #56] + add r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #68] + ldr r0, [sp, #68] + mov r7, #1 + svc #0 + +.size _start, .-_start From 4670c4ae8a0706ebaa5b50c07828e86a95fc8589 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 09:52:32 +0100 Subject: [PATCH 20/34] prints work, yippiiiiiie! Time for fault injection and code hardening! --- fissc/crt-rsa.trv | 2 + interpreter/out.asm | 49 +++++++ interpreter/run | 45 ++++++- interpreter/src/interpreter.rs | 236 +++++++++++++++++++++++++++++++-- interpreter/src/memory.rs | 65 ++++++++- out.asm | 49 +++++++ 6 files changed, 431 insertions(+), 15 deletions(-) diff --git a/fissc/crt-rsa.trv b/fissc/crt-rsa.trv index fd74984..abfc117 100644 --- a/fissc/crt-rsa.trv +++ b/fissc/crt-rsa.trv @@ -113,5 +113,7 @@ func main() -> Integer { g_sign = tmp; + print("g_sign herro = ", 1337); + return g_sign; } diff --git a/interpreter/out.asm b/interpreter/out.asm index 825bed9..36235d3 100644 --- a/interpreter/out.asm +++ b/interpreter/out.asm @@ -399,8 +399,57 @@ end_while_10: str r0, [sp, #52] ldr r0, [sp, #52] str r0, [sp, #68] + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #15 + mov r7, #4 + svc #0 + mov r0, #1337 + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_14 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_14 +print_int_loop_14: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_14 +print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 ldr r0, [sp, #68] mov r7, #1 svc #0 .size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_sign herro = " +newline: + .ascii "\n" +num_buf: + .space 16 diff --git a/interpreter/run b/interpreter/run index ca0dd81..36857f5 100755 --- a/interpreter/run +++ b/interpreter/run @@ -1,8 +1,49 @@ #!/bin/bash +set -euo pipefail + +# Always run from the interpreter crate directory, even if invoked from repo root. +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +rewrite_path_arg() { + local a="$1" + # If called from repo root like: ./interpreter/run interpreter/out.asm + if [[ "$a" == interpreter/* ]]; then + local stripped="${a#interpreter/}" + if [[ -f "$stripped" ]]; then + printf '%s' "$stripped" + return 0 + fi + fi + # If passed an absolute/relative path that doesn't exist from here, + # but the basename does (e.g., repo-root paths), fall back to basename. + if [[ ! -f "$a" ]]; then + local base + base="$(basename -- "$a")" + if [[ -f "$base" ]]; then + printf '%s' "$base" + return 0 + fi + fi + printf '%s' "$a" +} + if [ "$1" = "--debug" ]; then shift - cargo run -- "$@" + if [[ $# -ge 1 ]]; then + first="$(rewrite_path_arg "$1")" + shift + cargo run -- "$first" "$@" + else + cargo run -- + fi else - RUSTFLAGS="-A warnings" cargo run --release -- "$@" + if [[ $# -ge 1 ]]; then + first="$(rewrite_path_arg "$1")" + shift + RUSTFLAGS="-A warnings" cargo run --release -- "$first" "$@" + else + RUSTFLAGS="-A warnings" cargo run --release -- + fi fi diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 858a29f..c4a4534 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -75,6 +75,7 @@ pub struct Interpreter { registers: [i32; NUM_REGISTERS], pc: u32, branch_map: HashMap, + data_map: HashMap, eof_pc: u32, cpsr: Cpsr, file: Vec, @@ -90,6 +91,7 @@ impl Interpreter { registers: [0; NUM_REGISTERS], pc: 0, branch_map: HashMap::new(), + data_map: HashMap::new(), eof_pc: 0, cpsr: Cpsr::default(), file: Vec::new(), @@ -328,6 +330,9 @@ impl Interpreter { if found_start { if line.starts_with(".size _start") { result.pop(); + break; + } else if line.starts_with(".section .data") || line.starts_with(".data") { + break; } else { let label = line.trim_start().to_string(); result.push(line.trim_start().to_string()); @@ -348,6 +353,76 @@ impl Interpreter { result } + fn parse_data_section(&mut self) { + let mut in_data_section = false; + let mut current_addr = 0; + let mut last_label: Option = None; + + for line in &self.file { + let line = line.trim(); + + if line.starts_with(".section .data") || line == ".data" { + in_data_section = true; + continue; + } + + if line.starts_with(".text") || line.starts_with(".section .text") { + in_data_section = false; + continue; + } + + if in_data_section { + if line.contains(":") { + let label = line.trim_end_matches(':').to_string(); + self.data_map.insert(label.clone(), current_addr); + last_label = Some(label); + } else if line.contains(".ascii") { + if let Some(_) = line.find("\"") { + let start = line.find("\"").unwrap() + 1; + let end = start + line[start..].find("\"").unwrap(); + let string_data = &line[start..end]; + + // The assembler interprets escapes inside ".ascii" strings (e.g., "\n"). + // We store the resulting bytes into the emulated data/heap region. + let mut chars = string_data.chars().peekable(); + while let Some(ch) = chars.next() { + if ch == '\\' { + let esc = chars.next().unwrap_or('\\'); + let byte = match esc { + 'n' => b'\n', + 'r' => b'\r', + 't' => b'\t', + '0' => b'\0', + '\\' => b'\\', + '"' => b'"', + // Unknown escape: keep as-is (backslash + char) + other => { + self.memory.heap[current_addr] = b'\\'; + current_addr += 1; + other as u8 + } + }; + self.memory.heap[current_addr] = byte; + current_addr += 1; + } else { + self.memory.heap[current_addr] = ch as u8; + current_addr += 1; + } + } + } + } else if line.contains(".space") { + if let Some(size_str) = line.split(".space").nth(1) { + let size: usize = size_str.trim().parse().unwrap_or(0); + for _ in 0..size { + self.memory.heap[current_addr] = 0; + current_addr += 1; + } + } + } + } + } + } + fn exec_mov(&mut self, content: String) { if self.debug { println!("Executing mov instruction: {}", content); @@ -393,6 +468,17 @@ impl Interpreter { println!("Exit syscall (r7=1), returning exit code: {}", exit_code); } return Some(exit_code); + } else if syscall_num == 4 { + let fd = self.get_reg(0); + let addr = self.get_reg(1) as usize; + let len = self.get_reg(2) as usize; + + if fd == 1 { + let data = self.memory.read_heap(addr, len); + print!("{}", String::from_utf8_lossy(&data)); + use std::io::Write; + std::io::stdout().flush().ok(); + } } } } @@ -474,11 +560,11 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - let offset_from_sp = ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; - self.memory.write_stack32(offset_from_sp, value as u32); + let effective_addr = (base_addr as i32 + offset) as usize; + self.memory.write_stack32_at(effective_addr, value as u32); if self.debug { - println!("Stored value {} at stack offset {}", value, offset_from_sp); + println!("Stored value {} at address {}", value, effective_addr); let stack_data = self.memory.get_stack(); let sp = self.memory.get_sp(); println!( @@ -503,6 +589,60 @@ impl Interpreter { println!("Executing ldr instruction: {}", content); } + // Handle "ldr rN, =label" form (load address of label) + if content.contains("=.") || content.contains("=num_buf") || content.contains("=newline") { + let parts: Vec<&str> = content.split_whitespace().collect(); + let dest_reg = parts[1].replace(",", ""); + let dest_idx: usize = dest_reg[1..] + .parse() + .expect("Failed to parse destination register index"); + + // Try to find the label + let mut label_found = false; + + if let Some(label_start) = content.find("=.") { + let label = &content[label_start + 1..]; + let label = label.trim().trim_end_matches('\n'); + if let Some(&addr) = self.data_map.get(label) { + self.set_reg(dest_idx, addr as i32); + label_found = true; + if self.debug { + println!( + "Loaded label address {} for {} into r{}", + addr, label, dest_idx + ); + } + } + } + + if !label_found && content.contains("=num_buf") { + if let Some(&addr) = self.data_map.get("num_buf") { + self.set_reg(dest_idx, addr as i32); + label_found = true; + if self.debug { + println!( + "Loaded label address {} for num_buf into r{}", + addr, dest_idx + ); + } + } + } + + if !label_found && content.contains("=newline") { + if let Some(&addr) = self.data_map.get("newline") { + self.set_reg(dest_idx, addr as i32); + if self.debug { + println!( + "Loaded label address {} for newline into r{}", + addr, dest_idx + ); + } + } + } + + return; + } + // 1. Parse the parts (e.g., "ldr", "r0,", "[sp, #0]") let parts: Vec<&str> = content.split_whitespace().collect(); @@ -544,18 +684,17 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - // 6. Calculate the effective offset relative to the current SP - let effective_offset = - ((base_addr as i32) - (self.memory.get_sp() as i32) + offset) as usize; + // 6. Calculate the effective address + let effective_addr = (base_addr as i32 + offset) as usize; // 7. Load the value from memory and update the register - let value = self.memory.read_stack32(effective_offset); + let value = self.memory.read_stack32_at(effective_addr); self.set_reg(dest_idx, value as i32); if self.debug { println!( - "Loaded value {} from stack offset {} into r{}", - value, effective_offset, dest_idx + "Loaded value {} from address {} into r{}", + value, effective_addr, dest_idx ); } } @@ -636,6 +775,9 @@ impl Interpreter { } fn exec_add(&mut self, content: String) { + if self.debug { + println!("Executing add instruction: {}", content); + } let parts: Vec<&str> = content.split_whitespace().collect(); let dest = parts[1].replace(",", ""); @@ -698,7 +840,80 @@ impl Interpreter { self.set_reg(dest_idx, result); } + fn exec_sdiv(&mut self, content: String) { + if self.debug { + println!("Executing sdiv instruction: {}", content); + } + let parts: Vec<&str> = content.split_whitespace().collect(); + + let dest = parts[1].replace(",", ""); + let op1 = parts[2].replace(",", ""); + let op2 = parts[3].replace(",", ""); + + let dest_idx: usize = dest[1..].parse().unwrap(); + + let src_val: i32 = { + let src_idx: usize = op1[1..].parse().unwrap(); + self.get_reg(src_idx) + }; + + let value: i32 = { + let reg_idx: usize = op2[1..].parse().unwrap(); + self.get_reg(reg_idx) + }; + + let result = src_val / value; + self.set_reg(dest_idx, result); + } + + fn exec_strb(&mut self, content: String) { + if self.debug { + println!("Executing strb instruction: {}", content); + } + let parts: Vec<&str> = content.split_whitespace().collect(); + let src_reg = parts[1].replace(",", ""); + let src_idx: usize = src_reg[1..] + .parse() + .expect("Failed to parse register index"); + let value = self.get_reg(src_idx) as u8; + + let addr_part = content + .split_once('[') + .and_then(|(_, rest)| rest.split_once(']')) + .map(|(inside, _)| inside) + .unwrap_or(""); + + let mut base_addr: usize = 0; + let mut offset: i32 = 0; + let mut base_reg_name = String::new(); + + for part in addr_part.split(',') { + let part = part.trim(); + if part == "sp" || part.starts_with('r') { + base_reg_name = part.to_string(); + } else if let Some(imm) = part.strip_prefix('#') { + offset = imm.parse().expect("Failed to parse offset"); + } + } + + if base_reg_name == "sp" { + base_addr = self.memory.get_sp(); + } else if let Some(reg_num) = base_reg_name.strip_prefix('r') { + let reg_idx: usize = reg_num.parse().expect("Failed to parse register index"); + base_addr = self.get_reg(reg_idx) as usize; + } + + let effective_addr = (base_addr as i32 + offset) as usize; + + if effective_addr < self.memory.heap.len() { + self.memory.heap[effective_addr] = value; + } else if effective_addr < self.memory.stack.len() { + self.memory.stack[effective_addr] = value; + } + } + pub fn execute(&mut self) -> u32 { + self.parse_data_section(); let start_block = self.get_start(); if self.debug { eprintln!("DEBUG: start_block = {:?}", start_block); @@ -727,6 +942,8 @@ impl Interpreter { } } f if f.starts_with("sub") => self.exec_sub(instruction.clone()), + // Important: check "strb" before "str" since "strb".starts_with("str") is true. + f if f.starts_with("strb") => self.exec_strb(instruction.clone()), f if f.starts_with("str") => self.exec_str(instruction.clone()), f if f.starts_with("ldr") => self.exec_ldr(instruction.clone()), f if f.starts_with("cmp") => self.exec_cmp(instruction.clone()), @@ -737,6 +954,7 @@ impl Interpreter { } f if f.starts_with("add") => self.exec_add(instruction.clone()), f if f.starts_with("mul") => self.exec_mul(instruction.clone()), + f if f.starts_with("sdiv") => self.exec_sdiv(instruction.clone()), f if f.contains(":") => {} invalid => panic!("Invalid instruction: {invalid}"), } diff --git a/interpreter/src/memory.rs b/interpreter/src/memory.rs index 5750bea..51bf7c5 100644 --- a/interpreter/src/memory.rs +++ b/interpreter/src/memory.rs @@ -2,8 +2,8 @@ const STACK_SIZE: usize = 1024 * 1024; const HEAP_SIZE: usize = 1024 * 1024; pub struct EmulatorMemory { - stack: Vec, - heap: Vec, + pub stack: Vec, + pub heap: Vec, heap_alloc_index: usize, stack_pointer: usize, } @@ -69,13 +69,70 @@ impl EmulatorMemory { self.heap[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); } + pub fn write_heap(&mut self, addr: usize, value: u8) { + self.heap[addr] = value; + } + + pub fn read_heap(&self, addr: usize, len: usize) -> Vec { + self.heap[addr..addr + len].to_vec() + } + pub fn write_stack32(&mut self, offset: usize, value: u32) { - let addr = self.stack_pointer + offset; + let (addr, overflow) = self.stack_pointer.overflowing_add(offset); + if overflow || addr + 4 > self.stack.len() { + eprintln!( + "Warning: Stack write out of bounds at offset {} (sp={}, addr={}, stack_len={})", + offset, + self.stack_pointer, + addr, + self.stack.len() + ); + return; + } self.stack[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); } + pub fn write_stack32_at(&mut self, addr: usize, value: u32) { + if addr + 4 > self.stack.len() { + eprintln!( + "Warning: Stack write out of bounds at addr {} (stack_len={})", + addr, + self.stack.len() + ); + return; + } + self.stack[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); + } + + pub fn read_stack32_at(&self, addr: usize) -> u32 { + if addr + 4 > self.stack.len() { + eprintln!( + "Warning: Stack read out of bounds at addr {} (stack_len={})", + addr, + self.stack.len() + ); + return 0; + } + u32::from_le_bytes([ + self.stack[addr], + self.stack[addr + 1], + self.stack[addr + 2], + self.stack[addr + 3], + ]) + } + pub fn read_stack32(&self, offset: usize) -> u32 { - let addr = self.stack_pointer + offset; + let (addr, overflow) = self.stack_pointer.overflowing_add(offset); + if overflow || addr + 4 > self.stack.len() { + eprintln!( + "Warning: Stack read out of bounds at offset {} (sp={}, addr={}, stack_len={})", + offset, + self.stack_pointer, + addr, + self.stack.len() + ); + return 0; + } if addr + 4 > self.stack.len() { panic!("Stack out of bounds read at offset {}", offset); diff --git a/out.asm b/out.asm index 825bed9..36235d3 100644 --- a/out.asm +++ b/out.asm @@ -399,8 +399,57 @@ end_while_10: str r0, [sp, #52] ldr r0, [sp, #52] str r0, [sp, #68] + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #15 + mov r7, #4 + svc #0 + mov r0, #1337 + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_14 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_14 +print_int_loop_14: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_14 +print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 ldr r0, [sp, #68] mov r7, #1 svc #0 .size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_sign herro = " +newline: + .ascii "\n" +num_buf: + .space 16 From c788b1ad2ff0705e904cfd06a6d790926cfd3cc4 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 10:18:00 +0100 Subject: [PATCH 21/34] more than one print --- fissc/crt-rsa.trv | 1 + interpreter/out.asm | 43 ++++++++++++++++++++++++++++++++++ interpreter/src/interpreter.rs | 5 +++- out.asm | 43 ++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) diff --git a/fissc/crt-rsa.trv b/fissc/crt-rsa.trv index abfc117..d44292c 100644 --- a/fissc/crt-rsa.trv +++ b/fissc/crt-rsa.trv @@ -114,6 +114,7 @@ func main() -> Integer { g_sign = tmp; print("g_sign herro = ", 1337); + print("g_countermeasure: ", g_countermeasure); return g_sign; } diff --git a/interpreter/out.asm b/interpreter/out.asm index 36235d3..f05f88c 100644 --- a/interpreter/out.asm +++ b/interpreter/out.asm @@ -430,6 +430,47 @@ print_int_loop_14: cmp r4, #0 bne print_int_loop_14 print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #18 + mov r7, #4 + svc #0 + ldr r0, [sp, #100] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_15 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_15 +print_int_loop_15: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_15 +print_int_done_15: mov r0, #1 mov r1, r1 mov r2, r2 @@ -449,6 +490,8 @@ print_int_done_14: .section .data .Lstr0: .ascii "g_sign herro = " +.Lstr1: + .ascii "g_countermeasure: " newline: .ascii "\n" num_buf: diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index c4a4534..0d6b3a0 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -372,7 +372,10 @@ impl Interpreter { } if in_data_section { - if line.contains(":") { + // A label definition line is of the form `label:` (colon at end). + // Don't treat directives like `.ascii "a:b"` as a label just because + // the string literal contains ':'. + if line.ends_with(':') { let label = line.trim_end_matches(':').to_string(); self.data_map.insert(label.clone(), current_addr); last_label = Some(label); diff --git a/out.asm b/out.asm index 36235d3..f05f88c 100644 --- a/out.asm +++ b/out.asm @@ -430,6 +430,47 @@ print_int_loop_14: cmp r4, #0 bne print_int_loop_14 print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #18 + mov r7, #4 + svc #0 + ldr r0, [sp, #100] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_15 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_15 +print_int_loop_15: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_15 +print_int_done_15: mov r0, #1 mov r1, r1 mov r2, r2 @@ -449,6 +490,8 @@ print_int_done_14: .section .data .Lstr0: .ascii "g_sign herro = " +.Lstr1: + .ascii "g_countermeasure: " newline: .ascii "\n" num_buf: From b783dae3e3e93ab39063dac38e304fbdcc5a085c Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 13:58:37 +0100 Subject: [PATCH 22/34] restructuring --- Cargo.lock => compiler/Cargo.lock | 0 Cargo.toml => compiler/Cargo.toml | 0 README.md => compiler/README.md | 0 {fissc => compiler/fissc}/Basic/.Makefile.swp | Bin {fissc => compiler/fissc}/Basic/Makefile | 0 {fissc => compiler/fissc}/Basic/bin/crt-rsa | Bin {fissc => compiler/fissc}/Basic/include/commons.h | 0 .../fissc}/Basic/src/countermeasure.c | 0 {fissc => compiler/fissc}/Basic/src/crt-rsa.c | 0 {fissc => compiler/fissc}/Basic/src/initialize.c | 0 {fissc => compiler/fissc}/Basic/src/main.c | 0 {fissc => compiler/fissc}/Basic/src/oracle.c | 0 {fissc => compiler/fissc}/crt-rsa.trv | 0 {fissc => compiler/fissc}/share/interface.h | 0 {fissc => compiler/fissc}/share/lazart.h | 0 {fissc => compiler/fissc}/share/types.h | 0 main.asm => compiler/main.asm | 0 out.asm => compiler/out.asm | 0 run_asm => compiler/run_asm | 0 {src => compiler/src}/codegen/codegen.rs | 0 {src => compiler/src}/codegen/mod.rs | 0 {src => compiler/src}/lexer/lexer.rs | 0 {src => compiler/src}/lexer/mod.rs | 0 {src => compiler/src}/lexer/token.rs | 0 {src => compiler/src}/main.rs | 0 {src => compiler/src}/parser/mod.rs | 0 {src => compiler/src}/parser/parser.rs | 0 {src => compiler/src}/semantic/mod.rs | 0 {src => compiler/src}/semantic/symbol_table.rs | 0 {test_codes => compiler/test_codes}/simple.trv | 0 .../test_codes}/simple.trv.output | 0 .../test_codes}/test_if_else.trv | 0 .../test_codes}/test_if_else.trv.output | 0 .../test_codes}/test_main_let.trv | 0 .../test_codes}/test_main_let.trv.output | 0 .../test_codes}/test_main_return.trv | 0 .../test_codes}/test_main_return.trv.output | 0 {test_codes => compiler/test_codes}/test_while.trv | 0 .../test_codes}/test_while.trv.output | 0 .../test_codes}/test_while_nested.trv | 0 .../test_codes}/test_while_nested.trv.output | 0 .../test_codes}/test_while_simple.trv | 0 .../test_codes}/test_while_simple.trv.output | 0 .../test_codes}/test_while_two_loops.trv | 0 .../test_codes}/test_while_two_loops.trv.output | 0 .../test_codes_compiled}/simple.asm | 0 .../test_codes_compiled}/test_main_let.asm | 0 .../test_codes_compiled}/test_main_return.asm | 0 .../test_codes_compiled}/test_while.asm | 0 .../test_codes_compiled}/test_while_nested.asm | 0 .../test_codes_compiled}/test_while_simple.asm | 0 .../test_codes_compiled}/test_while_two_loops.asm | 0 52 files changed, 0 insertions(+), 0 deletions(-) rename Cargo.lock => compiler/Cargo.lock (100%) rename Cargo.toml => compiler/Cargo.toml (100%) rename README.md => compiler/README.md (100%) rename {fissc => compiler/fissc}/Basic/.Makefile.swp (100%) rename {fissc => compiler/fissc}/Basic/Makefile (100%) rename {fissc => compiler/fissc}/Basic/bin/crt-rsa (100%) rename {fissc => compiler/fissc}/Basic/include/commons.h (100%) rename {fissc => compiler/fissc}/Basic/src/countermeasure.c (100%) rename {fissc => compiler/fissc}/Basic/src/crt-rsa.c (100%) rename {fissc => compiler/fissc}/Basic/src/initialize.c (100%) rename {fissc => compiler/fissc}/Basic/src/main.c (100%) rename {fissc => compiler/fissc}/Basic/src/oracle.c (100%) rename {fissc => compiler/fissc}/crt-rsa.trv (100%) rename {fissc => compiler/fissc}/share/interface.h (100%) rename {fissc => compiler/fissc}/share/lazart.h (100%) rename {fissc => compiler/fissc}/share/types.h (100%) rename main.asm => compiler/main.asm (100%) rename out.asm => compiler/out.asm (100%) rename run_asm => compiler/run_asm (100%) rename {src => compiler/src}/codegen/codegen.rs (100%) rename {src => compiler/src}/codegen/mod.rs (100%) rename {src => compiler/src}/lexer/lexer.rs (100%) rename {src => compiler/src}/lexer/mod.rs (100%) rename {src => compiler/src}/lexer/token.rs (100%) rename {src => compiler/src}/main.rs (100%) rename {src => compiler/src}/parser/mod.rs (100%) rename {src => compiler/src}/parser/parser.rs (100%) rename {src => compiler/src}/semantic/mod.rs (100%) rename {src => compiler/src}/semantic/symbol_table.rs (100%) rename {test_codes => compiler/test_codes}/simple.trv (100%) rename {test_codes => compiler/test_codes}/simple.trv.output (100%) rename {test_codes => compiler/test_codes}/test_if_else.trv (100%) rename {test_codes => compiler/test_codes}/test_if_else.trv.output (100%) rename {test_codes => compiler/test_codes}/test_main_let.trv (100%) rename {test_codes => compiler/test_codes}/test_main_let.trv.output (100%) rename {test_codes => compiler/test_codes}/test_main_return.trv (100%) rename {test_codes => compiler/test_codes}/test_main_return.trv.output (100%) rename {test_codes => compiler/test_codes}/test_while.trv (100%) rename {test_codes => compiler/test_codes}/test_while.trv.output (100%) rename {test_codes => compiler/test_codes}/test_while_nested.trv (100%) rename {test_codes => compiler/test_codes}/test_while_nested.trv.output (100%) rename {test_codes => compiler/test_codes}/test_while_simple.trv (100%) rename {test_codes => compiler/test_codes}/test_while_simple.trv.output (100%) rename {test_codes => compiler/test_codes}/test_while_two_loops.trv (100%) rename {test_codes => compiler/test_codes}/test_while_two_loops.trv.output (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/simple.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_main_let.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_main_return.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_while.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_while_nested.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_while_simple.asm (100%) rename {test_codes_compiled => compiler/test_codes_compiled}/test_while_two_loops.asm (100%) diff --git a/Cargo.lock b/compiler/Cargo.lock similarity index 100% rename from Cargo.lock rename to compiler/Cargo.lock diff --git a/Cargo.toml b/compiler/Cargo.toml similarity index 100% rename from Cargo.toml rename to compiler/Cargo.toml diff --git a/README.md b/compiler/README.md similarity index 100% rename from README.md rename to compiler/README.md diff --git a/fissc/Basic/.Makefile.swp b/compiler/fissc/Basic/.Makefile.swp similarity index 100% rename from fissc/Basic/.Makefile.swp rename to compiler/fissc/Basic/.Makefile.swp diff --git a/fissc/Basic/Makefile b/compiler/fissc/Basic/Makefile similarity index 100% rename from fissc/Basic/Makefile rename to compiler/fissc/Basic/Makefile diff --git a/fissc/Basic/bin/crt-rsa b/compiler/fissc/Basic/bin/crt-rsa similarity index 100% rename from fissc/Basic/bin/crt-rsa rename to compiler/fissc/Basic/bin/crt-rsa diff --git a/fissc/Basic/include/commons.h b/compiler/fissc/Basic/include/commons.h similarity index 100% rename from fissc/Basic/include/commons.h rename to compiler/fissc/Basic/include/commons.h diff --git a/fissc/Basic/src/countermeasure.c b/compiler/fissc/Basic/src/countermeasure.c similarity index 100% rename from fissc/Basic/src/countermeasure.c rename to compiler/fissc/Basic/src/countermeasure.c diff --git a/fissc/Basic/src/crt-rsa.c b/compiler/fissc/Basic/src/crt-rsa.c similarity index 100% rename from fissc/Basic/src/crt-rsa.c rename to compiler/fissc/Basic/src/crt-rsa.c diff --git a/fissc/Basic/src/initialize.c b/compiler/fissc/Basic/src/initialize.c similarity index 100% rename from fissc/Basic/src/initialize.c rename to compiler/fissc/Basic/src/initialize.c diff --git a/fissc/Basic/src/main.c b/compiler/fissc/Basic/src/main.c similarity index 100% rename from fissc/Basic/src/main.c rename to compiler/fissc/Basic/src/main.c diff --git a/fissc/Basic/src/oracle.c b/compiler/fissc/Basic/src/oracle.c similarity index 100% rename from fissc/Basic/src/oracle.c rename to compiler/fissc/Basic/src/oracle.c diff --git a/fissc/crt-rsa.trv b/compiler/fissc/crt-rsa.trv similarity index 100% rename from fissc/crt-rsa.trv rename to compiler/fissc/crt-rsa.trv diff --git a/fissc/share/interface.h b/compiler/fissc/share/interface.h similarity index 100% rename from fissc/share/interface.h rename to compiler/fissc/share/interface.h diff --git a/fissc/share/lazart.h b/compiler/fissc/share/lazart.h similarity index 100% rename from fissc/share/lazart.h rename to compiler/fissc/share/lazart.h diff --git a/fissc/share/types.h b/compiler/fissc/share/types.h similarity index 100% rename from fissc/share/types.h rename to compiler/fissc/share/types.h diff --git a/main.asm b/compiler/main.asm similarity index 100% rename from main.asm rename to compiler/main.asm diff --git a/out.asm b/compiler/out.asm similarity index 100% rename from out.asm rename to compiler/out.asm diff --git a/run_asm b/compiler/run_asm similarity index 100% rename from run_asm rename to compiler/run_asm diff --git a/src/codegen/codegen.rs b/compiler/src/codegen/codegen.rs similarity index 100% rename from src/codegen/codegen.rs rename to compiler/src/codegen/codegen.rs diff --git a/src/codegen/mod.rs b/compiler/src/codegen/mod.rs similarity index 100% rename from src/codegen/mod.rs rename to compiler/src/codegen/mod.rs diff --git a/src/lexer/lexer.rs b/compiler/src/lexer/lexer.rs similarity index 100% rename from src/lexer/lexer.rs rename to compiler/src/lexer/lexer.rs diff --git a/src/lexer/mod.rs b/compiler/src/lexer/mod.rs similarity index 100% rename from src/lexer/mod.rs rename to compiler/src/lexer/mod.rs diff --git a/src/lexer/token.rs b/compiler/src/lexer/token.rs similarity index 100% rename from src/lexer/token.rs rename to compiler/src/lexer/token.rs diff --git a/src/main.rs b/compiler/src/main.rs similarity index 100% rename from src/main.rs rename to compiler/src/main.rs diff --git a/src/parser/mod.rs b/compiler/src/parser/mod.rs similarity index 100% rename from src/parser/mod.rs rename to compiler/src/parser/mod.rs diff --git a/src/parser/parser.rs b/compiler/src/parser/parser.rs similarity index 100% rename from src/parser/parser.rs rename to compiler/src/parser/parser.rs diff --git a/src/semantic/mod.rs b/compiler/src/semantic/mod.rs similarity index 100% rename from src/semantic/mod.rs rename to compiler/src/semantic/mod.rs diff --git a/src/semantic/symbol_table.rs b/compiler/src/semantic/symbol_table.rs similarity index 100% rename from src/semantic/symbol_table.rs rename to compiler/src/semantic/symbol_table.rs diff --git a/test_codes/simple.trv b/compiler/test_codes/simple.trv similarity index 100% rename from test_codes/simple.trv rename to compiler/test_codes/simple.trv diff --git a/test_codes/simple.trv.output b/compiler/test_codes/simple.trv.output similarity index 100% rename from test_codes/simple.trv.output rename to compiler/test_codes/simple.trv.output diff --git a/test_codes/test_if_else.trv b/compiler/test_codes/test_if_else.trv similarity index 100% rename from test_codes/test_if_else.trv rename to compiler/test_codes/test_if_else.trv diff --git a/test_codes/test_if_else.trv.output b/compiler/test_codes/test_if_else.trv.output similarity index 100% rename from test_codes/test_if_else.trv.output rename to compiler/test_codes/test_if_else.trv.output diff --git a/test_codes/test_main_let.trv b/compiler/test_codes/test_main_let.trv similarity index 100% rename from test_codes/test_main_let.trv rename to compiler/test_codes/test_main_let.trv diff --git a/test_codes/test_main_let.trv.output b/compiler/test_codes/test_main_let.trv.output similarity index 100% rename from test_codes/test_main_let.trv.output rename to compiler/test_codes/test_main_let.trv.output diff --git a/test_codes/test_main_return.trv b/compiler/test_codes/test_main_return.trv similarity index 100% rename from test_codes/test_main_return.trv rename to compiler/test_codes/test_main_return.trv diff --git a/test_codes/test_main_return.trv.output b/compiler/test_codes/test_main_return.trv.output similarity index 100% rename from test_codes/test_main_return.trv.output rename to compiler/test_codes/test_main_return.trv.output diff --git a/test_codes/test_while.trv b/compiler/test_codes/test_while.trv similarity index 100% rename from test_codes/test_while.trv rename to compiler/test_codes/test_while.trv diff --git a/test_codes/test_while.trv.output b/compiler/test_codes/test_while.trv.output similarity index 100% rename from test_codes/test_while.trv.output rename to compiler/test_codes/test_while.trv.output diff --git a/test_codes/test_while_nested.trv b/compiler/test_codes/test_while_nested.trv similarity index 100% rename from test_codes/test_while_nested.trv rename to compiler/test_codes/test_while_nested.trv diff --git a/test_codes/test_while_nested.trv.output b/compiler/test_codes/test_while_nested.trv.output similarity index 100% rename from test_codes/test_while_nested.trv.output rename to compiler/test_codes/test_while_nested.trv.output diff --git a/test_codes/test_while_simple.trv b/compiler/test_codes/test_while_simple.trv similarity index 100% rename from test_codes/test_while_simple.trv rename to compiler/test_codes/test_while_simple.trv diff --git a/test_codes/test_while_simple.trv.output b/compiler/test_codes/test_while_simple.trv.output similarity index 100% rename from test_codes/test_while_simple.trv.output rename to compiler/test_codes/test_while_simple.trv.output diff --git a/test_codes/test_while_two_loops.trv b/compiler/test_codes/test_while_two_loops.trv similarity index 100% rename from test_codes/test_while_two_loops.trv rename to compiler/test_codes/test_while_two_loops.trv diff --git a/test_codes/test_while_two_loops.trv.output b/compiler/test_codes/test_while_two_loops.trv.output similarity index 100% rename from test_codes/test_while_two_loops.trv.output rename to compiler/test_codes/test_while_two_loops.trv.output diff --git a/test_codes_compiled/simple.asm b/compiler/test_codes_compiled/simple.asm similarity index 100% rename from test_codes_compiled/simple.asm rename to compiler/test_codes_compiled/simple.asm diff --git a/test_codes_compiled/test_main_let.asm b/compiler/test_codes_compiled/test_main_let.asm similarity index 100% rename from test_codes_compiled/test_main_let.asm rename to compiler/test_codes_compiled/test_main_let.asm diff --git a/test_codes_compiled/test_main_return.asm b/compiler/test_codes_compiled/test_main_return.asm similarity index 100% rename from test_codes_compiled/test_main_return.asm rename to compiler/test_codes_compiled/test_main_return.asm diff --git a/test_codes_compiled/test_while.asm b/compiler/test_codes_compiled/test_while.asm similarity index 100% rename from test_codes_compiled/test_while.asm rename to compiler/test_codes_compiled/test_while.asm diff --git a/test_codes_compiled/test_while_nested.asm b/compiler/test_codes_compiled/test_while_nested.asm similarity index 100% rename from test_codes_compiled/test_while_nested.asm rename to compiler/test_codes_compiled/test_while_nested.asm diff --git a/test_codes_compiled/test_while_simple.asm b/compiler/test_codes_compiled/test_while_simple.asm similarity index 100% rename from test_codes_compiled/test_while_simple.asm rename to compiler/test_codes_compiled/test_while_simple.asm diff --git a/test_codes_compiled/test_while_two_loops.asm b/compiler/test_codes_compiled/test_while_two_loops.asm similarity index 100% rename from test_codes_compiled/test_while_two_loops.asm rename to compiler/test_codes_compiled/test_while_two_loops.asm From 67e5e864b008a4544137c1bc688f3efc9637f716 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 15:00:04 +0100 Subject: [PATCH 23/34] testing framework looks great! We just need to use the interpreter now and actually have hardenings. Jeg er helt fucked in me brain today, kan ik mere idag sorry boos --- testing/compiled_test_files/simple.asm | 46 +++++ testing/compiled_test_files/simple.hard.asm | 46 +++++ testing/compiled_test_files/test_if_else.asm | 32 ++++ .../compiled_test_files/test_if_else.hard.asm | 32 ++++ testing/compiled_test_files/test_main_let.asm | 16 ++ .../test_main_let.hard.asm | 16 ++ .../compiled_test_files/test_main_return.asm | 13 ++ .../test_main_return.hard.asm | 13 ++ testing/compiled_test_files/test_while.asm | 33 ++++ .../compiled_test_files/test_while.hard.asm | 33 ++++ .../compiled_test_files/test_while_nested.asm | 54 ++++++ .../test_while_nested.hard.asm | 54 ++++++ .../compiled_test_files/test_while_simple.asm | 33 ++++ .../test_while_simple.hard.asm | 33 ++++ .../test_while_two_loops.asm | 56 ++++++ .../test_while_two_loops.hard.asm | 56 ++++++ testing/config.toml | 1 + testing/requirements.txt | 1 + testing/setup | 19 ++ .../src/__pycache__/testing.cpython-314.pyc | Bin 0 -> 3341 bytes .../__pycache__/testrunner.cpython-314.pyc | Bin 0 -> 10832 bytes testing/src/testrunner.py | 175 ++++++++++++++++++ testing/test | 33 ++++ testing/tests/simple.trv | 13 ++ testing/tests/simple.trv.output | 1 + testing/tests/test_if_else.trv | 9 + testing/tests/test_if_else.trv.output | 1 + testing/tests/test_main_let.trv | 4 + testing/tests/test_main_let.trv.output | 1 + testing/tests/test_main_return.trv | 3 + testing/tests/test_main_return.trv.output | 1 + testing/tests/test_while.trv | 7 + testing/tests/test_while.trv.output | 1 + testing/tests/test_while_nested.trv | 11 ++ testing/tests/test_while_nested.trv.output | 1 + testing/tests/test_while_simple.trv | 7 + testing/tests/test_while_simple.trv.output | 1 + testing/tests/test_while_two_loops.trv | 11 ++ testing/tests/test_while_two_loops.trv.output | 1 + 39 files changed, 868 insertions(+) create mode 100644 testing/compiled_test_files/simple.asm create mode 100644 testing/compiled_test_files/simple.hard.asm create mode 100644 testing/compiled_test_files/test_if_else.asm create mode 100644 testing/compiled_test_files/test_if_else.hard.asm create mode 100644 testing/compiled_test_files/test_main_let.asm create mode 100644 testing/compiled_test_files/test_main_let.hard.asm create mode 100644 testing/compiled_test_files/test_main_return.asm create mode 100644 testing/compiled_test_files/test_main_return.hard.asm create mode 100644 testing/compiled_test_files/test_while.asm create mode 100644 testing/compiled_test_files/test_while.hard.asm create mode 100644 testing/compiled_test_files/test_while_nested.asm create mode 100644 testing/compiled_test_files/test_while_nested.hard.asm create mode 100644 testing/compiled_test_files/test_while_simple.asm create mode 100644 testing/compiled_test_files/test_while_simple.hard.asm create mode 100644 testing/compiled_test_files/test_while_two_loops.asm create mode 100644 testing/compiled_test_files/test_while_two_loops.hard.asm create mode 100644 testing/config.toml create mode 100644 testing/requirements.txt create mode 100755 testing/setup create mode 100644 testing/src/__pycache__/testing.cpython-314.pyc create mode 100644 testing/src/__pycache__/testrunner.cpython-314.pyc create mode 100644 testing/src/testrunner.py create mode 100755 testing/test create mode 100644 testing/tests/simple.trv create mode 100644 testing/tests/simple.trv.output create mode 100644 testing/tests/test_if_else.trv create mode 100644 testing/tests/test_if_else.trv.output create mode 100644 testing/tests/test_main_let.trv create mode 100644 testing/tests/test_main_let.trv.output create mode 100644 testing/tests/test_main_return.trv create mode 100644 testing/tests/test_main_return.trv.output create mode 100644 testing/tests/test_while.trv create mode 100644 testing/tests/test_while.trv.output create mode 100644 testing/tests/test_while_nested.trv create mode 100644 testing/tests/test_while_nested.trv.output create mode 100644 testing/tests/test_while_simple.trv create mode 100644 testing/tests/test_while_simple.trv.output create mode 100644 testing/tests/test_while_two_loops.trv create mode 100644 testing/tests/test_while_two_loops.trv.output diff --git a/testing/compiled_test_files/simple.asm b/testing/compiled_test_files/simple.asm new file mode 100644 index 0000000..60e98bc --- /dev/null +++ b/testing/compiled_test_files/simple.asm @@ -0,0 +1,46 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + mov r0, #11 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_1 + mov r0, #12 + str r0, [sp] + b endif_1 +else_1: + mov r0, #11 + str r0, [sp] +endif_1: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/simple.hard.asm b/testing/compiled_test_files/simple.hard.asm new file mode 100644 index 0000000..60e98bc --- /dev/null +++ b/testing/compiled_test_files/simple.hard.asm @@ -0,0 +1,46 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + mov r0, #11 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_1 + mov r0, #12 + str r0, [sp] + b endif_1 +else_1: + mov r0, #11 + str r0, [sp] +endif_1: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_if_else.asm b/testing/compiled_test_files/test_if_else.asm new file mode 100644 index 0000000..9683485 --- /dev/null +++ b/testing/compiled_test_files/test_if_else.asm @@ -0,0 +1,32 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + mov r0, #11 + str r0, [sp] + b endif_0 +else_0: + mov r0, #12 + str r0, [sp] +endif_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_if_else.hard.asm b/testing/compiled_test_files/test_if_else.hard.asm new file mode 100644 index 0000000..9683485 --- /dev/null +++ b/testing/compiled_test_files/test_if_else.hard.asm @@ -0,0 +1,32 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #10 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + mov r0, #11 + str r0, [sp] + b endif_0 +else_0: + mov r0, #12 + str r0, [sp] +endif_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_main_let.asm b/testing/compiled_test_files/test_main_let.asm new file mode 100644 index 0000000..890e947 --- /dev/null +++ b/testing/compiled_test_files/test_main_let.asm @@ -0,0 +1,16 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #27 + str r0, [sp] + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_main_let.hard.asm b/testing/compiled_test_files/test_main_let.hard.asm new file mode 100644 index 0000000..890e947 --- /dev/null +++ b/testing/compiled_test_files/test_main_let.hard.asm @@ -0,0 +1,16 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #27 + str r0, [sp] + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_main_return.asm b/testing/compiled_test_files/test_main_return.asm new file mode 100644 index 0000000..01167be --- /dev/null +++ b/testing/compiled_test_files/test_main_return.asm @@ -0,0 +1,13 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r0, #69 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_main_return.hard.asm b/testing/compiled_test_files/test_main_return.hard.asm new file mode 100644 index 0000000..01167be --- /dev/null +++ b/testing/compiled_test_files/test_main_return.hard.asm @@ -0,0 +1,13 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r0, #69 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while.asm b/testing/compiled_test_files/test_while.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/testing/compiled_test_files/test_while.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while.hard.asm b/testing/compiled_test_files/test_while.hard.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/testing/compiled_test_files/test_while.hard.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_nested.asm b/testing/compiled_test_files/test_while_nested.asm new file mode 100644 index 0000000..e8ede92 --- /dev/null +++ b/testing/compiled_test_files/test_while_nested.asm @@ -0,0 +1,54 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #2 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + add sp, sp, #4 + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_nested.hard.asm b/testing/compiled_test_files/test_while_nested.hard.asm new file mode 100644 index 0000000..e8ede92 --- /dev/null +++ b/testing/compiled_test_files/test_while_nested.hard.asm @@ -0,0 +1,54 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #2 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + add sp, sp, #4 + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_simple.asm b/testing/compiled_test_files/test_while_simple.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/testing/compiled_test_files/test_while_simple.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_simple.hard.asm b/testing/compiled_test_files/test_while_simple.hard.asm new file mode 100644 index 0000000..af133c7 --- /dev/null +++ b/testing/compiled_test_files/test_while_simple.hard.asm @@ -0,0 +1,33 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] +while_0: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #12 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_0 +end_while_0: + ldr r0, [sp, #0] + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_two_loops.asm b/testing/compiled_test_files/test_while_two_loops.asm new file mode 100644 index 0000000..18d6895 --- /dev/null +++ b/testing/compiled_test_files/test_while_two_loops.asm @@ -0,0 +1,56 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #4 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #0] + add r0, r1, r0 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/compiled_test_files/test_while_two_loops.hard.asm b/testing/compiled_test_files/test_while_two_loops.hard.asm new file mode 100644 index 0000000..18d6895 --- /dev/null +++ b/testing/compiled_test_files/test_while_two_loops.hard.asm @@ -0,0 +1,56 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #3 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: +while_1: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #4 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp] + b while_1 +end_while_1: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #0] + add r0, r1, r0 + mov r7, #1 + svc #0 + +.size _start, .-_start diff --git a/testing/config.toml b/testing/config.toml new file mode 100644 index 0000000..e3928fe --- /dev/null +++ b/testing/config.toml @@ -0,0 +1 @@ +tests_folder = "tests" diff --git a/testing/requirements.txt b/testing/requirements.txt new file mode 100644 index 0000000..bd79a65 --- /dev/null +++ b/testing/requirements.txt @@ -0,0 +1 @@ +toml diff --git a/testing/setup b/testing/setup new file mode 100755 index 0000000..f712e75 --- /dev/null +++ b/testing/setup @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BIN_DIR="$SCRIPT_DIR/bin" + +mkdir -p "$BIN_DIR" + +echo "Building compiler..." +cd "$SCRIPT_DIR/../compiler" +cargo build --release +cp target/release/trivic "$BIN_DIR/compiler" + +echo "Building interpreter..." +cd "$SCRIPT_DIR/../interpreter" +cargo build --release +cp target/release/thumb2_interpreter "$BIN_DIR/interpreter" + +echo "Done! Binaries in $BIN_DIR" diff --git a/testing/src/__pycache__/testing.cpython-314.pyc b/testing/src/__pycache__/testing.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..845a02a109113c768b9d5b0e607fbef62bfd01d5 GIT binary patch literal 3341 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 literal 0 HcmV?d00001 diff --git a/testing/src/testrunner.py b/testing/src/testrunner.py new file mode 100644 index 0000000..a38d8f9 --- /dev/null +++ b/testing/src/testrunner.py @@ -0,0 +1,175 @@ +import os +import sys +import subprocess +import shutil +import toml +from datetime import datetime + +class TestRunner: + def __init__(self, config_path=None): + if config_path is None: + config_path = os.path.join(os.path.dirname(__file__), "..", "config.toml") + + with open(config_path, 'r') as f: + config = toml.load(f) + + self.base_dir = os.path.join(os.path.dirname(__file__), "..") + self.tests_folder = os.path.join(self.base_dir, config.get('tests_folder', 'tests')) + self.artifacts_folder = os.path.join(self.base_dir, "artifacts") + self.tests = self._discover_tests() + + def _discover_tests(self): + tests = [] + if not os.path.exists(self.tests_folder): + return tests + + files = os.listdir(self.tests_folder) + trv_files = sorted([f for f in files if f.endswith('.trv')]) + + for trv_file in trv_files: + test_name = trv_file[:-4] + output_file = trv_file + ".output" + + if output_file in files: + trv_path = os.path.join(self.tests_folder, trv_file) + output_path = os.path.join(self.tests_folder, output_file) + + with open(output_path, 'r') as f: + expected_output = f.read().strip() + + tests.append({ + 'name': test_name, + 'path': trv_path, + 'expected_output': expected_output + }) + + return tests + + def check_bin(self): + from pathlib import Path + + script_dir = Path(__file__).resolve().parent.parent + setup_path = script_dir / "setup" + + bin_dir = script_dir / "bin" + + if not bin_dir.is_dir(): + raise FileNotFoundError( + f"Missing: compiler, interpreter. Fix by running: {setup_path}" + ) + + missing = [] + + if not (bin_dir / "compiler").is_file(): + missing.append("compiler") + + if not (bin_dir / "interpreter").is_file(): + missing.append("interpreter") + + if missing: + raise FileNotFoundError( + f"Missing: {', '.join(missing)}. Fix by running: {setup_path}" + ) + + def compile_test(self, test, hard, compiled_folder): + trv_path = test['path'] + test_name = test['name'] + + if hard: + asm_path = os.path.join(compiled_folder, f"{test_name}.hard.asm") + else: + asm_path = os.path.join(compiled_folder, f"{test_name}.asm") + + compiler_dir = os.path.join(os.path.dirname(__file__), "..", "bin") + + cmd = [os.path.join(compiler_dir, "compiler"), trv_path, "-o", asm_path] + if hard: + cmd.append("--hard") + + result = subprocess.run(cmd, cwd=compiler_dir, capture_output=True, text=True) + return result.returncode == 0, asm_path, result.stdout, result.stderr + + def list_tests(self): + return self.tests + + def _get_next_run_number(self): + if not os.path.exists(self.artifacts_folder): + return 1 + + max_num = 0 + for item in os.listdir(self.artifacts_folder): + base_name = item[:-4] if item.endswith('.zip') else item + if os.path.isdir(os.path.join(self.artifacts_folder, item)) or item.endswith('.zip'): + parts = base_name.split('-', 1) + if len(parts) == 2 and parts[0].isdigit(): + max_num = max(max_num, int(parts[0])) + return max_num + 1 + + def setup(self): + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + run_num = self._get_next_run_number() + self.run_folder_name = f"{run_num}-{timestamp}" + self.run_folder = os.path.join(self.artifacts_folder, self.run_folder_name) + self.run_tests_folder = os.path.join(self.run_folder, "tests") + self.compiled_folder = os.path.join(self.run_folder, "compiled_test_files") + + os.makedirs(self.run_folder, exist_ok=True) + os.makedirs(self.run_tests_folder, exist_ok=True) + os.makedirs(self.compiled_folder, exist_ok=True) + + for f in os.listdir(self.tests_folder): + if f.endswith('.trv') or f.endswith('.trv.output'): + shutil.copy(os.path.join(self.tests_folder, f), self.run_tests_folder) + + return self.run_folder + + def compile(self): + results = [] + for test in self.tests: + test_result = {'name': test['name'], 'normal': None, 'hard': None} + + for hard in [False, True]: + hard_str = "hard" if hard else "normal" + success, asm_path, stdout, stderr = self.compile_test(test, hard, self.compiled_folder) + test_result[hard_str] = {'success': success, 'asm_path': asm_path, 'stdout': stdout, 'stderr': stderr} + + results.append(test_result) + + return results + + def run_tests(self): + if not hasattr(self, 'run_folder'): + self.setup() + + results = self.compile() + + for test, result in zip(self.tests, results): + print(f"Test: {test['name']}") + + for hard in [False, True]: + hard_str = "hard" if hard else "normal" + res = result[hard_str] + if res['success']: + print(f" Compiled ({hard_str}) successfully") + else: + print(f" Compilation failed ({hard_str}):") + if res['stdout']: + print(f" stdout: {res['stdout']}") + if res['stderr']: + print(f" stderr: {res['stderr']}") + + print(f" Expected output: {test['expected_output']}") + + zip_base = os.path.join(self.artifacts_folder, self.run_folder_name) + shutil.make_archive(zip_base, 'zip', self.artifacts_folder, self.run_folder_name) + shutil.rmtree(self.run_folder) + + print(f"\nArtifacts saved to: {zip_base}.zip") + + +if __name__ == "__main__": + runner = TestRunner() + + print(f"Running test runner") + print(f"Found {len(runner.tests)} tests") + runner.run_tests() diff --git a/testing/test b/testing/test new file mode 100755 index 0000000..65aae71 --- /dev/null +++ b/testing/test @@ -0,0 +1,33 @@ +#!/bin/python3 + +import argparse + +from src.testrunner import TestRunner + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--config', type=str, default=None, help='Path to config.toml') + parser.add_argument('--skip-run', action='store_true', help='Only setup and compile, skip running tests') + args = parser.parse_args() + + runner = TestRunner(config_path=args.config) + # check that the compiler and interpreter is present: + runner.check_bin() + + + print(f"Setting up...") + folder = runner.setup() + print(f"Created folder: {folder}") + + print(f"\nCompiling tests...") + results = runner.compile() + print(f"Compiled {len(results)} tests") + + if not args.skip_run: + print(f"\nRunning tests...") + runner.run_tests() + else: + print(f"\nSkipping test run (--skip-run)") + +if __name__ == "__main__": + main() diff --git a/testing/tests/simple.trv b/testing/tests/simple.trv new file mode 100644 index 0000000..62abea2 --- /dev/null +++ b/testing/tests/simple.trv @@ -0,0 +1,13 @@ +func main() -> Integer { + let num : Integer = 0; + + while num < 10 do { + num = 11; + } + if num > 10 { + num = 12; + } else { + num = 11; + } + return num; +} diff --git a/testing/tests/simple.trv.output b/testing/tests/simple.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/testing/tests/simple.trv.output @@ -0,0 +1 @@ +12 diff --git a/testing/tests/test_if_else.trv b/testing/tests/test_if_else.trv new file mode 100644 index 0000000..3b984ea --- /dev/null +++ b/testing/tests/test_if_else.trv @@ -0,0 +1,9 @@ +func main() -> Integer { + let num : Integer = 9; + if num > 10 { + num = 11; + } else { + num = 12; + } + return num; +} diff --git a/testing/tests/test_if_else.trv.output b/testing/tests/test_if_else.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/testing/tests/test_if_else.trv.output @@ -0,0 +1 @@ +12 diff --git a/testing/tests/test_main_let.trv b/testing/tests/test_main_let.trv new file mode 100644 index 0000000..fdc57cb --- /dev/null +++ b/testing/tests/test_main_let.trv @@ -0,0 +1,4 @@ +func main() -> Integer { + let num : Integer = 27; + return num; +} diff --git a/testing/tests/test_main_let.trv.output b/testing/tests/test_main_let.trv.output new file mode 100644 index 0000000..f64f5d8 --- /dev/null +++ b/testing/tests/test_main_let.trv.output @@ -0,0 +1 @@ +27 diff --git a/testing/tests/test_main_return.trv b/testing/tests/test_main_return.trv new file mode 100644 index 0000000..c66bbb3 --- /dev/null +++ b/testing/tests/test_main_return.trv @@ -0,0 +1,3 @@ +func main() -> Integer { + return 69; +} diff --git a/testing/tests/test_main_return.trv.output b/testing/tests/test_main_return.trv.output new file mode 100644 index 0000000..b5489e5 --- /dev/null +++ b/testing/tests/test_main_return.trv.output @@ -0,0 +1 @@ +69 diff --git a/testing/tests/test_while.trv b/testing/tests/test_while.trv new file mode 100644 index 0000000..db54eef --- /dev/null +++ b/testing/tests/test_while.trv @@ -0,0 +1,7 @@ +func main() -> Integer { + let num : Integer = 9; + while num < 12 { + num = num + 1; + } + return num; +} diff --git a/testing/tests/test_while.trv.output b/testing/tests/test_while.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/testing/tests/test_while.trv.output @@ -0,0 +1 @@ +12 diff --git a/testing/tests/test_while_nested.trv b/testing/tests/test_while_nested.trv new file mode 100644 index 0000000..7102f7f --- /dev/null +++ b/testing/tests/test_while_nested.trv @@ -0,0 +1,11 @@ +func main() -> Integer { + let a : Integer = 0; + while a < 3 { + let b : Integer = 0; + while b < 2 { + b = b + 1; + } + a = a + 1; + } + return a; +} diff --git a/testing/tests/test_while_nested.trv.output b/testing/tests/test_while_nested.trv.output new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/testing/tests/test_while_nested.trv.output @@ -0,0 +1 @@ +3 diff --git a/testing/tests/test_while_simple.trv b/testing/tests/test_while_simple.trv new file mode 100644 index 0000000..db54eef --- /dev/null +++ b/testing/tests/test_while_simple.trv @@ -0,0 +1,7 @@ +func main() -> Integer { + let num : Integer = 9; + while num < 12 { + num = num + 1; + } + return num; +} diff --git a/testing/tests/test_while_simple.trv.output b/testing/tests/test_while_simple.trv.output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/testing/tests/test_while_simple.trv.output @@ -0,0 +1 @@ +12 diff --git a/testing/tests/test_while_two_loops.trv b/testing/tests/test_while_two_loops.trv new file mode 100644 index 0000000..629c22c --- /dev/null +++ b/testing/tests/test_while_two_loops.trv @@ -0,0 +1,11 @@ +func main() -> Integer { + let a : Integer = 0; + let b : Integer = 0; + while a < 3 { + a = a + 1; + } + while b < 4 { + b = b + 1; + } + return a+b; +} diff --git a/testing/tests/test_while_two_loops.trv.output b/testing/tests/test_while_two_loops.trv.output new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/testing/tests/test_while_two_loops.trv.output @@ -0,0 +1 @@ +7 From 575afdc10506b176a3055a7dbe7b159f76451a56 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Wed, 11 Mar 2026 15:01:40 +0100 Subject: [PATCH 24/34] git ignore stuff --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c3cf292..ff60a5b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ # already existing elements were commented out **/target -/tmp -/temp /interpreter/target /interpreter/tmp /playground @@ -15,3 +13,6 @@ *.core **/tmp **/temp + +/testing/bin +/testing/artifacts From 6002d7df0f7d35efdcc0acd87c8e3778f97d56b3 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Mon, 16 Mar 2026 10:14:30 +0100 Subject: [PATCH 25/34] tested formatter teehee --- interpreter/src/interpreter.rs | 160 ++++++++++----------------------- 1 file changed, 48 insertions(+), 112 deletions(-) diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 0d6b3a0..418b6b0 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -53,11 +53,7 @@ impl Cpsr { let is_then = self.it_state.mask[step_idx] == 't'; let condition_met = self.evaluate_condition(&self.it_state.base_cond); - let execute = if is_then { - condition_met - } else { - !condition_met - }; + let execute = if is_then { condition_met } else { !condition_met }; // Advance or Reset self.it_state.current_instr += 1; @@ -134,7 +130,8 @@ impl Interpreter { } pub fn read_file(&mut self, file_path: &String) -> bool { let file = File::open(file_path).expect("Could not open file: {file_path}"); - let lines: Vec = std::io::BufReader::new(file) + let lines: Vec = std::io::BufReader + ::new(file) .lines() .map(|line| line.expect("Could not read line from file")) .collect(); @@ -184,28 +181,17 @@ impl Interpreter { println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ CPSR FLAGS: ║"); println!("╟──────────────────────────────────────────────────────────────────╢"); - println!( - "║ Z (Zero): {:<5} ║", - self.cpsr.z - ); - println!( - "║ N (Negative): {:<5} ║", - self.cpsr.n - ); - println!( - "║ C (Carry): {:<5} ║", - self.cpsr.c - ); - println!( - "║ V (Overflow): {:<5} ║", - self.cpsr.v - ); + println!("║ Z (Zero): {:<5} ║", self.cpsr.z); + println!("║ N (Negative): {:<5} ║", self.cpsr.n); + println!("║ C (Carry): {:<5} ║", self.cpsr.c); + println!("║ V (Overflow): {:<5} ║", self.cpsr.v); println!("╟──────────────────────────────────────────────────────────────────╢"); println!("║ PROGRAM COUNTER: ║"); println!( "║ PC: {:>10} (0x{:08x}) ║", - self.pc, self.pc + self.pc, + self.pc ); println!("╟──────────────────────────────────────────────────────────────────╢"); @@ -323,7 +309,7 @@ impl Interpreter { result.push(label.clone()); branch_map.insert( label[0..label.len() - 1].to_string(), - (result.len() - 1) as u32, + (result.len() - 1) as u32 ); } false => { @@ -339,7 +325,7 @@ impl Interpreter { if line.contains(":") { branch_map.insert( label[0..label.len() - 1].to_string(), - (result.len() - 1) as u32, + (result.len() - 1) as u32 ); } } @@ -447,10 +433,7 @@ impl Interpreter { let value = self.get_reg(src_idx); self.set_reg(dest_idx, value); if self.debug { - println!( - "Mock: mov r{}, r{} (register to register)", - dest_idx, src_idx - ); + println!("Mock: mov r{}, r{} (register to register)", dest_idx, src_idx); } } } @@ -505,20 +488,14 @@ impl Interpreter { let src_val: i32; if let Some(src_str) = src.strip_prefix('r') { - let src_register = src_str - .replace("r", "") - .parse() - .expect("Unable to parse register"); + let src_register = src_str.replace("r", "").parse().expect("Unable to parse register"); src_val = self.get_reg(src_register); } else { src_val = self.memory.get_sp() as i32; } if let Some(dst_str) = dest.strip_prefix('r') { - let dst_register = dst_str - .replace("r", "") - .parse() - .expect("Unable to parse register"); + let dst_register = dst_str.replace("r", "").parse().expect("Unable to parse register"); let result = src_val - sub_value; self.set_reg(dst_register, result); } else if src == "sp" { @@ -532,9 +509,7 @@ impl Interpreter { } let parts: Vec<&str> = content.split_whitespace().collect(); let dest_reg = parts[1].replace(",", ""); - let dest_idx: usize = dest_reg[1..] - .parse() - .expect("Failed to parse register index"); + let dest_idx: usize = dest_reg[1..].parse().expect("Failed to parse register index"); let value = self.get_reg(dest_idx); let addr_part = content @@ -563,7 +538,7 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - let effective_addr = (base_addr as i32 + offset) as usize; + let effective_addr = ((base_addr as i32) + offset) as usize; self.memory.write_stack32_at(effective_addr, value as u32); if self.debug { @@ -610,10 +585,7 @@ impl Interpreter { self.set_reg(dest_idx, addr as i32); label_found = true; if self.debug { - println!( - "Loaded label address {} for {} into r{}", - addr, label, dest_idx - ); + println!("Loaded label address {} for {} into r{}", addr, label, dest_idx); } } } @@ -623,10 +595,7 @@ impl Interpreter { self.set_reg(dest_idx, addr as i32); label_found = true; if self.debug { - println!( - "Loaded label address {} for num_buf into r{}", - addr, dest_idx - ); + println!("Loaded label address {} for num_buf into r{}", addr, dest_idx); } } } @@ -635,10 +604,7 @@ impl Interpreter { if let Some(&addr) = self.data_map.get("newline") { self.set_reg(dest_idx, addr as i32); if self.debug { - println!( - "Loaded label address {} for newline into r{}", - addr, dest_idx - ); + println!("Loaded label address {} for newline into r{}", addr, dest_idx); } } } @@ -681,24 +647,19 @@ impl Interpreter { if base_reg_name == "sp" { base_addr = self.memory.get_sp(); } else if let Some(reg_num) = base_reg_name.strip_prefix('r') { - let reg_idx: usize = reg_num - .parse() - .expect("Failed to parse base register index"); + let reg_idx: usize = reg_num.parse().expect("Failed to parse base register index"); base_addr = self.get_reg(reg_idx) as usize; } // 6. Calculate the effective address - let effective_addr = (base_addr as i32 + offset) as usize; + let effective_addr = ((base_addr as i32) + offset) as usize; // 7. Load the value from memory and update the register let value = self.memory.read_stack32_at(effective_addr); self.set_reg(dest_idx, value as i32); if self.debug { - println!( - "Loaded value {} from address {} into r{}", - value, effective_addr, dest_idx - ); + println!("Loaded value {} from address {} into r{}", value, effective_addr, dest_idx); } } @@ -708,7 +669,7 @@ impl Interpreter { } let parts: Vec<&str> = content - .split(|c: char| c == ',' || c.is_whitespace()) + .split(|c: char| (c == ',' || c.is_whitespace())) .filter(|s| !s.is_empty()) .collect(); @@ -725,7 +686,7 @@ impl Interpreter { let rm_idx: usize = parts[2][1..].parse().expect("Failed to parse Rm index"); self.get_reg(rm_idx) }; - let result = (val_n).wrapping_sub(val_op2); + let result = val_n.wrapping_sub(val_op2); self.cpsr.z = result == 0; self.cpsr.n = result < 0; @@ -737,7 +698,13 @@ impl Interpreter { if self.debug { println!( "CMP Result: {:#x} - {:#x} = {:#x} | Flags: N:{} Z:{} C:{} V:{}", - val_n, val_op2, result, self.cpsr.n, self.cpsr.z, self.cpsr.c, self.cpsr.v + val_n, + val_op2, + result, + self.cpsr.n, + self.cpsr.z, + self.cpsr.c, + self.cpsr.v ); } } @@ -787,11 +754,7 @@ impl Interpreter { let op1 = parts[2].replace(",", ""); let op2 = parts[3].replace(",", ""); - let dest_idx: usize = if dest == "sp" { - 13 - } else { - dest[1..].parse().unwrap() - }; + let dest_idx: usize = if dest == "sp" { 13 } else { dest[1..].parse().unwrap() }; let src_val: i32 = if op1 == "sp" { self.memory.get_sp() as i32 @@ -803,11 +766,7 @@ impl Interpreter { let value = if let Some(imm) = op2.strip_prefix('#') { imm.parse::().unwrap() } else { - let reg_idx: usize = if op2 == "sp" { - 13 - } else { - op2[1..].parse().unwrap() - }; + let reg_idx: usize = if op2 == "sp" { 13 } else { op2[1..].parse().unwrap() }; self.get_reg(reg_idx) }; @@ -875,9 +834,7 @@ impl Interpreter { } let parts: Vec<&str> = content.split_whitespace().collect(); let src_reg = parts[1].replace(",", ""); - let src_idx: usize = src_reg[1..] - .parse() - .expect("Failed to parse register index"); + let src_idx: usize = src_reg[1..].parse().expect("Failed to parse register index"); let value = self.get_reg(src_idx) as u8; let addr_part = content @@ -906,7 +863,7 @@ impl Interpreter { base_addr = self.get_reg(reg_idx) as usize; } - let effective_addr = (base_addr as i32 + offset) as usize; + let effective_addr = ((base_addr as i32) + offset) as usize; if effective_addr < self.memory.heap.len() { self.memory.heap[effective_addr] = value; @@ -928,7 +885,7 @@ impl Interpreter { } if self.start_time.elapsed().as_nanos() > self.max_time.as_nanos() { println!("Detected Infinite Loop"); - exit(88) + exit(88); } if !self.cpsr.should_execute() { if self.debug { @@ -941,7 +898,7 @@ impl Interpreter { f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { if let Some(exit_code) = self.exec_svc(instruction.clone()) { - return (exit_code as u32) & 0xFF; + return (exit_code as u32) & 0xff; } } f if f.starts_with("sub") => self.exec_sub(instruction.clone()), @@ -1008,10 +965,7 @@ mod tests { assert!(status.success(), "Linker failed for {}", asm_path); // Run in qemu - let status = Command::new("qemu-arm") - .arg(&bin) - .status() - .expect("Failed to run qemu"); + let status = Command::new("qemu-arm").arg(&bin).status().expect("Failed to run qemu"); status.code().unwrap_or(-1) } @@ -1132,7 +1086,7 @@ mod tests { interp.file = vec![ "_start:".to_string(), " mov r0, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let start_block = interp.get_start(); @@ -1148,7 +1102,7 @@ mod tests { "_start:".to_string(), " mov r0, #10".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let exit_code = interp.execute(); @@ -1167,7 +1121,7 @@ mod tests { " ldr r1, [sp]".to_string(), " mov r0, r1".to_string(), " mov r7, #1".to_string(), - " svc #0".to_string(), + " svc #0".to_string() ]; let exit_code = interp.execute(); @@ -1190,14 +1144,8 @@ mod tests { interp.set_reg(1, 50); interp.exec_cmp("cmp r1, #100".to_string()); assert!(!interp.cpsr.z, "Z should be false when not equal"); - assert!( - interp.cpsr.n, - "N should be true because 50 - 100 is negative" - ); - assert!( - !interp.cpsr.c, - "C should be false because 50 < 100 (borrow occurred)" - ); + assert!(interp.cpsr.n, "N should be true because 50 - 100 is negative"); + assert!(!interp.cpsr.c, "C should be false because 50 < 100 (borrow occurred)"); // 3. Test Greater Than (Positive result) interp.set_reg(1, 200); @@ -1211,13 +1159,10 @@ mod tests { // too big for 32-bit signed integer (wraps around) interp.set_reg(1, 0x7fffffff); // Max Positive i32 interp.set_reg(2, -1); // -1 in two's complement - // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) + // Math: 0x7FFFFFFF - (-1) = 0x80000000 (which is -2147483648 in signed) interp.exec_cmp("cmp r1, r2".to_string()); assert!(interp.cpsr.v, "V should be true due to signed overflow"); - assert!( - interp.cpsr.n, - "N should be true because result wrapped to 0x80000000" - ); + assert!(interp.cpsr.n, "N should be true because result wrapped to 0x80000000"); } #[test] fn test_it_block_execution_logic() { @@ -1246,10 +1191,7 @@ mod tests { // Test Instruction 2 (E) let should_run_2 = interp.cpsr.should_execute(); - assert!( - !should_run_2, - "Instruction 2 (E) should NOT run when GT is true" - ); + assert!(!should_run_2, "Instruction 2 (E) should NOT run when GT is true"); assert_eq!(interp.cpsr.it_state.current_instr, 2); // 3. Reset and Scenario B: Condition is FALSE (R1 < R0) @@ -1262,17 +1204,11 @@ mod tests { // Test Instruction 1 (T) let should_run_1_f = interp.cpsr.should_execute(); - assert!( - !should_run_1_f, - "Instruction 1 (T) should NOT run when GT is false" - ); + assert!(!should_run_1_f, "Instruction 1 (T) should NOT run when GT is false"); // Test Instruction 2 (E) let should_run_2_f = interp.cpsr.should_execute(); - assert!( - should_run_2_f, - "Instruction 2 (E) SHOULD run when GT is false (Else case)" - ); + assert!(should_run_2_f, "Instruction 2 (E) SHOULD run when GT is false (Else case)"); // Verify block auto-deactivates assert!( From bef7441ac2c4ae684773e18944d78707d6cc5c11 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Mon, 16 Mar 2026 15:43:37 +0100 Subject: [PATCH 26/34] Pure Python Experimentation Setup, gotta do something else that that is slow (in future for now is fine i thinkets --- .gitignore | 1 + interpreter/src/interpreter.rs | 3 +- .../compiled_test_files/simple.asm | 76 ---- .../compiled_test_files/simple.hard.asm | 134 ------- testing/1-20260313_104334/tests/simple.trv | 22 -- .../1-20260313_104334/tests/simple.trv.output | 1 - .../compiled_test_files/simple.asm | 76 ---- .../compiled_test_files/simple.hard.asm | 134 ------- testing/2-20260313_125959/tests/simple.trv | 22 -- .../2-20260313_125959/tests/simple.trv.output | 1 - testing/config.toml | 5 + testing/fissc/crt-rsa.trv.output | 1 + testing/requirements.txt | 1 + .../__pycache__/testrunner.cpython-314.pyc | Bin 10832 -> 17485 bytes testing/src/testrunner.py | 328 ++++++++++++++---- 15 files changed, 276 insertions(+), 529 deletions(-) delete mode 100644 testing/1-20260313_104334/compiled_test_files/simple.asm delete mode 100644 testing/1-20260313_104334/compiled_test_files/simple.hard.asm delete mode 100644 testing/1-20260313_104334/tests/simple.trv delete mode 100644 testing/1-20260313_104334/tests/simple.trv.output delete mode 100644 testing/2-20260313_125959/compiled_test_files/simple.asm delete mode 100644 testing/2-20260313_125959/compiled_test_files/simple.hard.asm delete mode 100644 testing/2-20260313_125959/tests/simple.trv delete mode 100644 testing/2-20260313_125959/tests/simple.trv.output create mode 100644 testing/fissc/crt-rsa.trv.output diff --git a/.gitignore b/.gitignore index ac53c9d..0da23e0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ /testing/bin /testing/artifacts /testing/src/__pycache__ +/testing/fa diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 8084268..b733d83 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -6,7 +6,8 @@ use std::usize; use crate::memory::EmulatorMemory; -const NUM_REGISTERS: usize = 32; +const NUM_REGISTERS: usize = 13; //FIXME: Find out if num registers is 13 (r0-r12) plsssss +//FIXME: Also find out what to do with sp, lr, apsr, cpsr #[derive(Clone, Debug, PartialEq, Default)] pub struct ItState { diff --git a/testing/1-20260313_104334/compiled_test_files/simple.asm b/testing/1-20260313_104334/compiled_test_files/simple.asm deleted file mode 100644 index 7116286..0000000 --- a/testing/1-20260313_104334/compiled_test_files/simple.asm +++ /dev/null @@ -1,76 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] -while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - ldr r0, [sp, #8] - mov r1, r0 - ldr r0, [sp, #0] - add r0, r1, r0 - str r0, [sp, #8] - add sp, sp, #4 - b while_0 -end_while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq else_1 - mov r0, #12 - str r0, [sp, #4] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add sp, sp, #4 - b endif_1 -else_1: - mov r0, #11 - str r0, [sp, #4] -endif_1: - ldr r0, [sp, #0] - mov r1, r0 - mov r0, #1 - cmp r1, r0 - mov r0, #0 - it ne - movne r0, #1 - cmp r0, #0 - beq else_2 - ldr r0, [sp, #0] - mov r7, #1 - svc #0 - b endif_2 -else_2: - ldr r0, [sp, #4] - mov r7, #1 - svc #0 -endif_2: - add sp, sp, #8 - -.size _start, .-_start diff --git a/testing/1-20260313_104334/compiled_test_files/simple.hard.asm b/testing/1-20260313_104334/compiled_test_files/simple.hard.asm deleted file mode 100644 index b540827..0000000 --- a/testing/1-20260313_104334/compiled_test_files/simple.hard.asm +++ /dev/null @@ -1,134 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - mov r9, #0 - mov r10, #1 - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 -while_0: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #8] - mov r1, r0 - ldr r0, [sp, #0] - add r0, r1, r0 - str r0, [sp, #8] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - add sp, sp, #4 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - b while_0 -end_while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq else_1 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - mov r0, #12 - str r0, [sp, #4] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - add sp, sp, #4 - b endif_1 -else_1: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - mov r0, #11 - str r0, [sp, #4] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 -endif_1: - ldr r0, [sp, #0] - mov r1, r0 - mov r0, #1 - cmp r1, r0 - mov r0, #0 - it ne - movne r0, #1 - cmp r0, #0 - beq else_2 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #0] - mov r7, #1 - svc #0 - b endif_2 -else_2: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #4] - mov r7, #1 - svc #0 -endif_2: - add sp, sp, #8 -countermeasure: - mov r0, #77 - mov r7, #1 - svc #0 - -.size _start, .-_start diff --git a/testing/1-20260313_104334/tests/simple.trv b/testing/1-20260313_104334/tests/simple.trv deleted file mode 100644 index 0205385..0000000 --- a/testing/1-20260313_104334/tests/simple.trv +++ /dev/null @@ -1,22 +0,0 @@ -func main() -> Boolean { - let num : Integer = 0; - let test : Boolean = True; - - while num < 10 do { - let etellerandet : Integer = 1; - num = num + etellerandet; - } - - if num > 10 { - num = 12; - let dingdong : Integer = 0; - } else { - num = 11; - } - - if test != True { - return test; - } else { - return num; - } -} diff --git a/testing/1-20260313_104334/tests/simple.trv.output b/testing/1-20260313_104334/tests/simple.trv.output deleted file mode 100644 index b4de394..0000000 --- a/testing/1-20260313_104334/tests/simple.trv.output +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/testing/2-20260313_125959/compiled_test_files/simple.asm b/testing/2-20260313_125959/compiled_test_files/simple.asm deleted file mode 100644 index 7116286..0000000 --- a/testing/2-20260313_125959/compiled_test_files/simple.asm +++ /dev/null @@ -1,76 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] -while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - ldr r0, [sp, #8] - mov r1, r0 - ldr r0, [sp, #0] - add r0, r1, r0 - str r0, [sp, #8] - add sp, sp, #4 - b while_0 -end_while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq else_1 - mov r0, #12 - str r0, [sp, #4] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add sp, sp, #4 - b endif_1 -else_1: - mov r0, #11 - str r0, [sp, #4] -endif_1: - ldr r0, [sp, #0] - mov r1, r0 - mov r0, #1 - cmp r1, r0 - mov r0, #0 - it ne - movne r0, #1 - cmp r0, #0 - beq else_2 - ldr r0, [sp, #0] - mov r7, #1 - svc #0 - b endif_2 -else_2: - ldr r0, [sp, #4] - mov r7, #1 - svc #0 -endif_2: - add sp, sp, #8 - -.size _start, .-_start diff --git a/testing/2-20260313_125959/compiled_test_files/simple.hard.asm b/testing/2-20260313_125959/compiled_test_files/simple.hard.asm deleted file mode 100644 index b540827..0000000 --- a/testing/2-20260313_125959/compiled_test_files/simple.hard.asm +++ /dev/null @@ -1,134 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - mov r9, #0 - mov r10, #1 - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 -while_0: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - sub sp, sp, #4 - mov r0, #1 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #8] - mov r1, r0 - ldr r0, [sp, #0] - add r0, r1, r0 - str r0, [sp, #8] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - add sp, sp, #4 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - b while_0 -end_while_0: - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #10 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq else_1 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - mov r0, #12 - str r0, [sp, #4] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - add sp, sp, #4 - b endif_1 -else_1: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - mov r0, #11 - str r0, [sp, #4] - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 -endif_1: - ldr r0, [sp, #0] - mov r1, r0 - mov r0, #1 - cmp r1, r0 - mov r0, #0 - it ne - movne r0, #1 - cmp r0, #0 - beq else_2 - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #0] - mov r7, #1 - svc #0 - b endif_2 -else_2: - add r9, r9, #1 - cmp r9, r10 - bne countermeasure - add r10, r10, #1 - ldr r0, [sp, #4] - mov r7, #1 - svc #0 -endif_2: - add sp, sp, #8 -countermeasure: - mov r0, #77 - mov r7, #1 - svc #0 - -.size _start, .-_start diff --git a/testing/2-20260313_125959/tests/simple.trv b/testing/2-20260313_125959/tests/simple.trv deleted file mode 100644 index 0205385..0000000 --- a/testing/2-20260313_125959/tests/simple.trv +++ /dev/null @@ -1,22 +0,0 @@ -func main() -> Boolean { - let num : Integer = 0; - let test : Boolean = True; - - while num < 10 do { - let etellerandet : Integer = 1; - num = num + etellerandet; - } - - if num > 10 { - num = 12; - let dingdong : Integer = 0; - } else { - num = 11; - } - - if test != True { - return test; - } else { - return num; - } -} diff --git a/testing/2-20260313_125959/tests/simple.trv.output b/testing/2-20260313_125959/tests/simple.trv.output deleted file mode 100644 index b4de394..0000000 --- a/testing/2-20260313_125959/tests/simple.trv.output +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/testing/config.toml b/testing/config.toml index e3928fe..48889b3 100644 --- a/testing/config.toml +++ b/testing/config.toml @@ -1 +1,6 @@ tests_folder = "tests" +fissc_folder = "fissc" +modeled_registers = [ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12" +] \ No newline at end of file diff --git a/testing/fissc/crt-rsa.trv.output b/testing/fissc/crt-rsa.trv.output new file mode 100644 index 0000000..fa1bddf --- /dev/null +++ b/testing/fissc/crt-rsa.trv.output @@ -0,0 +1 @@ +1337 \ No newline at end of file diff --git a/testing/requirements.txt b/testing/requirements.txt index bd79a65..90df715 100644 --- a/testing/requirements.txt +++ b/testing/requirements.txt @@ -1 +1,2 @@ toml +tqdm \ No newline at end of file diff --git a/testing/src/__pycache__/testrunner.cpython-314.pyc b/testing/src/__pycache__/testrunner.cpython-314.pyc index 9f11c20e8bf9c715fb91315211a50297fef85010..48a2f6c63067eb70a9f244762997726c89cf2b8f 100644 GIT binary patch delta 8617 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: + for pc in range(1, max_pc): + for bit in range( + 1, 32 + ): # TODO: Find ud af om den skal hedde 33 eller 32, ændrede til 32 selvom chatten mente 33 + injection_points.append(f"pc:{pc}:{bit}") + + # reg faults: reg::: + for pc in range(1, max_pc): + for reg in range(13): + for bit in range(1, 33): + injection_points.append(f"reg:{pc}:{reg}:{bit}") + + return injection_points + + def _run_fault_campaign(self, test_name, variant, asm_path, expected_output): + injection_points = self._generate_injection_points(asm_path) + + cpu_count = multiprocessing.cpu_count() + print(f" Using {cpu_count} workers") + + results = [] + + tasks = [ + (asm_path, injection_point, expected_output) + for injection_point in injection_points + ] + + with concurrent.futures.ProcessPoolExecutor(max_workers=cpu_count) as executor: + for res in tqdm( + executor.map(_fault_worker, tasks, chunksize=50), + total=len(tasks), + desc="Fault Injection", + ): + res["test"] = test_name + res["variant"] = variant + results.append(res) + + return results + + def _write_fault_results_csv(self, rows, output_path): + fieldnames = [ + "test", + "variant", + "injection_point", + "returncode", + "stdout", + "stderr", + "expected_output", + "passed", + ] + + with open(output_path, "w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + writer.writerows(rows) + def compile(self): results = [] for test in self.tests: - test_result = {'name': test['name'], 'normal': None, 'hard': None} - + test_result = {"name": test["name"], "normal": None, "hard": None} + for hard in [False, True]: hard_str = "hard" if hard else "normal" - success, asm_path, stdout, stderr = self.compile_test(test, hard, self.compiled_folder) - test_result[hard_str] = {'success': success, 'asm_path': asm_path, 'stdout': stdout, 'stderr': stderr} - + success, asm_path, stdout, stderr = self.compile_test( + test, hard, self.compiled_folder + ) + test_result[hard_str] = { + "success": success, + "asm_path": asm_path, + "stdout": stdout, + "stderr": stderr, + } + results.append(test_result) - + self.compile_results = results return results - + def run_tests(self): - if not hasattr(self, 'run_folder'): + if not hasattr(self, "run_folder"): self.setup() - - results = self.compile() - - for test, result in zip(self.tests, results): + + if self.compile_results is None: + self.compile() + + all_fault_results = [] + + for test, result in zip(self.tests, self.compile_results): print(f"Test: {test['name']}") - + for hard in [False, True]: hard_str = "hard" if hard else "normal" res = result[hard_str] - if res['success']: - print(f" Compiled ({hard_str}) successfully") - else: - print(f" Compilation failed ({hard_str}):") - if res['stdout']: + + if not res["success"]: + print(f" Compilation failed ({hard_str})") + if res["stdout"]: print(f" stdout: {res['stdout']}") - if res['stderr']: + if res["stderr"]: print(f" stderr: {res['stderr']}") - - print(f" Expected output: {test['expected_output']}") - + continue + + asm_path = res["asm_path"] + max_pc = self._get_program_max_pc(asm_path) + injection_points = self._generate_injection_points(asm_path) + + print(f" Compiled ({hard_str}) successfully") + print(f" ASM path: {asm_path}") + print(f" Max PC: {max_pc}") + print(f" Fault runs to execute: {len(injection_points)}") + + fault_results = self._run_fault_campaign( + test_name=test["name"], + variant=hard_str, + asm_path=asm_path, + expected_output=test["expected_output"], + ) + + all_fault_results.extend(fault_results) + + csv_path = os.path.join(self.run_folder, "fault_results.csv") + self._write_fault_results_csv(all_fault_results, csv_path) + zip_base = os.path.join(self.artifacts_folder, self.run_folder_name) - shutil.make_archive(zip_base, 'zip', self.artifacts_folder, self.run_folder_name) + shutil.make_archive( + zip_base, "zip", self.artifacts_folder, self.run_folder_name + ) shutil.rmtree(self.run_folder) - + print(f"\nArtifacts saved to: {zip_base}.zip") if __name__ == "__main__": runner = TestRunner() - + print(f"Running test runner") print(f"Found {len(runner.tests)} tests") runner.run_tests() From 8b409b1c14e467e826b6c975d5d69e30e68e2f16 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 20 Mar 2026 11:10:36 +0100 Subject: [PATCH 27/34] added minimc as submodule --- .gitmodules | 3 +++ minimc | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 minimc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d849f24 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "minimc"] + path = minimc + url = https://github.com/dannybpoulsen/minimc diff --git a/minimc b/minimc new file mode 160000 index 0000000..e496b90 --- /dev/null +++ b/minimc @@ -0,0 +1 @@ +Subproject commit e496b903866a93436f561834e375197b68e16511 From a108d7a597e9cec28dd406cd44b5d03df084aae5 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 20 Mar 2026 12:02:29 +0100 Subject: [PATCH 28/34] changed to sqlite3 output! --- .gitignore | 1 - testing/config.toml | 14 ++- testing/fissc/crt-rsa.trv.output | 2 +- .../src/__pycache__/testing.cpython-314.pyc | Bin 3341 -> 0 bytes .../__pycache__/testrunner.cpython-314.pyc | Bin 17485 -> 0 bytes testing/src/database.py | 105 ++++++++++++++++ testing/src/testrunner.py | 113 ++++++++++++------ testing/test | 3 +- 8 files changed, 193 insertions(+), 45 deletions(-) delete mode 100644 testing/src/__pycache__/testing.cpython-314.pyc delete mode 100644 testing/src/__pycache__/testrunner.cpython-314.pyc create mode 100644 testing/src/database.py diff --git a/.gitignore b/.gitignore index 0da23e0..ac53c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ /testing/bin /testing/artifacts /testing/src/__pycache__ -/testing/fa diff --git a/testing/config.toml b/testing/config.toml index 48889b3..c24cb8b 100644 --- a/testing/config.toml +++ b/testing/config.toml @@ -1,6 +1,14 @@ -tests_folder = "tests" -fissc_folder = "fissc" +tests_folder = "fissc" modeled_registers = [ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" -] \ No newline at end of file +] + +[pass_mode] +default = "stdout" + +[pass_mode.returncode] +expected = 0 + +[pass_mode.stdout] +expected = "g_sign = 11254" diff --git a/testing/fissc/crt-rsa.trv.output b/testing/fissc/crt-rsa.trv.output index fa1bddf..cfeff4a 100644 --- a/testing/fissc/crt-rsa.trv.output +++ b/testing/fissc/crt-rsa.trv.output @@ -1 +1 @@ -1337 \ No newline at end of file +11254 diff --git a/testing/src/__pycache__/testing.cpython-314.pyc b/testing/src/__pycache__/testing.cpython-314.pyc deleted file mode 100644 index 845a02a109113c768b9d5b0e607fbef62bfd01d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3341 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 diff --git a/testing/src/database.py b/testing/src/database.py new file mode 100644 index 0000000..168ff99 --- /dev/null +++ b/testing/src/database.py @@ -0,0 +1,105 @@ +import sqlite3 +from datetime import datetime + + +class ResultsDatabase: + SCHEMA = """ + CREATE TABLE IF NOT EXISTS runs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + run_number INTEGER NOT NULL, + timestamp TEXT NOT NULL, + tests_folder TEXT, + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ); + + CREATE TABLE IF NOT EXISTS test_results ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + run_id INTEGER NOT NULL, + test TEXT NOT NULL, + variant TEXT NOT NULL, + injection_point TEXT NOT NULL, + fault_type TEXT, + fault_pc INTEGER, + fault_reg INTEGER, + fault_bit INTEGER, + returncode INTEGER NOT NULL, + stdout TEXT, + stderr TEXT, + expected_output TEXT NOT NULL, + passed INTEGER NOT NULL, + FOREIGN KEY (run_id) REFERENCES runs(id) + ); + + CREATE INDEX IF NOT EXISTS idx_test_results_run_id ON test_results(run_id); + CREATE INDEX IF NOT EXISTS idx_test_results_test ON test_results(test); + CREATE INDEX IF NOT EXISTS idx_test_results_variant ON test_results(variant); + CREATE INDEX IF NOT EXISTS idx_test_results_passed ON test_results(passed); + """ + + def __init__(self, db_path): + self.db_path = db_path + self._conn = None + self._init_db() + + def _init_db(self): + self._conn = sqlite3.connect(self.db_path) + self._conn.executescript(self.SCHEMA) + self._conn.commit() + + def close(self): + if self._conn: + self._conn.close() + self._conn = None + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + def create_run(self, run_number, tests_folder=None): + timestamp = datetime.now().isoformat() + cursor = self._conn.execute( + "INSERT INTO runs (run_number, timestamp, tests_folder) VALUES (?, ?, ?)", + (run_number, timestamp, tests_folder), + ) + self._conn.commit() + return cursor.lastrowid + + def insert_results_batch(self, run_id, results): + rows = [] + for res in results: + parts = res["injection_point"].split(":") + if parts[0] == "pc": + fault_type, fault_pc, fault_reg, fault_bit = ("pc", int(parts[1]), None, int(parts[2])) + elif parts[0] == "reg": + fault_type, fault_pc, fault_reg, fault_bit = ("reg", int(parts[1]), int(parts[2]), int(parts[3])) + else: + fault_type, fault_pc, fault_reg, fault_bit = (None, None, None, None) + + rows.append(( + run_id, + res["test"], + res["variant"], + res["injection_point"], + fault_type, + fault_pc, + fault_reg, + fault_bit, + res["returncode"], + res["stdout"], + res["stderr"], + res["expected_output"], + int(res["passed"]), + )) + + self._conn.executemany( + """ + INSERT INTO test_results + (run_id, test, variant, injection_point, fault_type, fault_pc, fault_reg, fault_bit, + returncode, stdout, stderr, expected_output, passed) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + rows, + ) + self._conn.commit() diff --git a/testing/src/testrunner.py b/testing/src/testrunner.py index 0837a36..ad8a452 100644 --- a/testing/src/testrunner.py +++ b/testing/src/testrunner.py @@ -8,10 +8,11 @@ import concurrent.futures import multiprocessing from tqdm import tqdm +from src.database import ResultsDatabase def _fault_worker(args): - asm_path, injection_point, expected_output = args + asm_path, injection_point, pass_mode_config = args bin_dir = os.path.join(os.path.dirname(__file__), "..", "bin") interpreter_path = os.path.join(bin_dir, "interpreter") @@ -20,19 +21,30 @@ def _fault_worker(args): result = subprocess.run(cmd, cwd=bin_dir, capture_output=True, text=True) - observed = str(result.returncode) - passed = observed == expected_output + passed = _check_passed(result, pass_mode_config) return { "injection_point": injection_point, "returncode": result.returncode, "stdout": result.stdout.strip(), "stderr": result.stderr.strip(), - "expected_output": expected_output, + "expected_output": pass_mode_config.get("expected", ""), "passed": passed, } +def _check_passed(result, pass_mode_config): + mode = pass_mode_config.get("mode", "returncode") + expected = pass_mode_config.get("expected", 0) + + if mode == "returncode": + return result.returncode == expected + elif mode == "stdout": + return expected in result.stdout + else: + raise ValueError(f"Unknown pass mode: {mode}") + + class TestRunner: def __init__(self, config_path=None): if config_path is None: @@ -64,6 +76,8 @@ def __init__(self, config_path=None): "r12", ], ) + self.default_pass_mode = config.get("pass_mode", {}).get("default", "returncode") + self.pass_mode_configs = config.get("pass_mode", {}) self.tests = self._discover_tests() self.compile_results = None @@ -78,24 +92,53 @@ def _discover_tests(self): for trv_file in trv_files: test_name = trv_file[:-4] output_file = trv_file + ".output" + toml_file = trv_file + ".toml" - if output_file in files: - trv_path = os.path.join(self.tests_folder, trv_file) - output_path = os.path.join(self.tests_folder, output_file) + if output_file not in files: + continue - with open(output_path, "r") as f: - expected_output = f.read().strip() + trv_path = os.path.join(self.tests_folder, trv_file) + output_path = os.path.join(self.tests_folder, output_file) - tests.append( - { - "name": test_name, - "path": trv_path, - "expected_output": expected_output, - } - ) + with open(output_path, "r") as f: + expected_output = f.read().strip() + + pass_mode_config = self._load_pass_mode_config(test_name, trv_file, files) + + tests.append( + { + "name": test_name, + "path": trv_path, + "expected_output": expected_output, + "pass_mode": pass_mode_config, + } + ) return tests + def _load_pass_mode_config(self, test_name, trv_file, files): + toml_file = trv_file + ".toml" + + if toml_file in files: + toml_path = os.path.join(self.tests_folder, toml_file) + with open(toml_path, "r") as f: + test_config = toml.load(f) + pass_mode = test_config.get("pass_mode", {}) + if "mode" in pass_mode: + mode = pass_mode["mode"] + mode_config = self.pass_mode_configs.get(mode, {}) + return { + "mode": mode, + "expected": pass_mode.get("expected", mode_config.get("expected", 0)), + } + + mode = self.default_pass_mode + mode_config = self.pass_mode_configs.get(mode, {}) + return { + "mode": mode, + "expected": mode_config.get("expected", 0), + } + def check_bin(self): from pathlib import Path @@ -185,6 +228,7 @@ def setup(self): self.run_folder = os.path.join(self.artifacts_folder, self.run_folder_name) self.run_tests_folder = os.path.join(self.run_folder, "tests") self.compiled_folder = os.path.join(self.run_folder, "compiled_test_files") + self.db_path = os.path.join(self.run_folder, "results.db") os.makedirs(self.run_folder, exist_ok=True) os.makedirs(self.run_tests_folder, exist_ok=True) @@ -194,6 +238,9 @@ def setup(self): if f.endswith(".trv") or f.endswith(".trv.output"): shutil.copy(os.path.join(self.tests_folder, f), self.run_tests_folder) + self.db = ResultsDatabase(self.db_path) + self.run_id = self.db.create_run(run_num, self.tests_folder) + return self.run_folder def _get_program_max_pc(self, asm_path): @@ -254,16 +301,20 @@ def _generate_injection_points(self, asm_path): return injection_points - def _run_fault_campaign(self, test_name, variant, asm_path, expected_output): + def _run_fault_campaign(self, test_name, variant, asm_path, pass_mode_config, limit=None): injection_points = self._generate_injection_points(asm_path) + if limit is not None and len(injection_points) > limit: + injection_points = injection_points[:limit] + print(f" Limited to {limit} injection points") + cpu_count = multiprocessing.cpu_count() print(f" Using {cpu_count} workers") results = [] tasks = [ - (asm_path, injection_point, expected_output) + (asm_path, injection_point, pass_mode_config) for injection_point in injection_points ] @@ -279,23 +330,6 @@ def _run_fault_campaign(self, test_name, variant, asm_path, expected_output): return results - def _write_fault_results_csv(self, rows, output_path): - fieldnames = [ - "test", - "variant", - "injection_point", - "returncode", - "stdout", - "stderr", - "expected_output", - "passed", - ] - - with open(output_path, "w", newline="") as f: - writer = csv.DictWriter(f, fieldnames=fieldnames) - writer.writeheader() - writer.writerows(rows) - def compile(self): results = [] for test in self.tests: @@ -317,7 +351,7 @@ def compile(self): self.compile_results = results return results - def run_tests(self): + def run_tests(self, limit=None): if not hasattr(self, "run_folder"): self.setup() @@ -354,13 +388,14 @@ def run_tests(self): test_name=test["name"], variant=hard_str, asm_path=asm_path, - expected_output=test["expected_output"], + pass_mode_config=test["pass_mode"], + limit=limit, ) all_fault_results.extend(fault_results) - csv_path = os.path.join(self.run_folder, "fault_results.csv") - self._write_fault_results_csv(all_fault_results, csv_path) + self.db.insert_results_batch(self.run_id, all_fault_results) + self.db.close() zip_base = os.path.join(self.artifacts_folder, self.run_folder_name) shutil.make_archive( diff --git a/testing/test b/testing/test index 65aae71..1ab589c 100755 --- a/testing/test +++ b/testing/test @@ -8,6 +8,7 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument('--config', type=str, default=None, help='Path to config.toml') parser.add_argument('--skip-run', action='store_true', help='Only setup and compile, skip running tests') + parser.add_argument('--limit', type=int, default=None, help='Limit number of injection points to test') args = parser.parse_args() runner = TestRunner(config_path=args.config) @@ -25,7 +26,7 @@ def main(): if not args.skip_run: print(f"\nRunning tests...") - runner.run_tests() + runner.run_tests(limit=args.limit) else: print(f"\nSkipping test run (--skip-run)") From a198498a0a853fe55428930d9413e5fd1b6b61d7 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Tue, 24 Mar 2026 14:07:28 +0100 Subject: [PATCH 29/34] fdjlsa --- compiler/vpin/VerifyPIN_0/Makefile | 26 + compiler/vpin/VerifyPIN_0/src/code.c | 58 ++ compiler/vpin/VerifyPIN_0/src/commons.h | 26 + .../vpin/VerifyPIN_0/src/countermeasure.c | 27 + compiler/vpin/VerifyPIN_0/src/initialize.c | 48 ++ compiler/vpin/VerifyPIN_0/src/main.c | 50 ++ compiler/vpin/VerifyPIN_0/src/oracle.c | 45 ++ compiler/vpin/crt-rsa.asm | 498 ++++++++++++++++++ {testing/fissc => compiler/vpin}/crt-rsa.trv | 0 compiler/vpin/out.asm | 276 ++++++++++ compiler/vpin/share/interface.h | 49 ++ compiler/vpin/share/lazart.h | 21 + compiler/vpin/share/types.h | 29 + compiler/vpin/verifypin.asm | 282 ++++++++++ compiler/vpin/verifypin.trv | 46 ++ testing/config.toml | 6 +- testing/fissc/disabled/crt-rsa.trv | 121 +++++ .../fissc/{ => disabled}/crt-rsa.trv.output | 0 testing/fissc/verifypin.trv | 46 ++ testing/fissc/verifypin.trv.output | 3 + testing/src/database.py | 6 +- testing/src/testrunner.py | 57 +- testing/test | 15 +- 23 files changed, 1720 insertions(+), 15 deletions(-) create mode 100755 compiler/vpin/VerifyPIN_0/Makefile create mode 100755 compiler/vpin/VerifyPIN_0/src/code.c create mode 100755 compiler/vpin/VerifyPIN_0/src/commons.h create mode 100755 compiler/vpin/VerifyPIN_0/src/countermeasure.c create mode 100755 compiler/vpin/VerifyPIN_0/src/initialize.c create mode 100755 compiler/vpin/VerifyPIN_0/src/main.c create mode 100755 compiler/vpin/VerifyPIN_0/src/oracle.c create mode 100644 compiler/vpin/crt-rsa.asm rename {testing/fissc => compiler/vpin}/crt-rsa.trv (100%) create mode 100644 compiler/vpin/out.asm create mode 100755 compiler/vpin/share/interface.h create mode 100755 compiler/vpin/share/lazart.h create mode 100755 compiler/vpin/share/types.h create mode 100644 compiler/vpin/verifypin.asm create mode 100644 compiler/vpin/verifypin.trv create mode 100644 testing/fissc/disabled/crt-rsa.trv rename testing/fissc/{ => disabled}/crt-rsa.trv.output (100%) create mode 100644 testing/fissc/verifypin.trv create mode 100644 testing/fissc/verifypin.trv.output diff --git a/compiler/vpin/VerifyPIN_0/Makefile b/compiler/vpin/VerifyPIN_0/Makefile new file mode 100755 index 0000000..094bf73 --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/Makefile @@ -0,0 +1,26 @@ +# Makefile script with commands to generate the benchmark assembly and binaries. +# Description of the targets: +# x86-ptc: produce lazart object files with oracle PTC +# x86-auth: produce lazart object files with oracle AUTH +# clean: clean generated files, including output binaries + +.PHONY: clean x86-ptc x86-auth + +TARGET = verifypin_0 +FILES = src/countermeasure.c src/initialize.c src/oracle.c src/code.c src/main.c + +INC_DIR = -I../share -Iinclude +BIN_DIR = bin + +CFLAGS = $(INC_DIR) -Wall -Wextra + +x86-auth: + @mkdir -p $(BIN_DIR) + @clang -DAUTH $(FILES) $(CFLAGS) -o $(BIN_DIR)/$(TARGET) + +x86-ptc: + @mkdir -p $(BIN_DIR) + @clang -DPTC $(FILES) $(CFLAGS) -o $(BIN_DIR)/$(TARGET) + +clean: + @rm -rf $(BIN_DIR) diff --git a/compiler/vpin/VerifyPIN_0/src/code.c b/compiler/vpin/VerifyPIN_0/src/code.c new file mode 100755 index 0000000..72553cd --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/code.c @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#include "interface.h" +#include "types.h" +#include "commons.h" + +extern SBYTE g_ptc; +extern BOOL g_authenticated; +extern UBYTE g_userPin[PIN_SIZE]; +extern UBYTE g_cardPin[PIN_SIZE]; + +#ifdef INLINE +__attribute__((always_inline)) inline BOOL byteArrayCompare(UBYTE* a1, UBYTE* a2, UBYTE size) +#else +BOOL byteArrayCompare(UBYTE* a1, UBYTE* a2, UBYTE size) +#endif +{ + int i; + for(i = 0; i < size; i++) { + if(a1[i] != a2[i]) { + return 0; + } + } + return 1; +} + +BOOL verifyPIN() { + g_authenticated = 0; + + if(g_ptc > 0) { + if(byteArrayCompare(g_userPin, g_cardPin, PIN_SIZE) == 1) { + g_ptc = 3; + g_authenticated = 1; // Authentication(); + return 1; + } else { + g_ptc--; + return 0; + } + } + + return 0; +} diff --git a/compiler/vpin/VerifyPIN_0/src/commons.h b/compiler/vpin/VerifyPIN_0/src/commons.h new file mode 100755 index 0000000..78ce18f --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/commons.h @@ -0,0 +1,26 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#ifndef H_COMMONS +#define H_COMMONS + +// macro definitions +#define INITIAL_VALUE 0x2a +#define PIN_SIZE 4 + +#endif // H_COMMONS diff --git a/compiler/vpin/VerifyPIN_0/src/countermeasure.c b/compiler/vpin/VerifyPIN_0/src/countermeasure.c new file mode 100755 index 0000000..3475fbf --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/countermeasure.c @@ -0,0 +1,27 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#include "interface.h" +#include "types.h" + +extern UBYTE g_countermeasure; + +void countermeasure() +{ + g_countermeasure = 1; +} diff --git a/compiler/vpin/VerifyPIN_0/src/initialize.c b/compiler/vpin/VerifyPIN_0/src/initialize.c new file mode 100755 index 0000000..50abcc9 --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/initialize.c @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#include "types.h" +#include "interface.h" +#include "commons.h" + +// global variables definition +BOOL g_authenticated; +SBYTE g_ptc; +UBYTE g_countermeasure; +UBYTE g_userPin[PIN_SIZE]; +UBYTE g_cardPin[PIN_SIZE]; + + +void initialize() +{ + // local variables + int i; + // global variables initialization + g_authenticated = 0; + g_ptc = 3; + g_countermeasure = 0; + // card PIN = 1 2 3 4 5... + for (i = 0; i < PIN_SIZE; ++i) { + g_cardPin[i] = i+1; + } + // user PIN = 0 0 0 0 0... + for (i = 0 ; i < PIN_SIZE; ++i) { + g_userPin[i] = 0; + } +} + diff --git a/compiler/vpin/VerifyPIN_0/src/main.c b/compiler/vpin/VerifyPIN_0/src/main.c new file mode 100755 index 0000000..159fb1c --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/main.c @@ -0,0 +1,50 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* You can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +/*$ + @name = VerifyPIN_0 + @feature = verifyPIN + @fault-model = test-inversion + @attack-scenario = oracle + @countermeasure = none + @maintainers = Etienne Boespflug, VERIMAG + @authors = Lionel Rivière, SERTIF Consortium + @version 2.2 +*/ + +#include + +#include "interface.h" +#include "types.h" +#include "lazart.h" + +extern UBYTE g_countermeasure; +extern BOOL g_authenticated; +extern SBYTE g_ptc; + +BOOL verifyPIN(void); + +int main() +{ + initialize(); + verifyPIN(); + LAZART_ORACLE(oracle()); + + printf("[@] g_countermeasure = %i, g_authenticated = %x, g_ptc = %i\n", g_countermeasure, g_authenticated, g_ptc); + return 0; +} diff --git a/compiler/vpin/VerifyPIN_0/src/oracle.c b/compiler/vpin/VerifyPIN_0/src/oracle.c new file mode 100755 index 0000000..72306cb --- /dev/null +++ b/compiler/vpin/VerifyPIN_0/src/oracle.c @@ -0,0 +1,45 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#include "interface.h" +#include "types.h" + +// define the oracle you want to use. +#ifdef AUTH +#define oracle_auth oracle +#endif + +#ifdef PTC +#define oracle_ptc oracle +#endif + +extern UBYTE g_countermeasure; +extern BOOL g_authenticated; +extern SBYTE g_ptc; + +BOOL oracle_auth() +{ + return g_countermeasure != 1 && g_authenticated == 1; +} + +BOOL oracle_ptc() +{ + return g_countermeasure != 1 && g_ptc >= 3; +} + + diff --git a/compiler/vpin/crt-rsa.asm b/compiler/vpin/crt-rsa.asm new file mode 100644 index 0000000..4840fca --- /dev/null +++ b/compiler/vpin/crt-rsa.asm @@ -0,0 +1,498 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #11413 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3533 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #113 + str r0, [sp] + sub sp, sp, #4 + mov r0, #59 + str r0, [sp] + sub sp, sp, #4 + mov r0, #97 + str r0, [sp] + sub sp, sp, #4 + mov r0, #101 + str r0, [sp] + sub sp, sp, #4 + mov r0, #-1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #23 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #76] + str r0, [sp, #44] + ldr r0, [sp, #88] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_0: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_0 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_1: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_1 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_2: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_2 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_2 +end_while_2: +while_3: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_3 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_3 +end_while_3: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp, #16] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_1 +end_while_1: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_0 +end_while_0: + ldr r0, [sp, #36] + str r0, [sp, #60] + ldr r0, [sp, #64] + str r0, [sp, #48] + ldr r0, [sp, #72] + str r0, [sp, #44] + ldr r0, [sp, #84] + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + mov r0, #0 + str r0, [sp, #4] +while_5: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #44] + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_5 + ldr r0, [sp, #36] + str r0, [sp, #28] + ldr r0, [sp, #48] + str r0, [sp, #24] + ldr r0, [sp, #40] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_6: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_6 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_7: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_7 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_7 +end_while_7: +while_8: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_8 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_8 +end_while_8: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_9 + mov r0, #0 + str r0, [sp, #16] + b endif_9 +else_9: +endif_9: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_6 +end_while_6: + ldr r0, [sp, #16] + str r0, [sp, #36] + ldr r0, [sp, #4] + mov r1, r0 + mov r0, #1 + add r0, r1, r0 + str r0, [sp, #4] + b while_5 +end_while_5: + ldr r0, [sp, #36] + str r0, [sp, #56] + ldr r0, [sp, #60] + mov r1, r0 + ldr r0, [sp, #56] + sub r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #28] + ldr r0, [sp, #80] + str r0, [sp, #24] + ldr r0, [sp, #88] + str r0, [sp, #20] + mov r0, #0 + str r0, [sp, #16] +while_10: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_10 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #28] + add r0, r1, r0 + str r0, [sp, #16] +while_11: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq end_while_11 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + sub r0, r1, r0 + str r0, [sp, #16] + b while_11 +end_while_11: +while_12: + ldr r0, [sp, #16] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it lt + movlt r0, #1 + cmp r0, #0 + beq end_while_12 + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + add r0, r1, r0 + str r0, [sp, #16] + b while_12 +end_while_12: + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_13 + mov r0, #0 + str r0, [sp, #16] + b endif_13 +else_13: +endif_13: + ldr r0, [sp, #24] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #24] + b while_10 +end_while_10: + ldr r0, [sp, #16] + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #84] + mul r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + mov r1, r0 + ldr r0, [sp, #56] + add r0, r1, r0 + str r0, [sp, #52] + ldr r0, [sp, #52] + str r0, [sp, #68] + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #9 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_14 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_14 +print_int_loop_14: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_14 +print_int_done_14: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #18 + mov r7, #4 + svc #0 + ldr r0, [sp, #100] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_15 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_15 +print_int_loop_15: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_15 +print_int_done_15: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + ldr r0, [sp, #68] + mov r7, #1 + svc #0 + +.size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_sign = " +.Lstr1: + .ascii "g_countermeasure: " +newline: + .ascii "\n" +num_buf: + .space 16 diff --git a/testing/fissc/crt-rsa.trv b/compiler/vpin/crt-rsa.trv similarity index 100% rename from testing/fissc/crt-rsa.trv rename to compiler/vpin/crt-rsa.trv diff --git a/compiler/vpin/out.asm b/compiler/vpin/out.asm new file mode 100644 index 0000000..83c42ef --- /dev/null +++ b/compiler/vpin/out.asm @@ -0,0 +1,276 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #2 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + sub sp, sp, #4 + mov r0, #4 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + mov r0, #0 + str r0, [sp, #32] + ldr r0, [sp, #36] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #32] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_1 + mov r0, #0 + str r0, [sp] + b endif_1 +else_1: +endif_1: + ldr r0, [sp, #12] + mov r1, r0 + ldr r0, [sp, #28] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_2 + mov r0, #0 + str r0, [sp] + b endif_2 +else_2: +endif_2: + ldr r0, [sp, #8] + mov r1, r0 + ldr r0, [sp, #24] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_3 + mov r0, #0 + str r0, [sp] + b endif_3 +else_3: +endif_3: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_5 + mov r0, #3 + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + b endif_5 +else_5: + ldr r0, [sp, #40] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #40] +endif_5: + add sp, sp, #4 + b endif_0 +else_0: +endif_0: + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #18 + mov r7, #4 + svc #0 + ldr r0, [sp, #40] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_6 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_6 +print_int_loop_6: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_6 +print_int_done_6: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #17 + mov r7, #4 + svc #0 + ldr r0, [sp, #32] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_7 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_7 +print_int_loop_7: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_7 +print_int_done_7: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr2 + mov r2, #7 + mov r7, #4 + svc #0 + ldr r0, [sp, #36] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_8 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_8 +print_int_loop_8: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_8 +print_int_done_8: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + ldr r0, [sp, #32] + mov r7, #1 + svc #0 + +.size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_countermeasure: " +.Lstr1: + .ascii "g_authenticated: " +.Lstr2: + .ascii "g_ptc: " +newline: + .ascii "\n" +num_buf: + .space 16 diff --git a/compiler/vpin/share/interface.h b/compiler/vpin/share/interface.h new file mode 100755 index 0000000..62ea22f --- /dev/null +++ b/compiler/vpin/share/interface.h @@ -0,0 +1,49 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +/*$ + @authors = SERTIF Consortium + @feature = N/A + @target = N/A + @countermeasure = N/A + @difficulties = N/A + @purpose = shared interface for examples +*/ + +#ifndef H_INTERFACE +#define H_INTERFACE + +#include "types.h" + +/* defines what happens when a fault has been detected + implementation defined +*/ +void countermeasure(void); + +/* initializes global variables at the beginning of an example + implementation-defined + example-defined +*/ +void initialize(void); + +/* determines whether an attack is successful + example-defined +*/ +BOOL oracle(void); + +#endif // H_INTERFACE diff --git a/compiler/vpin/share/lazart.h b/compiler/vpin/share/lazart.h new file mode 100755 index 0000000..cf68670 --- /dev/null +++ b/compiler/vpin/share/lazart.h @@ -0,0 +1,21 @@ +#ifndef LAZART_API_HPP +#define LAZART_API_HPP + +#ifdef LAZART + +#include + +/*#define LAZART_ORACLE(oracle) \ + if(oracle) { \ + klee_assume(oracle); \ + } else { \ + klee_assume(0 != 0 ); \ + }*/ + +#define LAZART_ORACLE(oracle) klee_assume(oracle) + +#else +#define LAZART_ORACLE(oracle) +#endif // LAZART + +#endif // LAZART_API_HPP diff --git a/compiler/vpin/share/types.h b/compiler/vpin/share/types.h new file mode 100755 index 0000000..74bb38e --- /dev/null +++ b/compiler/vpin/share/types.h @@ -0,0 +1,29 @@ +/**************************************************************************/ +/* */ +/* This file is part of FISSC. */ +/* */ +/* you can redistribute it and/or modify it under the terms of the GNU */ +/* Lesser General Public License as published by the Free Software */ +/* Foundation, version 3.0. */ +/* */ +/* It is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Lesser General Public License for more details. */ +/* */ +/* See the GNU Lesser General Public License version 3.0 */ +/* for more details (enclosed in the file LICENSE). */ +/* */ +/**************************************************************************/ + +#ifndef H_TYPES +#define H_TYPES +typedef signed char SBYTE; +typedef unsigned char UBYTE; +typedef unsigned char BOOL; +typedef unsigned long ULONG; + +#define BOOL_TRUE 0xAA +#define BOOL_FALSE 0x55 + +#endif // H_TYPES diff --git a/compiler/vpin/verifypin.asm b/compiler/vpin/verifypin.asm new file mode 100644 index 0000000..204cb5b --- /dev/null +++ b/compiler/vpin/verifypin.asm @@ -0,0 +1,282 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + sub sp, sp, #4 + mov r0, #2 + str r0, [sp] + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + sub sp, sp, #4 + mov r0, #4 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + mov r0, #0 + str r0, [sp, #32] + ldr r0, [sp, #36] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #32] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_1 + mov r0, #0 + str r0, [sp] + b endif_1 +else_1: +endif_1: + ldr r0, [sp, #12] + mov r1, r0 + ldr r0, [sp, #28] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_2 + mov r0, #0 + str r0, [sp] + b endif_2 +else_2: +endif_2: + ldr r0, [sp, #8] + mov r1, r0 + ldr r0, [sp, #24] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_3 + mov r0, #0 + str r0, [sp] + b endif_3 +else_3: +endif_3: + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_4 + mov r0, #0 + str r0, [sp] + b endif_4 +else_4: +endif_4: + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_5 + mov r0, #3 + str r0, [sp, #40] + mov r0, #1 + str r0, [sp, #36] + ldr r0, [sp, #36] + mov r7, #1 + svc #0 + b endif_5 +else_5: + ldr r0, [sp, #40] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #40] + mov r0, #0 + mov r7, #1 + svc #0 +endif_5: + add sp, sp, #4 + b endif_0 +else_0: +endif_0: + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #18 + mov r7, #4 + svc #0 + ldr r0, [sp, #40] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_6 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_6 +print_int_loop_6: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_6 +print_int_done_6: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #17 + mov r7, #4 + svc #0 + ldr r0, [sp, #32] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_7 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_7 +print_int_loop_7: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_7 +print_int_done_7: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =.Lstr2 + mov r2, #7 + mov r7, #4 + svc #0 + ldr r0, [sp, #36] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_8 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_8 +print_int_loop_8: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_8 +print_int_done_8: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + mov r0, #0 + mov r7, #1 + svc #0 + +.size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_countermeasure: " +.Lstr1: + .ascii "g_authenticated: " +.Lstr2: + .ascii "g_ptc: " +newline: + .ascii "\n" +num_buf: + .space 16 diff --git a/compiler/vpin/verifypin.trv b/compiler/vpin/verifypin.trv new file mode 100644 index 0000000..904bbf5 --- /dev/null +++ b/compiler/vpin/verifypin.trv @@ -0,0 +1,46 @@ +func main() -> Integer { + let g_countermeasure : Integer = 0; + let ptc : Integer = 3; + let authenticated : Integer = 0; + let cardPin1 : Integer = 1; + let cardPin2 : Integer = 2; + let cardPin3 : Integer = 3; + let cardPin4 : Integer = 4; + let userPin1 : Integer = 0; + let userPin2 : Integer = 0; + let userPin3 : Integer = 0; + let userPin4 : Integer = 0; + + authenticated = 0; + + if ptc > 0 then { + let pinsEqual : Integer = 1; + if userPin1 != cardPin1 then { + pinsEqual = 0; + } + + if userPin2 != cardPin2 then { + pinsEqual = 0; + } + + if userPin3 != cardPin3 then { + pinsEqual = 0; + } + + if userPin4 != cardPin4 then { + pinsEqual = 0; + } + + if pinsEqual == 1 then { + ptc = 3; + authenticated = 1; + } else { + ptc = ptc - 1; + } + } + print("g_countermeasure: ", g_countermeasure); + print("g_authenticated: ", authenticated); + print("g_ptc: ", ptc); + + return authenticated; +} diff --git a/testing/config.toml b/testing/config.toml index c24cb8b..0c776a1 100644 --- a/testing/config.toml +++ b/testing/config.toml @@ -1,4 +1,5 @@ -tests_folder = "fissc" +test_folder = "fissc" + modeled_registers = [ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" @@ -11,4 +12,5 @@ default = "stdout" expected = 0 [pass_mode.stdout] -expected = "g_sign = 11254" +expected_pass = "g_authenticated: 0" +expected_fail = "g_authenticated: 1" diff --git a/testing/fissc/disabled/crt-rsa.trv b/testing/fissc/disabled/crt-rsa.trv new file mode 100644 index 0000000..62fc913 --- /dev/null +++ b/testing/fissc/disabled/crt-rsa.trv @@ -0,0 +1,121 @@ +func main() -> Integer { + let g_countermeasure : Integer = 0; + let g_N : Integer = 11413; + let g_e : Integer = 3533; + let g_p : Integer = 101; + let g_q : Integer = 113; + let g_iq : Integer = 59; + let g_dp : Integer = 97; + let g_dq : Integer = 101; + let g_sign : Integer = -1; + let g_M : Integer = 23; + + let Cp : Integer = 0; + let Cq : Integer = 0; + let tmp : Integer = 0; + + let a : Integer = 0; + let b : Integer = 0; + let n : Integer = 0; + let r : Integer = 0; + + let mul_r : Integer = 0; + let mul_a : Integer = 0; + let mul_b : Integer = 0; + let mul_n : Integer = 0; + let mul_tmp : Integer = 0; + + let pow_a : Integer = 0; + let pow_tmp : Integer = 0; + let pow_b : Integer = 0; + let pow_n : Integer = 0; + + a = g_M; + b = g_dp; + n = g_p; + r = 1; + pow_b = 0; + while pow_b < b { + mul_a = r; + mul_b = a; + mul_n = n; + mul_tmp = 0; + while mul_b > 0 { + mul_tmp = mul_tmp + mul_a; + while mul_tmp > mul_n { + mul_tmp = mul_tmp - mul_n; + } + while mul_tmp < 0 { + mul_tmp = mul_tmp + mul_n; + } + if mul_tmp == mul_n { + mul_tmp = 0; + } + mul_b = mul_b - 1; + } + r = mul_tmp; + pow_b = pow_b + 1; + } + Cp = r; + + a = g_M; + b = g_dq; + n = g_q; + r = 1; + pow_b = 0; + while pow_b < b { + mul_a = r; + mul_b = a; + mul_n = n; + mul_tmp = 0; + while mul_b > 0 { + mul_tmp = mul_tmp + mul_a; + while mul_tmp > mul_n { + mul_tmp = mul_tmp - mul_n; + } + while mul_tmp < 0 { + mul_tmp = mul_tmp + mul_n; + } + if mul_tmp == mul_n { + mul_tmp = 0; + } + mul_b = mul_b - 1; + } + r = mul_tmp; + pow_b = pow_b + 1; + } + Cq = r; + + tmp = Cp - Cq; + + mul_a = tmp; + mul_b = g_iq; + mul_n = g_p; + mul_tmp = 0; + while mul_b > 0 { + mul_tmp = mul_tmp + mul_a; + while mul_tmp > mul_n { + mul_tmp = mul_tmp - mul_n; + } + while mul_tmp < 0 { + mul_tmp = mul_tmp + mul_n; + } + if mul_tmp == mul_n { + mul_tmp = 0; + } + mul_b = mul_b - 1; + } + tmp = mul_tmp; + + tmp = tmp * g_q; + + tmp = tmp + Cq; + + g_sign = tmp; + + print("g_sign = ", g_sign); + + print("g_countermeasure: ", g_countermeasure); + + return g_sign; +} diff --git a/testing/fissc/crt-rsa.trv.output b/testing/fissc/disabled/crt-rsa.trv.output similarity index 100% rename from testing/fissc/crt-rsa.trv.output rename to testing/fissc/disabled/crt-rsa.trv.output diff --git a/testing/fissc/verifypin.trv b/testing/fissc/verifypin.trv new file mode 100644 index 0000000..904bbf5 --- /dev/null +++ b/testing/fissc/verifypin.trv @@ -0,0 +1,46 @@ +func main() -> Integer { + let g_countermeasure : Integer = 0; + let ptc : Integer = 3; + let authenticated : Integer = 0; + let cardPin1 : Integer = 1; + let cardPin2 : Integer = 2; + let cardPin3 : Integer = 3; + let cardPin4 : Integer = 4; + let userPin1 : Integer = 0; + let userPin2 : Integer = 0; + let userPin3 : Integer = 0; + let userPin4 : Integer = 0; + + authenticated = 0; + + if ptc > 0 then { + let pinsEqual : Integer = 1; + if userPin1 != cardPin1 then { + pinsEqual = 0; + } + + if userPin2 != cardPin2 then { + pinsEqual = 0; + } + + if userPin3 != cardPin3 then { + pinsEqual = 0; + } + + if userPin4 != cardPin4 then { + pinsEqual = 0; + } + + if pinsEqual == 1 then { + ptc = 3; + authenticated = 1; + } else { + ptc = ptc - 1; + } + } + print("g_countermeasure: ", g_countermeasure); + print("g_authenticated: ", authenticated); + print("g_ptc: ", ptc); + + return authenticated; +} diff --git a/testing/fissc/verifypin.trv.output b/testing/fissc/verifypin.trv.output new file mode 100644 index 0000000..4eda5e0 --- /dev/null +++ b/testing/fissc/verifypin.trv.output @@ -0,0 +1,3 @@ +g_countermeasure: 0 +g_authenticated: 0 +g_ptc: 2 diff --git a/testing/src/database.py b/testing/src/database.py index 168ff99..aa376de 100644 --- a/testing/src/database.py +++ b/testing/src/database.py @@ -26,6 +26,7 @@ class ResultsDatabase: stdout TEXT, stderr TEXT, expected_output TEXT NOT NULL, + matched_output_line TEXT, passed INTEGER NOT NULL, FOREIGN KEY (run_id) REFERENCES runs(id) ); @@ -90,6 +91,7 @@ def insert_results_batch(self, run_id, results): res["stdout"], res["stderr"], res["expected_output"], + res.get("matched_output_line"), int(res["passed"]), )) @@ -97,8 +99,8 @@ def insert_results_batch(self, run_id, results): """ INSERT INTO test_results (run_id, test, variant, injection_point, fault_type, fault_pc, fault_reg, fault_bit, - returncode, stdout, stderr, expected_output, passed) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + returncode, stdout, stderr, expected_output, matched_output_line, passed) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, rows, ) diff --git a/testing/src/testrunner.py b/testing/src/testrunner.py index ad8a452..d5c69a1 100644 --- a/testing/src/testrunner.py +++ b/testing/src/testrunner.py @@ -23,24 +23,51 @@ def _fault_worker(args): passed = _check_passed(result, pass_mode_config) + matched_output_line = None + if pass_mode_config.get("mode") == "stdout": + expected_pass = pass_mode_config.get("expected_pass", "") + expected_fail = pass_mode_config.get("expected_fail", "") + + stdout_lines = result.stdout.strip().split("\n") + + if passed and expected_pass: + for line in stdout_lines: + if expected_pass in line: + matched_output_line = line.strip() + break + elif not passed and expected_fail: + for line in stdout_lines: + if expected_fail in line: + matched_output_line = line.strip() + break + + if matched_output_line is None: + matched_output_line = "N/A" + return { "injection_point": injection_point, "returncode": result.returncode, "stdout": result.stdout.strip(), "stderr": result.stderr.strip(), - "expected_output": pass_mode_config.get("expected", ""), + "expected_output": pass_mode_config.get("expected_pass", ""), + "matched_output_line": matched_output_line, "passed": passed, } def _check_passed(result, pass_mode_config): mode = pass_mode_config.get("mode", "returncode") - expected = pass_mode_config.get("expected", 0) + expected_pass = pass_mode_config.get("expected_pass", None) + expected_fail = pass_mode_config.get("expected_fail", None) if mode == "returncode": - return result.returncode == expected + return result.returncode == 0 elif mode == "stdout": - return expected in result.stdout + if expected_pass and expected_pass in result.stdout: + return True + elif expected_fail and expected_fail in result.stdout and result.returncode == 1: + return False + return True else: raise ValueError(f"Unknown pass mode: {mode}") @@ -55,7 +82,7 @@ def __init__(self, config_path=None): self.base_dir = os.path.join(os.path.dirname(__file__), "..") self.tests_folder = os.path.join( - self.base_dir, config.get("fissc_folder", "fissc") + self.base_dir, config.get("test_folder", "fissc") ) self.artifacts_folder = os.path.join(self.base_dir, "artifacts") self.modeled_registers = config.get( @@ -129,14 +156,16 @@ def _load_pass_mode_config(self, test_name, trv_file, files): mode_config = self.pass_mode_configs.get(mode, {}) return { "mode": mode, - "expected": pass_mode.get("expected", mode_config.get("expected", 0)), + "expected_pass": pass_mode.get("expected_pass", mode_config.get("expected_pass", 0)), + "expected_fail": pass_mode.get("expected_fail", mode_config.get("expected_fail", None)), } mode = self.default_pass_mode mode_config = self.pass_mode_configs.get(mode, {}) return { "mode": mode, - "expected": mode_config.get("expected", 0), + "expected_pass": mode_config.get("expected_pass", 0), + "expected_fail": mode_config.get("expected_fail", None), } def check_bin(self): @@ -351,7 +380,7 @@ def compile(self): self.compile_results = results return results - def run_tests(self, limit=None): + def run_tests(self, limit=None, run_variants="both"): if not hasattr(self, "run_folder"): self.setup() @@ -360,10 +389,18 @@ def run_tests(self, limit=None): all_fault_results = [] - for test, result in zip(self.tests, self.compile_results): + if run_variants == "normal": + variants = [False] + elif run_variants == "hard": + variants = [True] + else: + variants = [False, True] + compile_results = self.compile_results or [] + + for test, result in zip(self.tests, compile_results): print(f"Test: {test['name']}") - for hard in [False, True]: + for hard in variants: hard_str = "hard" if hard else "normal" res = result[hard_str] diff --git a/testing/test b/testing/test index 1ab589c..7c39202 100755 --- a/testing/test +++ b/testing/test @@ -9,8 +9,21 @@ def main(): parser.add_argument('--config', type=str, default=None, help='Path to config.toml') parser.add_argument('--skip-run', action='store_true', help='Only setup and compile, skip running tests') parser.add_argument('--limit', type=int, default=None, help='Limit number of injection points to test') + parser.add_argument('--nohard', action='store_true', help='Skip hardened version when running tests') + parser.add_argument('--hard', action='store_true', help='Only run hardened version') args = parser.parse_args() + if args.nohard and args.hard: + print("Error: Cannot use both --nohard and --hard") + return + + if args.hard: + run_variants = "hard" + elif args.nohard: + run_variants = "normal" + else: + run_variants = "both" + runner = TestRunner(config_path=args.config) # check that the compiler and interpreter is present: runner.check_bin() @@ -26,7 +39,7 @@ def main(): if not args.skip_run: print(f"\nRunning tests...") - runner.run_tests(limit=args.limit) + runner.run_tests(limit=args.limit, run_variants=run_variants) else: print(f"\nSkipping test run (--skip-run)") From 245965058e3e94b1d09d3795ae64bcfa1e5d2f31 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Wed, 25 Mar 2026 15:42:49 +0100 Subject: [PATCH 30/34] added new fields to db with information about injections (for experimentation) --- .gitignore | 3 + compiler/src/codegen/codegen.rs | 3 - interpreter/Cargo.lock | 7 + interpreter/Cargo.toml | 1 + interpreter/src/interpreter.rs | 30 +- interpreter/src/main.rs | 7 +- testing/fissc/verifypin.trv | 2 - testing/out.asm | 498 -------------------------------- testing/src/database.py | 42 ++- testing/src/testrunner.py | 18 +- 10 files changed, 95 insertions(+), 516 deletions(-) delete mode 100644 testing/out.asm diff --git a/.gitignore b/.gitignore index ac53c9d..d26baa7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ /testing/bin /testing/artifacts /testing/src/__pycache__ +/testing/[0-9]*-*/ +/testing/hardened.asm +/testing/out.asm diff --git a/compiler/src/codegen/codegen.rs b/compiler/src/codegen/codegen.rs index a3c801e..bd087c4 100644 --- a/compiler/src/codegen/codegen.rs +++ b/compiler/src/codegen/codegen.rs @@ -33,9 +33,6 @@ impl CodeGenerator { for func in ast { self.emit(func); } - if self.hard { - self.emit_countermeasure(); - } self.emit_print_data(); } diff --git a/interpreter/Cargo.lock b/interpreter/Cargo.lock index 2dd1dd9..b1c241e 100644 --- a/interpreter/Cargo.lock +++ b/interpreter/Cargo.lock @@ -116,6 +116,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + [[package]] name = "once_cell_polyfill" version = "1.70.2" @@ -172,6 +178,7 @@ name = "thumb2_interpreter" version = "0.1.0" dependencies = [ "clap", + "json", "pretty_assertions", ] diff --git a/interpreter/Cargo.toml b/interpreter/Cargo.toml index 02732e6..c14e0d6 100644 --- a/interpreter/Cargo.toml +++ b/interpreter/Cargo.toml @@ -8,3 +8,4 @@ pretty_assertions = "1.4" [dependencies] clap = { version = "4.5.60", features = ["derive"] } +json = "0.12.4" diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index b733d83..62f1fdc 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -4,6 +4,8 @@ use std::io::BufRead; use std::process::exit; use std::usize; +use json::{ JsonValue, object }; + use crate::memory::EmulatorMemory; const NUM_REGISTERS: usize = 13; //FIXME: Find out if num registers is 13 (r0-r12) plsssss @@ -90,6 +92,7 @@ pub enum InjectionTarget { pub struct InjectionSpec { pub target: InjectionTarget, pub trigger_pc: i32, + pub has_triggered: bool, } pub struct Interpreter { @@ -102,9 +105,11 @@ pub struct Interpreter { cpsr: Cpsr, file: Vec, debug: bool, + test_mode: bool, start_time: std::time::Instant, max_time: std::time::Duration, fault_spec: InjectionSpec, + test_report: json::JsonValue, } impl Interpreter { @@ -119,12 +124,15 @@ impl Interpreter { cpsr: Cpsr::default(), file: Vec::new(), debug: false, + test_mode: false, start_time: std::time::Instant::now(), max_time: std::time::Duration::from_millis(1000), fault_spec: InjectionSpec { target: InjectionTarget::None, trigger_pc: -1, + has_triggered: false, }, + test_report: object! { title: "test_report" }, } } @@ -173,6 +181,9 @@ impl Interpreter { ); } } + pub fn set_test_mode(&mut self, test_mode: bool) { + self.test_mode = test_mode; + } pub fn set_debug(&mut self, debug: bool) { self.debug = debug; @@ -744,7 +755,6 @@ impl Interpreter { if self.debug { println!("Executing cmp instruction: {}", content); } - let pc = self.pc; let parts: Vec<&str> = content .split(|c: char| (c == ',' || c.is_whitespace())) @@ -960,7 +970,9 @@ impl Interpreter { } fn trigger_register_fault(&mut self, register: usize, bit: u32) { let old_val = self.registers[register]; + self.test_report["reg_old_value"] = old_val.into(); self.registers[register] = self.flip_bit(old_val, bit); + self.test_report["reg_new_value"] = self.registers[register].clone().into(); println!("REGISTER FAULT TRIGGERED!"); } @@ -972,14 +984,20 @@ impl Interpreter { } while self.pc < self.eof_pc { let instruction = start_block.get(self.pc as usize).unwrap(); - - if (self.pc as i32) == self.fault_spec.trigger_pc { + if (self.pc as i32) == self.fault_spec.trigger_pc && !self.fault_spec.has_triggered { match self.fault_spec.target { InjectionTarget::Register { register, bit } => { self.trigger_register_fault(register, bit); + self.fault_spec.has_triggered = true; } InjectionTarget::ProgramCounter { bit } => { + self.test_report["pc_old_value"] = self.pc.clone().into(); self.pc = self.flip_bit_u32(self.pc, bit); + self.test_report["pc_new_value"] = self.pc.clone().into(); + let actual_exec_instr = start_block.get(self.pc as usize).unwrap(); + self.test_report["expected_exec_instr"] = instruction.as_str().into(); + self.test_report["actual_exec_instr"] = actual_exec_instr.as_str().into(); + self.fault_spec.has_triggered = true; continue; } _ => panic!("Injection type not implemented yet."), @@ -1004,6 +1022,9 @@ impl Interpreter { f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { if let Some(exit_code) = self.exec_svc(instruction.clone()) { + if self.test_mode { + println!("{}", self.test_report.dump()); + } return (exit_code as u32) & 0xff; } } @@ -1026,6 +1047,9 @@ impl Interpreter { } self.set_pc(self.pc + 1); } + if self.test_mode { + println!("{}", self.test_report.dump()); + } 0 } } diff --git a/interpreter/src/main.rs b/interpreter/src/main.rs index 2c2369d..222ae24 100644 --- a/interpreter/src/main.rs +++ b/interpreter/src/main.rs @@ -16,7 +16,10 @@ struct Args { max_time: Option, #[arg(short, long)] - injection_point: Option + injection_point: Option, + + #[arg(long)] + test_mode: bool } fn main() { @@ -25,7 +28,7 @@ fn main() { let mut interpreter = Interpreter::default(); interpreter.set_debug(args.debug); - + interpreter.set_test_mode(args.test_mode); if let Some(time) = args.max_time { interpreter.set_max_time(time); } diff --git a/testing/fissc/verifypin.trv b/testing/fissc/verifypin.trv index 904bbf5..e432608 100644 --- a/testing/fissc/verifypin.trv +++ b/testing/fissc/verifypin.trv @@ -1,5 +1,4 @@ func main() -> Integer { - let g_countermeasure : Integer = 0; let ptc : Integer = 3; let authenticated : Integer = 0; let cardPin1 : Integer = 1; @@ -38,7 +37,6 @@ func main() -> Integer { ptc = ptc - 1; } } - print("g_countermeasure: ", g_countermeasure); print("g_authenticated: ", authenticated); print("g_ptc: ", ptc); diff --git a/testing/out.asm b/testing/out.asm deleted file mode 100644 index 4840fca..0000000 --- a/testing/out.asm +++ /dev/null @@ -1,498 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #11413 - str r0, [sp] - sub sp, sp, #4 - mov r0, #3533 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #113 - str r0, [sp] - sub sp, sp, #4 - mov r0, #59 - str r0, [sp] - sub sp, sp, #4 - mov r0, #97 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #-1 - str r0, [sp] - sub sp, sp, #4 - mov r0, #23 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #76] - str r0, [sp, #44] - ldr r0, [sp, #88] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] -while_0: - ldr r0, [sp, #4] - mov r1, r0 - ldr r0, [sp, #44] - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_1: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_1 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_2: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_2 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_2 -end_while_2: -while_3: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_3 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_3 -end_while_3: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_4 - mov r0, #0 - str r0, [sp, #16] - b endif_4 -else_4: -endif_4: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_1 -end_while_1: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #1 - add r0, r1, r0 - str r0, [sp, #4] - b while_0 -end_while_0: - ldr r0, [sp, #36] - str r0, [sp, #60] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #72] - str r0, [sp, #44] - ldr r0, [sp, #84] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] -while_5: - ldr r0, [sp, #4] - mov r1, r0 - ldr r0, [sp, #44] - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_5 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_6: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_6 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_7: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_7 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_7 -end_while_7: -while_8: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_8 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_8 -end_while_8: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_9 - mov r0, #0 - str r0, [sp, #16] - b endif_9 -else_9: -endif_9: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_6 -end_while_6: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #1 - add r0, r1, r0 - str r0, [sp, #4] - b while_5 -end_while_5: - ldr r0, [sp, #36] - str r0, [sp, #56] - ldr r0, [sp, #60] - mov r1, r0 - ldr r0, [sp, #56] - sub r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #28] - ldr r0, [sp, #80] - str r0, [sp, #24] - ldr r0, [sp, #88] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_10: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_10 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_11: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_11 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_11 -end_while_11: -while_12: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_12 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_12 -end_while_12: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_13 - mov r0, #0 - str r0, [sp, #16] - b endif_13 -else_13: -endif_13: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_10 -end_while_10: - ldr r0, [sp, #16] - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #84] - mul r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #56] - add r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #68] - mov r0, #1 - ldr r1, =.Lstr0 - mov r2, #9 - mov r7, #4 - svc #0 - ldr r0, [sp, #68] - mov r4, r0 - ldr r1, =num_buf - add r1, r1, #16 - mov r2, #0 - cmp r4, #0 - bne print_int_loop_14 - mov r3, #48 - sub r1, r1, #1 - strb r3, [r1] - mov r2, #1 - b print_int_done_14 -print_int_loop_14: - mov r0, r4 - mov r3, #10 - sdiv r5, r0, r3 - mul r6, r5, r3 - sub r7, r0, r6 - add r7, r7, #48 - sub r1, r1, #1 - strb r7, [r1] - add r2, r2, #1 - mov r4, r5 - cmp r4, #0 - bne print_int_loop_14 -print_int_done_14: - mov r0, #1 - mov r1, r1 - mov r2, r2 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =newline - mov r2, #1 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =.Lstr1 - mov r2, #18 - mov r7, #4 - svc #0 - ldr r0, [sp, #100] - mov r4, r0 - ldr r1, =num_buf - add r1, r1, #16 - mov r2, #0 - cmp r4, #0 - bne print_int_loop_15 - mov r3, #48 - sub r1, r1, #1 - strb r3, [r1] - mov r2, #1 - b print_int_done_15 -print_int_loop_15: - mov r0, r4 - mov r3, #10 - sdiv r5, r0, r3 - mul r6, r5, r3 - sub r7, r0, r6 - add r7, r7, #48 - sub r1, r1, #1 - strb r7, [r1] - add r2, r2, #1 - mov r4, r5 - cmp r4, #0 - bne print_int_loop_15 -print_int_done_15: - mov r0, #1 - mov r1, r1 - mov r2, r2 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =newline - mov r2, #1 - mov r7, #4 - svc #0 - ldr r0, [sp, #68] - mov r7, #1 - svc #0 - -.size _start, .-_start - -.section .data -.Lstr0: - .ascii "g_sign = " -.Lstr1: - .ascii "g_countermeasure: " -newline: - .ascii "\n" -num_buf: - .space 16 diff --git a/testing/src/database.py b/testing/src/database.py index aa376de..aa76f6e 100644 --- a/testing/src/database.py +++ b/testing/src/database.py @@ -1,3 +1,4 @@ +import json import sqlite3 from datetime import datetime @@ -23,6 +24,12 @@ class ResultsDatabase: fault_reg INTEGER, fault_bit INTEGER, returncode INTEGER NOT NULL, + pc_before INTEGER, + pc_after INTEGER, + expected_exec_instr TEXT, + actual_exec_instr TEXT, + reg_old_value INTEGER, + reg_new_value INTEGER, stdout TEXT, stderr TEXT, expected_output TEXT NOT NULL, @@ -77,7 +84,30 @@ def insert_results_batch(self, run_id, results): fault_type, fault_pc, fault_reg, fault_bit = ("reg", int(parts[1]), int(parts[2]), int(parts[3])) else: fault_type, fault_pc, fault_reg, fault_bit = (None, None, None, None) - + test_report = json.loads(res["test_report"]) + pc_before = test_report.get("pc_old_value", None) + pc_new = test_report.get("pc_new_value", None) + expected_exec_instr = test_report.get("expected_exec_instr", "N/A") + actual_exec_instr = test_report.get("actual_exec_instr", "N/A") + reg_old_value = test_report.get("reg_old_value", None) + reg_new_value = test_report.get("reg_new_value", None) + + def _clamp_int(val, max_val=2**63 - 1, min_val=-(2**63)): + if val is None: + return None + try: + int_val = int(val) + except (ValueError, TypeError): + return None + if int_val > max_val or int_val < min_val: + return str(int_val) + return int_val + + pc_before = _clamp_int(pc_before) + pc_new = _clamp_int(pc_new) + reg_old_value = _clamp_int(reg_old_value) + reg_new_value = _clamp_int(reg_new_value) + rows.append(( run_id, res["test"], @@ -88,6 +118,12 @@ def insert_results_batch(self, run_id, results): fault_reg, fault_bit, res["returncode"], + pc_before, + pc_new, + expected_exec_instr, + actual_exec_instr, + reg_old_value, + reg_new_value, res["stdout"], res["stderr"], res["expected_output"], @@ -99,8 +135,8 @@ def insert_results_batch(self, run_id, results): """ INSERT INTO test_results (run_id, test, variant, injection_point, fault_type, fault_pc, fault_reg, fault_bit, - returncode, stdout, stderr, expected_output, matched_output_line, passed) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + returncode, pc_before, pc_after, expected_exec_instr, actual_exec_instr, reg_old_value, reg_new_value, stdout, stderr, expected_output, matched_output_line, passed) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, rows, ) diff --git a/testing/src/testrunner.py b/testing/src/testrunner.py index d5c69a1..a7b4a39 100644 --- a/testing/src/testrunner.py +++ b/testing/src/testrunner.py @@ -1,4 +1,5 @@ import os +import re import sys import subprocess import shutil @@ -17,7 +18,7 @@ def _fault_worker(args): bin_dir = os.path.join(os.path.dirname(__file__), "..", "bin") interpreter_path = os.path.join(bin_dir, "interpreter") - cmd = [interpreter_path, asm_path, "--injection-point", injection_point] + cmd = [interpreter_path, asm_path, "--injection-point", injection_point, "--test-mode"] result = subprocess.run(cmd, cwd=bin_dir, capture_output=True, text=True) @@ -43,7 +44,6 @@ def _fault_worker(args): if matched_output_line is None: matched_output_line = "N/A" - return { "injection_point": injection_point, "returncode": result.returncode, @@ -52,9 +52,17 @@ def _fault_worker(args): "expected_output": pass_mode_config.get("expected_pass", ""), "matched_output_line": matched_output_line, "passed": passed, + "test_report": _extract_test_report(result.stdout), } - +def _extract_test_report(stdout: str): + keyword = '"title":\s*"test_report"' + pattern = rf'\{{[^{{}}]*{keyword}[^{{}}]*\}}' + match = re.search(pattern, stdout,flags=re.MULTILINE) + if match: + return match.group(0) + return '{"title": "test_report"}' + def _check_passed(result, pass_mode_config): mode = pass_mode_config.get("mode", "returncode") expected_pass = pass_mode_config.get("expected_pass", None) @@ -318,14 +326,14 @@ def _generate_injection_points(self, asm_path): # pc faults: pc:: for pc in range(1, max_pc): for bit in range( - 1, 32 + 0, 31 ): # TODO: Find ud af om den skal hedde 33 eller 32, ændrede til 32 selvom chatten mente 33 injection_points.append(f"pc:{pc}:{bit}") # reg faults: reg::: for pc in range(1, max_pc): for reg in range(13): - for bit in range(1, 33): + for bit in range(0, 31): injection_points.append(f"reg:{pc}:{reg}:{bit}") return injection_points From f7ad04d7bbf057ba9e5536d036a3d406b70059c3 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Mar 2026 13:22:07 +0100 Subject: [PATCH 31/34] step counter done --- compiler/fissc/verifypin.trv | 59 ++++ compiler/hard.asm | 471 +++++++++++++++++++++++++++++ compiler/main.asm | 455 ---------------------------- compiler/out.asm | 515 +++----------------------------- compiler/src/codegen/codegen.rs | 46 ++- interpreter/hard.asm | 414 +++++++++++++++++++++++++ interpreter/src/interpreter.rs | 1 + 7 files changed, 1025 insertions(+), 936 deletions(-) create mode 100644 compiler/fissc/verifypin.trv create mode 100644 compiler/hard.asm delete mode 100644 compiler/main.asm create mode 100644 interpreter/hard.asm diff --git a/compiler/fissc/verifypin.trv b/compiler/fissc/verifypin.trv new file mode 100644 index 0000000..6cb4402 --- /dev/null +++ b/compiler/fissc/verifypin.trv @@ -0,0 +1,59 @@ +func main() -> Integer { + let ptc : Integer = 3; + let authenticated : Integer = 0; + let cardPin1 : Integer = 1; + let cardPin2 : Integer = 2; + let cardPin3 : Integer = 3; + let cardPin4 : Integer = 4; + let userPin1 : Integer = 0; + let userPin2 : Integer = 0; + let userPin3 : Integer = 0; + let userPin4 : Integer = 0; + + authenticated = 0; + + if ptc > 0 then { + let pinsEqual : Integer = 1; + if userPin1 != cardPin1 then { + pinsEqual = 0; + } + else { + pinsEqual = 1; + } + + if userPin2 != cardPin2 then { + pinsEqual = 0; + } + else { + pinsEqual = 1; + } + + if userPin3 != cardPin3 then { + pinsEqual = 0; + } + else { + pinsEqual = 1; + } + + if userPin4 != cardPin4 then { + pinsEqual = 0; + } + else { + pinsEqual = 1; + } + + if pinsEqual == 1 then { + ptc = 3; + authenticated = 1; + } else { + ptc = ptc - 1; + } + } + else { + let x : Integer = 1; + } + print("g_authenticated: ", authenticated); + print("g_ptc: ", ptc); + + return authenticated; +} diff --git a/compiler/hard.asm b/compiler/hard.asm new file mode 100644 index 0000000..bd7cc4a --- /dev/null +++ b/compiler/hard.asm @@ -0,0 +1,471 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r9, #0 + mov r10, #1 + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + add r9, r9, #1 + cmp r9, #1 + bne countermeasure + add r9, r9, #1 + cmp r9, #2 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #3 + bne countermeasure + add r9, r9, #1 + cmp r9, #4 + bne countermeasure + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #5 + bne countermeasure + add r9, r9, #1 + cmp r9, #6 + bne countermeasure + sub sp, sp, #4 + mov r0, #2 + str r0, [sp] + add r9, r9, #1 + cmp r9, #7 + bne countermeasure + add r9, r9, #1 + cmp r9, #8 + bne countermeasure + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + add r9, r9, #1 + cmp r9, #9 + bne countermeasure + add r9, r9, #1 + cmp r9, #10 + bne countermeasure + sub sp, sp, #4 + mov r0, #4 + str r0, [sp] + add r9, r9, #1 + cmp r9, #11 + bne countermeasure + add r9, r9, #1 + cmp r9, #12 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #13 + bne countermeasure + add r9, r9, #1 + cmp r9, #14 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #15 + bne countermeasure + add r9, r9, #1 + cmp r9, #16 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #17 + bne countermeasure + add r9, r9, #1 + cmp r9, #18 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #19 + bne countermeasure + add r9, r9, #1 + cmp r9, #20 + bne countermeasure + mov r0, #0 + str r0, [sp, #32] + add r9, r9, #1 + cmp r9, #21 + bne countermeasure + add r9, r9, #1 + cmp r9, #22 + bne countermeasure + ldr r0, [sp, #36] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + add r9, r9, #1 + cmp r9, #23 + bne countermeasure + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #24 + bne countermeasure + add r9, r9, #1 + cmp r9, #25 + bne countermeasure + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #32] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_1 + add r9, r9, #1 + cmp r9, #26 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r9, #25 + b endif_1 +else_1: + add r9, r9, #1 + cmp r9, #26 + bne countermeasure + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r9, #25 +endif_1: + add r9, r9, #1 + cmp r9, #26 + bne countermeasure + ldr r0, [sp, #12] + mov r1, r0 + ldr r0, [sp, #28] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_2 + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r9, #26 + b endif_2 +else_2: + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r9, #26 +endif_2: + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + ldr r0, [sp, #8] + mov r1, r0 + ldr r0, [sp, #24] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_3 + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + mov r9, #27 + b endif_3 +else_3: + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + mov r9, #27 +endif_3: + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_4 + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + mov r9, #28 + b endif_4 +else_4: + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + mov r9, #28 +endif_4: + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_5 + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + mov r0, #3 + str r0, [sp, #40] + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + add r9, r9, #1 + cmp r9, #32 + bne countermeasure + mov r0, #1 + str r0, [sp, #36] + add r9, r9, #1 + cmp r9, #33 + bne countermeasure + add r9, r9, #1 + cmp r9, #34 + bne countermeasure + mov r9, #29 + b endif_5 +else_5: + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + ldr r0, [sp, #40] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #40] + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + add r9, r9, #1 + cmp r9, #32 + bne countermeasure + mov r9, #29 +endif_5: + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + add sp, sp, #4 + mov r9, #22 + b endif_0 +else_0: + add r9, r9, #1 + cmp r9, #23 + bne countermeasure + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #24 + bne countermeasure + add r9, r9, #1 + cmp r9, #25 + bne countermeasure + add sp, sp, #4 + mov r9, #22 +endif_0: + add r9, r9, #1 + cmp r9, #23 + bne countermeasure + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #17 + mov r7, #4 + svc #0 + ldr r0, [sp, #32] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_6 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_6 +print_int_loop_6: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_6 +print_int_done_6: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + add r9, r9, #1 + cmp r9, #24 + bne countermeasure + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #7 + mov r7, #4 + svc #0 + ldr r0, [sp, #36] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_7 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_7 +print_int_loop_7: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_7 +print_int_done_7: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + add r9, r9, #1 + cmp r9, #25 + bne countermeasure + ldr r0, [sp, #32] + mov r7, #1 + svc #0 + add r9, r9, #1 + cmp r9, #26 + bne countermeasure +countermeasure: + mov r0, #77 + mov r7, #1 + svc #0 + +.size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_authenticated: " +.Lstr1: + .ascii "g_ptc: " +newline: + .ascii "\n" +num_buf: + .space 16 +step_counter: + .word 0 +fault_msg: + .ascii "Control flow violation detected\n" diff --git a/compiler/main.asm b/compiler/main.asm deleted file mode 100644 index 7613098..0000000 --- a/compiler/main.asm +++ /dev/null @@ -1,455 +0,0 @@ -.syntax unified -.thumb - -.section .text -.global _start -.type _start, %function - -_start: - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #11413 - str r0, [sp] - sub sp, sp, #4 - mov r0, #3533 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #113 - str r0, [sp] - sub sp, sp, #4 - mov r0, #59 - str r0, [sp] - sub sp, sp, #4 - mov r0, #97 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #-1 - str r0, [sp] - sub sp, sp, #4 - mov r0, #23 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #76] - str r0, [sp, #44] - ldr r0, [sp, #88] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] -while_0: - ldr r0, [sp, #4] - mov r1, r0 - ldr r0, [sp, #44] - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_0 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_1: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_1 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_2: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_2 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_2 -end_while_2: -while_3: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_3 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_3 -end_while_3: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_4 - mov r0, #0 - str r0, [sp, #16] - b endif_4 -else_4: -endif_4: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_1 -end_while_1: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #1 - add r0, r1, r0 - str r0, [sp, #4] - b while_0 -end_while_0: - ldr r0, [sp, #36] - str r0, [sp, #60] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #72] - str r0, [sp, #44] - ldr r0, [sp, #84] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] -while_5: - ldr r0, [sp, #4] - mov r1, r0 - ldr r0, [sp, #44] - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_5 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_6: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_6 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_7: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_7 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_7 -end_while_7: -while_8: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_8 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_8 -end_while_8: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_9 - mov r0, #0 - str r0, [sp, #16] - b endif_9 -else_9: -endif_9: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_6 -end_while_6: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #1 - add r0, r1, r0 - str r0, [sp, #4] - b while_5 -end_while_5: - ldr r0, [sp, #36] - str r0, [sp, #56] - ldr r0, [sp, #60] - mov r1, r0 - ldr r0, [sp, #56] - sub r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #28] - ldr r0, [sp, #80] - str r0, [sp, #24] - ldr r0, [sp, #88] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_10: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_10 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_11: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_11 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_11 -end_while_11: -while_12: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_12 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_12 -end_while_12: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_13 - mov r0, #0 - str r0, [sp, #16] - b endif_13 -else_13: -endif_13: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_10 -end_while_10: - ldr r0, [sp, #16] - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #84] - mul r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #56] - add r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #68] - mov r0, #1 - ldr r1, =.Lstr0 - mov r2, #12 - mov r7, #4 - svc #0 - ldr r0, [sp, #68] - mov r4, r0 - ldr r1, =num_buf - add r1, r1, #16 - mov r2, #0 - cmp r4, #0 - bne print_int_loop_14 - mov r3, #48 - sub r1, r1, #1 - strb r3, [r1] - mov r2, #1 - b print_int_done_14 -print_int_loop_14: - mov r0, r4 - mov r3, #10 - sdiv r5, r0, r3 - mul r6, r5, r3 - sub r7, r0, r6 - add r7, r7, #48 - sub r1, r1, #1 - strb r7, [r1] - add r2, r2, #1 - mov r4, r5 - cmp r4, #0 - bne print_int_loop_14 -print_int_done_14: - mov r0, #1 - mov r1, r1 - mov r2, r2 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =newline - mov r2, #1 - mov r7, #4 - svc #0 - ldr r0, [sp, #68] - mov r7, #1 - svc #0 - -.size _start, .-_start - -.section .data -.Lstr0: - .ascii "gang_sign = " -newline: - .ascii "\n" -num_buf: - .space 16 diff --git a/compiler/out.asm b/compiler/out.asm index f05f88c..3aa5ccf 100644 --- a/compiler/out.asm +++ b/compiler/out.asm @@ -6,493 +6,64 @@ .type _start, %function _start: - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #11413 - str r0, [sp] - sub sp, sp, #4 - mov r0, #3533 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #113 - str r0, [sp] - sub sp, sp, #4 - mov r0, #59 - str r0, [sp] - sub sp, sp, #4 - mov r0, #97 - str r0, [sp] - sub sp, sp, #4 - mov r0, #101 - str r0, [sp] - sub sp, sp, #4 - mov r0, #-1 - str r0, [sp] - sub sp, sp, #4 - mov r0, #23 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - sub sp, sp, #4 - mov r0, #0 - str r0, [sp] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #76] - str r0, [sp, #44] - ldr r0, [sp, #88] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] + mov r9, #0 + mov r10, #1 + sub sp, sp, #4 + mov r0, #9 + str r0, [sp] + add r9, r9, #1 + cmp r9, #1 + bne countermeasure + add r9, r9, #1 + cmp r9, #2 + bne countermeasure + mov r10, #3 while_0: - ldr r0, [sp, #4] + add r9, r9, #1 + cmp r9, r10 + bne countermeasure + add r10, r10, #1 + ldr r0, [sp, #0] mov r1, r0 - ldr r0, [sp, #44] + mov r0, #12 cmp r1, r0 mov r0, #0 it lt movlt r0, #1 cmp r0, #0 beq end_while_0 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_1: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_1 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_2: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_2 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_2 -end_while_2: -while_3: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_3 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_3 -end_while_3: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_4 - mov r0, #0 - str r0, [sp, #16] - b endif_4 -else_4: -endif_4: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_1 -end_while_1: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] + ldr r0, [sp, #0] mov r1, r0 mov r0, #1 add r0, r1, r0 - str r0, [sp, #4] + str r0, [sp] + add r9, r9, #1 + cmp r9, r10 + bne countermeasure + add r10, r10, #1 + add r9, r9, #1 + cmp r9, r10 + bne countermeasure + add r10, r10, #1 + add r9, r9, #1 + cmp r9, r10 + bne countermeasure + add r10, r10, #1 b while_0 end_while_0: - ldr r0, [sp, #36] - str r0, [sp, #60] - ldr r0, [sp, #64] - str r0, [sp, #48] - ldr r0, [sp, #72] - str r0, [sp, #44] - ldr r0, [sp, #84] - str r0, [sp, #40] - mov r0, #1 - str r0, [sp, #36] - mov r0, #0 - str r0, [sp, #4] -while_5: - ldr r0, [sp, #4] - mov r1, r0 - ldr r0, [sp, #44] - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_5 - ldr r0, [sp, #36] - str r0, [sp, #28] - ldr r0, [sp, #48] - str r0, [sp, #24] - ldr r0, [sp, #40] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_6: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_6 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_7: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_7 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_7 -end_while_7: -while_8: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_8 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_8 -end_while_8: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_9 - mov r0, #0 - str r0, [sp, #16] - b endif_9 -else_9: -endif_9: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_6 -end_while_6: - ldr r0, [sp, #16] - str r0, [sp, #36] - ldr r0, [sp, #4] - mov r1, r0 - mov r0, #1 - add r0, r1, r0 - str r0, [sp, #4] - b while_5 -end_while_5: - ldr r0, [sp, #36] - str r0, [sp, #56] - ldr r0, [sp, #60] - mov r1, r0 - ldr r0, [sp, #56] - sub r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #28] - ldr r0, [sp, #80] - str r0, [sp, #24] - ldr r0, [sp, #88] - str r0, [sp, #20] - mov r0, #0 - str r0, [sp, #16] -while_10: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_10 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #28] - add r0, r1, r0 - str r0, [sp, #16] -while_11: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it gt - movgt r0, #1 - cmp r0, #0 - beq end_while_11 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - sub r0, r1, r0 - str r0, [sp, #16] - b while_11 -end_while_11: -while_12: - ldr r0, [sp, #16] - mov r1, r0 - mov r0, #0 - cmp r1, r0 - mov r0, #0 - it lt - movlt r0, #1 - cmp r0, #0 - beq end_while_12 - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - add r0, r1, r0 - str r0, [sp, #16] - b while_12 -end_while_12: - ldr r0, [sp, #16] - mov r1, r0 - ldr r0, [sp, #20] - cmp r1, r0 - mov r0, #0 - it eq - moveq r0, #1 - cmp r0, #0 - beq else_13 - mov r0, #0 - str r0, [sp, #16] - b endif_13 -else_13: -endif_13: - ldr r0, [sp, #24] - mov r1, r0 - mov r0, #1 - sub r0, r1, r0 - str r0, [sp, #24] - b while_10 -end_while_10: - ldr r0, [sp, #16] - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #84] - mul r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - mov r1, r0 - ldr r0, [sp, #56] - add r0, r1, r0 - str r0, [sp, #52] - ldr r0, [sp, #52] - str r0, [sp, #68] - mov r0, #1 - ldr r1, =.Lstr0 - mov r2, #15 - mov r7, #4 - svc #0 - mov r0, #1337 - mov r4, r0 - ldr r1, =num_buf - add r1, r1, #16 - mov r2, #0 - cmp r4, #0 - bne print_int_loop_14 - mov r3, #48 - sub r1, r1, #1 - strb r3, [r1] - mov r2, #1 - b print_int_done_14 -print_int_loop_14: - mov r0, r4 - mov r3, #10 - sdiv r5, r0, r3 - mul r6, r5, r3 - sub r7, r0, r6 - add r7, r7, #48 - sub r1, r1, #1 - strb r7, [r1] - add r2, r2, #1 - mov r4, r5 - cmp r4, #0 - bne print_int_loop_14 -print_int_done_14: - mov r0, #1 - mov r1, r1 - mov r2, r2 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =newline - mov r2, #1 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =.Lstr1 - mov r2, #18 - mov r7, #4 - svc #0 - ldr r0, [sp, #100] - mov r4, r0 - ldr r1, =num_buf - add r1, r1, #16 - mov r2, #0 - cmp r4, #0 - bne print_int_loop_15 - mov r3, #48 - sub r1, r1, #1 - strb r3, [r1] - mov r2, #1 - b print_int_done_15 -print_int_loop_15: - mov r0, r4 - mov r3, #10 - sdiv r5, r0, r3 - mul r6, r5, r3 - sub r7, r0, r6 - add r7, r7, #48 - sub r1, r1, #1 - strb r7, [r1] - add r2, r2, #1 - mov r4, r5 - cmp r4, #0 - bne print_int_loop_15 -print_int_done_15: - mov r0, #1 - mov r1, r1 - mov r2, r2 - mov r7, #4 - svc #0 - mov r0, #1 - ldr r1, =newline - mov r2, #1 - mov r7, #4 +mov r9, #2 + add r9, r9, #1 + cmp r9, #3 + bne countermeasure + ldr r0, [sp, #0] + mov r7, #1 svc #0 - ldr r0, [sp, #68] + add r9, r9, #1 + cmp r9, #4 + bne countermeasure +countermeasure: + mov r0, #77 mov r7, #1 svc #0 .size _start, .-_start - -.section .data -.Lstr0: - .ascii "g_sign herro = " -.Lstr1: - .ascii "g_countermeasure: " -newline: - .ascii "\n" -num_buf: - .space 16 diff --git a/compiler/src/codegen/codegen.rs b/compiler/src/codegen/codegen.rs index bd087c4..c5061b9 100644 --- a/compiler/src/codegen/codegen.rs +++ b/compiler/src/codegen/codegen.rs @@ -12,6 +12,7 @@ pub struct CodeGenerator { string_literals: Vec<(String, String)>, need_int_print: bool, step_counter: i32, + in_loop: bool, } impl CodeGenerator { @@ -25,6 +26,7 @@ impl CodeGenerator { string_literals: Vec::new(), need_int_print: false, step_counter: 0, + in_loop: false, } } pub fn generate(&mut self, ast: AST, is_hard: bool) { @@ -120,11 +122,19 @@ impl CodeGenerator { if !self.hard { return; } - - self.write_line("add r9, r9, #1", 1); - self.write_line("cmp r9, r10", 1); - self.write_line("bne countermeasure", 1); - self.write_line("add r10, r10, #1", 1); + self.step_counter += 1; + + if self.in_loop { + self.write_line("add r9, r9, #1", 1); + self.write_line("cmp r9, r10", 1); + self.write_line("bne countermeasure", 1); + self.write_line("add r10, r10, #1", 1); + + } else { + self.write_line("add r9, r9, #1", 1); + self.write_line(&format!("cmp r9, #{}", self.step_counter), 1); + self.write_line("bne countermeasure", 1); + } } fn emit_print_data(&mut self) { @@ -169,23 +179,30 @@ impl CodeGenerator { // THEN branch self.emit_step_check(); self.emit_block(block, false); - let then_end = self.step_counter; + if self.hard { + self.step_counter = saved; + self.write_line(&format!("mov r9, #{}", self.step_counter), 1); + } self.write_line(&format!("b endif_{}", label_id), 1); // ELSE branch self.write_line(&format!("else_{}:", label_id), 0); - self.step_counter = saved; + if self.hard { + self.step_counter = saved; + } if let Some(else_block) = option { self.emit_step_check(); self.emit_block(else_block, false); + if self.hard { + self.step_counter = saved; + self.write_line(&format!("mov r9, #{}", self.step_counter), 1); + } } - let else_end = self.step_counter; self.write_line(&format!("endif_{}:", label_id), 0); - self.step_counter = then_end.max(else_end); } _ => panic!("emit_if called with non-if statement"), } @@ -196,7 +213,13 @@ impl CodeGenerator { Stmt::While { expr, block } => { let label_id = self.label_count; self.label_count += 1; + let saved = self.step_counter; + self.in_loop = true; + + if self.hard { + self.write_line(&format!("mov r10, #{}", self.step_counter + 1), 1); + } self.write_line(&format!("while_{}:", label_id), 0); self.emit_step_check(); @@ -209,6 +232,11 @@ impl CodeGenerator { self.write_line(&format!("b while_{}", label_id), 1); self.write_line(&format!("end_while_{}:", label_id), 0); + if self.hard { + self.step_counter = saved; + self.write_line(&format!("mov r9, #{}", self.step_counter), 1); + } + self.in_loop = false; } _ => panic!("emit_while called with non-while statement"), } diff --git a/interpreter/hard.asm b/interpreter/hard.asm new file mode 100644 index 0000000..59dd9e2 --- /dev/null +++ b/interpreter/hard.asm @@ -0,0 +1,414 @@ +.syntax unified +.thumb + +.section .text +.global _start +.type _start, %function + +_start: + mov r9, #0 + mov r10, #1 + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + add r9, r9, #1 + cmp r9, #1 + bne countermeasure + add r9, r9, #1 + cmp r9, #2 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #3 + bne countermeasure + add r9, r9, #1 + cmp r9, #4 + bne countermeasure + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #5 + bne countermeasure + add r9, r9, #1 + cmp r9, #6 + bne countermeasure + sub sp, sp, #4 + mov r0, #2 + str r0, [sp] + add r9, r9, #1 + cmp r9, #7 + bne countermeasure + add r9, r9, #1 + cmp r9, #8 + bne countermeasure + sub sp, sp, #4 + mov r0, #3 + str r0, [sp] + add r9, r9, #1 + cmp r9, #9 + bne countermeasure + add r9, r9, #1 + cmp r9, #10 + bne countermeasure + sub sp, sp, #4 + mov r0, #4 + str r0, [sp] + add r9, r9, #1 + cmp r9, #11 + bne countermeasure + add r9, r9, #1 + cmp r9, #12 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #13 + bne countermeasure + add r9, r9, #1 + cmp r9, #14 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #15 + bne countermeasure + add r9, r9, #1 + cmp r9, #16 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #17 + bne countermeasure + add r9, r9, #1 + cmp r9, #18 + bne countermeasure + sub sp, sp, #4 + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #19 + bne countermeasure + add r9, r9, #1 + cmp r9, #20 + bne countermeasure + mov r0, #0 + str r0, [sp, #32] + add r9, r9, #1 + cmp r9, #21 + bne countermeasure + add r9, r9, #1 + cmp r9, #22 + bne countermeasure + ldr r0, [sp, #36] + mov r1, r0 + mov r0, #0 + cmp r1, r0 + mov r0, #0 + it gt + movgt r0, #1 + cmp r0, #0 + beq else_0 + add r9, r9, #1 + cmp r9, #23 + bne countermeasure + sub sp, sp, #4 + mov r0, #1 + str r0, [sp] + add r9, r9, #1 + cmp r9, #24 + bne countermeasure + add r9, r9, #1 + cmp r9, #25 + bne countermeasure + ldr r0, [sp, #16] + mov r1, r0 + ldr r0, [sp, #32] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_1 + add r9, r9, #1 + cmp r9, #26 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r9, #25 + b endif_1 +else_1: + mov r9, #25 +endif_1: + add r9, r9, #1 + cmp r9, #26 + bne countermeasure + ldr r0, [sp, #12] + mov r1, r0 + ldr r0, [sp, #28] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_2 + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r9, #26 + b endif_2 +else_2: + mov r9, #26 +endif_2: + add r9, r9, #1 + cmp r9, #27 + bne countermeasure + ldr r0, [sp, #8] + mov r1, r0 + ldr r0, [sp, #24] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_3 + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + mov r9, #27 + b endif_3 +else_3: + mov r9, #27 +endif_3: + add r9, r9, #1 + cmp r9, #28 + bne countermeasure + ldr r0, [sp, #4] + mov r1, r0 + ldr r0, [sp, #20] + cmp r1, r0 + mov r0, #0 + it ne + movne r0, #1 + cmp r0, #0 + beq else_4 + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + mov r0, #0 + str r0, [sp] + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + mov r9, #28 + b endif_4 +else_4: + mov r9, #28 +endif_4: + add r9, r9, #1 + cmp r9, #29 + bne countermeasure + ldr r0, [sp, #0] + mov r1, r0 + mov r0, #1 + cmp r1, r0 + mov r0, #0 + it eq + moveq r0, #1 + cmp r0, #0 + beq else_5 + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + mov r0, #3 + str r0, [sp, #40] + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + add r9, r9, #1 + cmp r9, #32 + bne countermeasure + mov r0, #1 + str r0, [sp, #36] + add r9, r9, #1 + cmp r9, #33 + bne countermeasure + add r9, r9, #1 + cmp r9, #34 + bne countermeasure + mov r9, #29 + b endif_5 +else_5: + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + ldr r0, [sp, #40] + mov r1, r0 + mov r0, #1 + sub r0, r1, r0 + str r0, [sp, #40] + add r9, r9, #1 + cmp r9, #31 + bne countermeasure + add r9, r9, #1 + cmp r9, #32 + bne countermeasure + mov r9, #29 +endif_5: + add r9, r9, #1 + cmp r9, #30 + bne countermeasure + add sp, sp, #4 + mov r9, #22 + b endif_0 +else_0: + mov r9, #22 +endif_0: + add r9, r9, #1 + cmp r9, #23 + bne countermeasure + mov r0, #1 + ldr r1, =.Lstr0 + mov r2, #17 + mov r7, #4 + svc #0 + ldr r0, [sp, #32] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_6 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_6 +print_int_loop_6: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_6 +print_int_done_6: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + add r9, r9, #1 + cmp r9, #24 + bne countermeasure + mov r0, #1 + ldr r1, =.Lstr1 + mov r2, #7 + mov r7, #4 + svc #0 + ldr r0, [sp, #36] + mov r4, r0 + ldr r1, =num_buf + add r1, r1, #16 + mov r2, #0 + cmp r4, #0 + bne print_int_loop_7 + mov r3, #48 + sub r1, r1, #1 + strb r3, [r1] + mov r2, #1 + b print_int_done_7 +print_int_loop_7: + mov r0, r4 + mov r3, #10 + sdiv r5, r0, r3 + mul r6, r5, r3 + sub r7, r0, r6 + add r7, r7, #48 + sub r1, r1, #1 + strb r7, [r1] + add r2, r2, #1 + mov r4, r5 + cmp r4, #0 + bne print_int_loop_7 +print_int_done_7: + mov r0, #1 + mov r1, r1 + mov r2, r2 + mov r7, #4 + svc #0 + mov r0, #1 + ldr r1, =newline + mov r2, #1 + mov r7, #4 + svc #0 + add r9, r9, #1 + cmp r9, #25 + bne countermeasure + ldr r0, [sp, #32] + mov r7, #1 + svc #0 + add r9, r9, #1 + cmp r9, #26 + bne countermeasure +countermeasure: + mov r0, #77 + mov r7, #1 + svc #0 + +.size _start, .-_start + +.section .data +.Lstr0: + .ascii "g_authenticated: " +.Lstr1: + .ascii "g_ptc: " +newline: + .ascii "\n" +num_buf: + .space 16 +step_counter: + .word 0 +fault_msg: + .ascii "Control flow violation detected\n" diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 62f1fdc..559884d 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -1018,6 +1018,7 @@ impl Interpreter { self.set_pc(self.pc + 1); continue; // Skip the match logic entirely } + match instruction { f if f.starts_with("mov") => self.exec_mov(instruction.clone()), f if f.starts_with("svc") => { From 8fa1511f7e86fe4a05168c04c614037e5fed3beb Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Mar 2026 13:23:47 +0100 Subject: [PATCH 32/34] fixed tests --- compiler/test_codes/simple.trv.output | 2 +- interpreter/src/interpreter.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/test_codes/simple.trv.output b/compiler/test_codes/simple.trv.output index 48082f7..b4de394 100644 --- a/compiler/test_codes/simple.trv.output +++ b/compiler/test_codes/simple.trv.output @@ -1 +1 @@ -12 +11 diff --git a/interpreter/src/interpreter.rs b/interpreter/src/interpreter.rs index 559884d..4ef3f87 100644 --- a/interpreter/src/interpreter.rs +++ b/interpreter/src/interpreter.rs @@ -757,7 +757,7 @@ impl Interpreter { } let parts: Vec<&str> = content - .split(|c: char| (c == ',' || c.is_whitespace())) + .split(|c: char| c == ',' || c.is_whitespace()) .filter(|s| !s.is_empty()) .collect(); From 8c0ed3813e44ba6a12182db586be8ac10e53c629 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Mar 2026 13:25:56 +0100 Subject: [PATCH 33/34] updated ci --- .github/workflows/ci.yml | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5660ea5..5facfdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,48 +8,49 @@ env: CARGO_TERM_COLOR: always jobs: - # This job handles all testing - test-compiler: + # Now we split the builds into separate jobs + build-compiler: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable # ... (insert your cache step here) ... - - name: Compiler Tests + - name: Build Compiler working-directory: ./compiler - run: cargo test - - test-interpreter: + run: cargo build --release + + build-interpreter: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable # ... (insert your cache step here) ... - - name: Interpreter Tests + - name: Build Interpreter working-directory: ./interpreter - run: cargo test + run: cargo build --release - # Now we split the builds into separate jobs - build-compiler: + # This job handles all testing + test-compiler: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable # ... (insert your cache step here) ... - - name: Build Compiler + - name: Compiler Tests working-directory: ./compiler - run: cargo build --release - - build-interpreter: + run: cargo test + + test-interpreter: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable # ... (insert your cache step here) ... - - name: Build Interpreter + - name: Interpreter Tests working-directory: ./interpreter - run: cargo build --release + run: cargo test + From ee5530466ff04fc33904f4eab06a8c8691d18c34 Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 26 Mar 2026 13:32:46 +0100 Subject: [PATCH 34/34] qemu stuff for ci --- .github/workflows/ci.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5facfdf..48c37a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,8 +14,10 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - # ... (insert your cache step here) ... + - name: Install ARM tools + run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi qemu-user + - name: Build Compiler working-directory: ./compiler run: cargo build --release @@ -25,8 +27,10 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - # ... (insert your cache step here) ... + - name: Install ARM tools + run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi qemu-user + - name: Build Interpreter working-directory: ./interpreter run: cargo build --release @@ -37,7 +41,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - # ... (insert your cache step here) ... + + - name: Install ARM tools + run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi qemu-user - name: Compiler Tests working-directory: ./compiler @@ -48,7 +54,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - # ... (insert your cache step here) ... + + - name: Install ARM tools + run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi qemu-user - name: Interpreter Tests working-directory: ./interpreter