From f77e8988e221660672046485b9150fa275821455 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:46:41 -0800 Subject: [PATCH 01/27] instruction: split arm, riscv opcodes and add registers --- src/instruction.rs | 220 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 199 insertions(+), 21 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 564e52a..9e36b3c 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -3,17 +3,31 @@ /// /// We do not aim for completness of translating every possible instruction, /// but we do want to thoroughly test for correctness. +/// +/// Some relevant references for making enums of instructions +/// https://github.com/lmcad-unicamp/riscv-sbt/blob/93bd48525362d00c6a2d7b320dc9cd9e62bc8fa9/sbt/Instruction.h#L62 +/// https://github.com/nbdd0121/r2vm/blob/5118be6b9e757c6fef2f019385873f403c23c548/lib/riscv/src/op.rs#L30 use strum_macros::EnumString; +/// RISC-V Instructions +/// +/// To make a function call in RISC-V you use the `jal` (jump and link) +/// instruction. This would require us ensure that we translate the RISC-V +/// calling convention into ARM. (`https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf) #[derive(Debug, EnumString)] -pub enum Instruction { - // RISC-V Instructions +pub enum RiscVInstruction { #[strum(serialize = "addi")] - Addi, + Addi { + dest: RiscVRegister, + src: RiscVRegister, + imm: i32, + }, #[strum(serialize = "sd")] Sd, #[strum(serialize = "ld")] Ld, + #[strum(serialize = "lw")] + Lw, #[strum(serialize = "sw")] Sw, #[strum(serialize = "lw")] @@ -28,27 +42,191 @@ pub enum Instruction { Jr, #[strum(serialize = "li")] Li, +} - // ARM Instructions +/// ARM Instructions +/// `https://iitd-plos.github.io/col718/ref/arm-instructionset.pdf#page=3` +#[derive(Debug, EnumString)] +pub enum ArmInstruction { + /// ADC Add with carry + /// + /// `Rd := Rn + Op2 + Carry` + #[strum(serialize = "adc")] + Adc, + /// ADD Add Rd := Rn + Op2 #[strum(serialize = "add")] - Add, - #[strum(serialize = "sub")] - Sub, - #[strum(serialize = "mov")] - Mov, - #[strum(serialize = "ldr")] - Ldr, - #[strum(serialize = "str")] - Str, + Add { + dest: ArmRegister, + arg1: ArmRegister, + arg2: ArmRegister, + }, + /// AND AND Rd := Rn AND Op2 + #[strum(serialize = "and")] + And, + /// B Branch R15 := address #[strum(serialize = "b")] B, - #[strum(serialize = "bl")] - Bl, - #[strum(serialize = "bx")] - Bx, - #[strum(serialize = "cmp")] - Cmp, - #[strum(serialize = "beq")] - Beq, } +/// RISC-V Registers +/// https://msyksphinz-self.github.io/riscv-isadoc/html/regs.html +#[derive(Debug, EnumString)] +pub enum RiscVRegister { + /// This is for arguments to opcodes which have an offset + /// I'm not sure how to make strum happy, so this doesn't auto parse. + #[strum(disabled)] + Offset { + register: Box, + offset: usize, + }, + #[strum(serialize = "x0")] + /// Hard-wired zero + X0, + #[strum(serialize = "ra")] + /// Return address + RA, + #[strum(serialize = "sp")] + /// Stack pointer + SP, + #[strum(serialize = "gp")] + /// Global pointer + GP, + #[strum(serialize = "tp")] + /// Thread pointer + TP, + #[strum(serialize = "t0")] + /// Temporary/alternate link register + T0, + #[strum(serialize = "t1")] + /// Temporaries + T1, + #[strum(serialize = "t2")] + /// Temporaries + T2, + #[strum(serialize = "s0", serialize = "fp")] + /// Saved register/frame pointer + S0FP, + #[strum(serialize = "s1")] + /// Saved registers + S1, + #[strum(serialize = "a0")] + /// Function arguments/return values + A0, + #[strum(serialize = "a1")] + /// Function arguments/return values + A1, + #[strum(serialize = "a2")] + /// Function arguments + A2, + #[strum(serialize = "a3")] + /// Function arguments + A3, + #[strum(serialize = "a4")] + /// Function arguments + A4, + #[strum(serialize = "a5")] + /// Function arguments + A5, + #[strum(serialize = "a6")] + /// Function arguments + A6, + #[strum(serialize = "a7")] + /// Function arguments + A7, + #[strum(serialize = "s2")] + /// Saved registers + S2, + #[strum(serialize = "s3")] + /// Saved registers + S3, + #[strum(serialize = "s4")] + /// Saved registers + S4, + #[strum(serialize = "s5")] + /// Saved registers + S5, + #[strum(serialize = "s6")] + /// Saved registers + S6, + #[strum(serialize = "s7")] + /// Saved registers + S7, + #[strum(serialize = "s8")] + /// Saved registers + S8, + #[strum(serialize = "s9")] + /// Saved registers + S9, + #[strum(serialize = "s10")] + /// Saved registers + S10, + #[strum(serialize = "s11")] + /// Saved registers + S11, + #[strum(serialize = "t3")] + /// Temporaries + T3, + #[strum(serialize = "t4")] + /// Temporaries + T4, + #[strum(serialize = "t5")] + /// Temporaries + T5, + #[strum(serialize = "t6")] + /// Temporaries + T6, +} + +/// ARM Registers +/// https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names +#[derive(Debug, EnumString)] +pub enum ArmRegister { + #[strum(serialize = "pc")] + /// Program counter. + Pc, + #[strum(serialize = "lr")] + /// Link register. + Lr, + #[strum(serialize = "sp")] + /// Stack pointer. + Sp, + #[strum(serialize = "ip")] + /// Intra-procedure-call scratch register. + Ip, + #[strum(serialize = "v8")] + /// ARM-state variable register 8. + V8, + #[strum(serialize = "sl")] + /// ARM-state variable register 7. Stack limit pointer in stack-checked variants. + Sl, + #[strum(serialize = "sb")] + /// ARM-state variable register 6. Static base in RWPI variants. + Sb, + #[strum(serialize = "v5")] + /// ARM-state variable register 5. + V5, + #[strum(serialize = "v4")] + /// Variable register 4. + V4, + #[strum(serialize = "v3")] + /// Variable register 3. + V3, + #[strum(serialize = "v2")] + /// Variable register 2. + V2, + #[strum(serialize = "v1")] + /// Variable register 1. + V1, + #[strum(serialize = "a4")] + /// Argument/result/scratch register 4. + A4, + #[strum(serialize = "a3")] + /// Argument/result/scratch register 3. + A3, + #[strum(serialize = "a2")] + /// Argument/result/scratch register 2. + A2, + #[strum(serialize = "a1")] + /// Argument/result/scratch register 1. + A1, +} From 98fe35ea398601562df7db50bd52f9b291d82112 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:47:25 -0800 Subject: [PATCH 02/27] translate: add minimal riscv translation map --- src/main.rs | 7 ++++--- src/translate.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/translate.rs diff --git a/src/main.rs b/src/main.rs index 87c6374..81ef70b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ use std::fs; use std::str::FromStr; mod instruction; -use instruction::Instruction; +pub mod translate; +use instruction::RiscVInstruction; /// Parse a text file into our enum. -fn parse_asm(asm: &str) -> Vec { +fn parse_asm(asm: &str) -> Vec { asm.lines() .filter_map(|line| { // TODO (Samir): Not sure that this will handle assembly labels @@ -14,7 +15,7 @@ fn parse_asm(asm: &str) -> Vec { if parts.is_empty() { None } else { - Instruction::from_str(parts[0]).ok() + RiscVInstruction::from_str(parts[0]).ok() } }) .collect() diff --git a/src/translate.rs b/src/translate.rs new file mode 100644 index 0000000..6c6eca3 --- /dev/null +++ b/src/translate.rs @@ -0,0 +1,19 @@ +use crate::instruction::{ArmInstruction, RiscVInstruction}; + +/// Run the core logic to match from RISC-V to ARM Instructions. + +/// Translate one instruction at a time. +pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { + match riscv_instr { + RiscVInstruction::Addi => add, + RiscVInstruction::Sd => todo!(), + RiscVInstruction::Ld => todo!(), + RiscVInstruction::Sw => todo!(), + RiscVInstruction::Lw => todo!(), + RiscVInstruction::Mv => todo!(), + RiscVInstruction::Addw => todo!(), + RiscVInstruction::SextW => todo!(), + RiscVInstruction::Jr => todo!(), + RiscVInstruction::Li => todo!(), + } +} From 89f727653b76863a22ef6d08bcbae1c63832e03e Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:47:57 -0800 Subject: [PATCH 03/27] meta: rename `test/` -> `tests/` --- test/binaries/add.c | 7 ---- test/test_parse_asm.rs | 48 ------------------------- test/test_translation.rs | 50 -------------------------- {test => tests}/binaries/Makefile | 0 {test => tests}/binaries/README.md | 0 tests/binaries/add.c | 41 +++++++++++++++++++++ {test => tests}/binaries/add.riscv.s | 0 {test => tests}/binaries/add.x86.s | 0 {test => tests}/binaries/flake.lock | 0 {test => tests}/binaries/flake.nix | 0 {test => tests}/binaries/hello_world.c | 0 tests/test_parse_asm.rs | 49 +++++++++++++++++++++++++ tests/test_translation.rs | 50 ++++++++++++++++++++++++++ 13 files changed, 140 insertions(+), 105 deletions(-) delete mode 100644 test/binaries/add.c delete mode 100644 test/test_parse_asm.rs delete mode 100644 test/test_translation.rs rename {test => tests}/binaries/Makefile (100%) rename {test => tests}/binaries/README.md (100%) create mode 100644 tests/binaries/add.c rename {test => tests}/binaries/add.riscv.s (100%) rename {test => tests}/binaries/add.x86.s (100%) rename {test => tests}/binaries/flake.lock (100%) rename {test => tests}/binaries/flake.nix (100%) rename {test => tests}/binaries/hello_world.c (100%) create mode 100644 tests/test_parse_asm.rs create mode 100644 tests/test_translation.rs diff --git a/test/binaries/add.c b/test/binaries/add.c deleted file mode 100644 index c8fff0f..0000000 --- a/test/binaries/add.c +++ /dev/null @@ -1,7 +0,0 @@ -int main(void) { - int x = 3; - int y = 4; - - return x + y; -} - diff --git a/test/test_parse_asm.rs b/test/test_parse_asm.rs deleted file mode 100644 index 6c6050a..0000000 --- a/test/test_parse_asm.rs +++ /dev/null @@ -1,48 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_asm() { - let asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let instructions = parse_asm(asm); - assert_eq!(instructions.len(), 17); - assert_eq!(instructions[0], Instruction::Addi); - assert_eq!(instructions[1], Instruction::Sd); - assert_eq!(instructions[2], Instruction::Ld); - assert_eq!(instructions[3], Instruction::Addi); - assert_eq!(instructions[4], Instruction::Li); - assert_eq!(instructions[5], Instruction::Sw); - assert_eq!(instructions[6], Instruction::Li); - assert_eq!(instructions[7], Instruction::Sw); - assert_eq!(instructions[8], Instruction::Lw); - assert_eq!(instructions[9], Instruction::Mv); - assert_eq!(instructions[10], Instruction::Lw); - assert_eq!(instructions[11], Instruction::Addw); - assert_eq!(instructions[12], Instruction::SextW); - assert_eq!(instructions[13], Instruction::Mv); - assert_eq!(instructions[14], Instruction::Ld); - assert_eq!(instructions[15], Instruction::Ld); - assert_eq!(instructions[16], Instruction::Addi); - assert_eq!(instructions[17], Instruction::Jr); - } -} diff --git a/test/test_translation.rs b/test/test_translation.rs deleted file mode 100644 index a652bd4..0000000 --- a/test/test_translation.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_binary_translate() { - let riscv_asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let translated_asm = binary_translate(riscv_asm); - let expected_output = " - Addi - Sd - Ld - Addi - Li - Sw - Li - Sw - Lw - Mv - Lw - Addw - SextW - Mv - Ld - Ld - Addi - Jr - "; - assert_eq!(translated_asm, expected_output); - } -} diff --git a/test/binaries/Makefile b/tests/binaries/Makefile similarity index 100% rename from test/binaries/Makefile rename to tests/binaries/Makefile diff --git a/test/binaries/README.md b/tests/binaries/README.md similarity index 100% rename from test/binaries/README.md rename to tests/binaries/README.md diff --git a/tests/binaries/add.c b/tests/binaries/add.c new file mode 100644 index 0000000..c5750d5 --- /dev/null +++ b/tests/binaries/add.c @@ -0,0 +1,41 @@ +int main(void) { + int x = 3; + int y = 4; + + return x + y; +} + +//////////////// arm +// main: +// sub sp, sp, #16 +// mov w0, 3 +// str w0, [sp, 12] +// mov w0, 4 +// str w0, [sp, 8] +// ldr w1, [sp, 12] +// ldr w0, [sp, 8] +// add w0, w1, w0 +// add sp, sp, 16 +// ret + +//////////// riscv +// https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:8,positionColumn:1,positionLineNumber:8,selectionStartColumn:1,selectionStartLineNumber:8,startColumn:1,startLineNumber:8),source:'int+main(void)+%7B%0A%09int+x+%3D+3%3B%0A%09int+y+%3D+4%3B%0A%0A%09return+x+%2B+y%3B%0A%7D%0A%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:rv64-gcc1420,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'',overrides:!(),selection:(endColumn:19,endLineNumber:19,positionColumn:19,positionLineNumber:19,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+RISC-V+(64-bits)+gcc+14.2.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 +// main: +// addi sp,sp,-32 +// sd ra,24(sp) +// sd s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld ß s0,16(sp) +// addi sp,sp,32 +// jr ra diff --git a/test/binaries/add.riscv.s b/tests/binaries/add.riscv.s similarity index 100% rename from test/binaries/add.riscv.s rename to tests/binaries/add.riscv.s diff --git a/test/binaries/add.x86.s b/tests/binaries/add.x86.s similarity index 100% rename from test/binaries/add.x86.s rename to tests/binaries/add.x86.s diff --git a/test/binaries/flake.lock b/tests/binaries/flake.lock similarity index 100% rename from test/binaries/flake.lock rename to tests/binaries/flake.lock diff --git a/test/binaries/flake.nix b/tests/binaries/flake.nix similarity index 100% rename from test/binaries/flake.nix rename to tests/binaries/flake.nix diff --git a/test/binaries/hello_world.c b/tests/binaries/hello_world.c similarity index 100% rename from test/binaries/hello_world.c rename to tests/binaries/hello_world.c diff --git a/tests/test_parse_asm.rs b/tests/test_parse_asm.rs new file mode 100644 index 0000000..0532a2b --- /dev/null +++ b/tests/test_parse_asm.rs @@ -0,0 +1,49 @@ +// #[cfg(test)] +// mod tests { +// use super::RiscVInstruction; +// use super::*; + +// #[test] +// fn test_parse_asm() { +// let asm = " +// addi sp,sp,-32 +// sd ra,24(sp) +// ld s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld s0,16(sp) +// addi sp,sp,32 +// jr ra +// "; +// let instructions = parse_asm(asm); +// assert_eq!(instructions.len(), 17); +// assert_eq!(instructions[0], RiscVInstruction::Addi); +// assert_eq!(instructions[1], RiscVInstruction::Sd); +// assert_eq!(instructions[2], RiscVInstruction::Ld); +// assert_eq!(instructions[3], RiscVInstruction::Addi); +// assert_eq!(instructions[4], RiscVInstruction::Li); +// assert_eq!(instructions[5], RiscVInstruction::Sw); +// assert_eq!(instructions[6], RiscVInstruction::Li); +// assert_eq!(instructions[7], RiscVInstruction::Sw); +// assert_eq!(instructions[8], RiscVInstruction::Lw); +// assert_eq!(instructions[9], RiscVInstruction::Mv); +// assert_eq!(instructions[10], RiscVInstruction::Lw); +// assert_eq!(instructions[11], RiscVInstruction::Addw); +// assert_eq!(instructions[12], RiscVInstruction::SextW); +// assert_eq!(instructions[13], RiscVInstruction::Mv); +// assert_eq!(instructions[14], RiscVInstruction::Ld); +// assert_eq!(instructions[15], RiscVInstruction::Ld); +// assert_eq!(instructions[16], RiscVInstruction::Addi); +// assert_eq!(instructions[17], RiscVInstruction::Jr); +// } +// } diff --git a/tests/test_translation.rs b/tests/test_translation.rs new file mode 100644 index 0000000..4ac049e --- /dev/null +++ b/tests/test_translation.rs @@ -0,0 +1,50 @@ +// #[cfg(test)] +// mod tests { +// use super::*; + +// #[test] +// fn test_binary_translate() { +// let riscv_asm = " +// addi sp,sp,-32 +// sd ra,24(sp) +// ld s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld s0,16(sp) +// addi sp,sp,32 +// jr ra +// "; +// let translated_asm = binary_translate(riscv_asm); +// let expected_output = " +// Addi +// Sd +// Ld +// Addi +// Li +// Sw +// Li +// Sw +// Lw +// Mv +// Lw +// Addw +// SextW +// Mv +// Ld +// Ld +// Addi +// Jr +// "; +// assert_eq!(translated_asm, expected_output); +// } +// } From 3279689e33e022ad95806f5fc3acfc6bf9e5aa17 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 8 Feb 2025 21:03:33 -0800 Subject: [PATCH 04/27] test imports --- src/instruction.rs | 17 +++++++ src/lib.rs | 2 + src/main.rs | 28 +---------- src/translate.rs | 15 +++++- tests/test_parse_asm.rs | 95 +++++++++++++++++++------------------ tests/test_translation.rs | 98 +++++++++++++++++++-------------------- 6 files changed, 129 insertions(+), 126 deletions(-) create mode 100644 src/lib.rs diff --git a/src/instruction.rs b/src/instruction.rs index 9e36b3c..6684fe1 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -230,3 +230,20 @@ pub enum ArmRegister { /// Argument/result/scratch register 1. A1, } + +/// Parse a text file into our enum. +pub fn parse_asm(asm: &str) -> Vec { + asm.lines() + .filter_map(|line| { + // TODO (Samir): Not sure that this will handle assembly labels + // We probably need to construct a map for those to find the + // original instruction they map to. + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.is_empty() { + None + } else { + RiscVInstruction::from_str(parts[0]).ok() + } + }) + .collect() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..28612f2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +pub mod instruction; +pub mod translate; diff --git a/src/main.rs b/src/main.rs index 81ef70b..ee6bcba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,36 +1,10 @@ use std::fs; use std::str::FromStr; -mod instruction; +pub mod instruction; pub mod translate; use instruction::RiscVInstruction; -/// Parse a text file into our enum. -fn parse_asm(asm: &str) -> Vec { - asm.lines() - .filter_map(|line| { - // TODO (Samir): Not sure that this will handle assembly labels - // We probably need to construct a map for those to find the - // original instruction they map to. - let parts: Vec<&str> = line.split_whitespace().collect(); - if parts.is_empty() { - None - } else { - RiscVInstruction::from_str(parts[0]).ok() - } - }) - .collect() -} -/// Runs binary translation -/// text file -> [`Instruction`] enum array -> text file -fn binary_translate(riscv_asm: &str) -> String { - let instructions = parse_asm(riscv_asm); - instructions - .into_iter() - .map(|instr| format!("{:?}", instr)) - .collect::>() - .join("\n") -} // Samir: I am using main for testing, but it not needed since you can run // `cargo test` instead. diff --git a/src/translate.rs b/src/translate.rs index 6c6eca3..17d5388 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -1,11 +1,11 @@ -use crate::instruction::{ArmInstruction, RiscVInstruction}; +use crate::instruction::{ArmInstruction, RiscVInstruction, parse_asm}; /// Run the core logic to match from RISC-V to ARM Instructions. /// Translate one instruction at a time. pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { match riscv_instr { - RiscVInstruction::Addi => add, + RiscVInstruction::Addi => todo!(), RiscVInstruction::Sd => todo!(), RiscVInstruction::Ld => todo!(), RiscVInstruction::Sw => todo!(), @@ -17,3 +17,14 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { RiscVInstruction::Li => todo!(), } } + +/// Runs binary translation +/// text file -> [`Instruction`] enum array -> text file +pub fn binary_translate(riscv_asm: &str) -> String { + let instructions = parse_asm(riscv_asm); + instructions + .into_iter() + .map(|instr| format!("{:?}", instr)) + .collect::>() + .join("\n") +} diff --git a/tests/test_parse_asm.rs b/tests/test_parse_asm.rs index 0532a2b..0c0372f 100644 --- a/tests/test_parse_asm.rs +++ b/tests/test_parse_asm.rs @@ -1,49 +1,48 @@ -// #[cfg(test)] -// mod tests { -// use super::RiscVInstruction; -// use super::*; +#[cfg(test)] +mod tests { + use binary_room::instruction::parse_asm; -// #[test] -// fn test_parse_asm() { -// let asm = " -// addi sp,sp,-32 -// sd ra,24(sp) -// ld s0,16(sp) -// addi s0,sp,32 -// li a5,3 -// sw a5,-20(s0) -// li a5,4 -// sw a5,-24(s0) -// lw a5,-20(s0) -// mv a4,a5 -// lw a5,-24(s0) -// addw a5,a4,a5 -// sext.w a5,a5 -// mv a0,a5 -// ld ra,24(sp) -// ld s0,16(sp) -// addi sp,sp,32 -// jr ra -// "; -// let instructions = parse_asm(asm); -// assert_eq!(instructions.len(), 17); -// assert_eq!(instructions[0], RiscVInstruction::Addi); -// assert_eq!(instructions[1], RiscVInstruction::Sd); -// assert_eq!(instructions[2], RiscVInstruction::Ld); -// assert_eq!(instructions[3], RiscVInstruction::Addi); -// assert_eq!(instructions[4], RiscVInstruction::Li); -// assert_eq!(instructions[5], RiscVInstruction::Sw); -// assert_eq!(instructions[6], RiscVInstruction::Li); -// assert_eq!(instructions[7], RiscVInstruction::Sw); -// assert_eq!(instructions[8], RiscVInstruction::Lw); -// assert_eq!(instructions[9], RiscVInstruction::Mv); -// assert_eq!(instructions[10], RiscVInstruction::Lw); -// assert_eq!(instructions[11], RiscVInstruction::Addw); -// assert_eq!(instructions[12], RiscVInstruction::SextW); -// assert_eq!(instructions[13], RiscVInstruction::Mv); -// assert_eq!(instructions[14], RiscVInstruction::Ld); -// assert_eq!(instructions[15], RiscVInstruction::Ld); -// assert_eq!(instructions[16], RiscVInstruction::Addi); -// assert_eq!(instructions[17], RiscVInstruction::Jr); -// } -// } + #[test] + fn test_parse_asm() { + let asm = " + addi sp,sp,-32 + sd ra,24(sp) + ld s0,16(sp) + addi s0,sp,32 + li a5,3 + sw a5,-20(s0) + li a5,4 + sw a5,-24(s0) + lw a5,-20(s0) + mv a4,a5 + lw a5,-24(s0) + addw a5,a4,a5 + sext.w a5,a5 + mv a0,a5 + ld ra,24(sp) + ld s0,16(sp) + addi sp,sp,32 + jr ra + "; + let instructions = parse_asm(asm); + assert_eq!(instructions.len(), 17); + assert_eq!(instructions[0], RiscVInstruction::Addi); + assert_eq!(instructions[1], RiscVInstruction::Sd); + assert_eq!(instructions[2], RiscVInstruction::Ld); + assert_eq!(instructions[3], RiscVInstruction::Addi); + assert_eq!(instructions[4], RiscVInstruction::Li); + assert_eq!(instructions[5], RiscVInstruction::Sw); + assert_eq!(instructions[6], RiscVInstruction::Li); + assert_eq!(instructions[7], RiscVInstruction::Sw); + assert_eq!(instructions[8], RiscVInstruction::Lw); + assert_eq!(instructions[9], RiscVInstruction::Mv); + assert_eq!(instructions[10], RiscVInstruction::Lw); + assert_eq!(instructions[11], RiscVInstruction::Addw); + assert_eq!(instructions[12], RiscVInstruction::SextW); + assert_eq!(instructions[13], RiscVInstruction::Mv); + assert_eq!(instructions[14], RiscVInstruction::Ld); + assert_eq!(instructions[15], RiscVInstruction::Ld); + assert_eq!(instructions[16], RiscVInstruction::Addi); + assert_eq!(instructions[17], RiscVInstruction::Jr); + } +} diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 4ac049e..5e5011c 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -1,50 +1,50 @@ -// #[cfg(test)] -// mod tests { -// use super::*; +#[cfg(test)] +mod tests { + use binary_room::translate::binary_translate; -// #[test] -// fn test_binary_translate() { -// let riscv_asm = " -// addi sp,sp,-32 -// sd ra,24(sp) -// ld s0,16(sp) -// addi s0,sp,32 -// li a5,3 -// sw a5,-20(s0) -// li a5,4 -// sw a5,-24(s0) -// lw a5,-20(s0) -// mv a4,a5 -// lw a5,-24(s0) -// addw a5,a4,a5 -// sext.w a5,a5 -// mv a0,a5 -// ld ra,24(sp) -// ld s0,16(sp) -// addi sp,sp,32 -// jr ra -// "; -// let translated_asm = binary_translate(riscv_asm); -// let expected_output = " -// Addi -// Sd -// Ld -// Addi -// Li -// Sw -// Li -// Sw -// Lw -// Mv -// Lw -// Addw -// SextW -// Mv -// Ld -// Ld -// Addi -// Jr -// "; -// assert_eq!(translated_asm, expected_output); -// } -// } + #[test] + fn test_binary_translate() { + let riscv_asm = " + addi sp,sp,-32 + sd ra,24(sp) + ld s0,16(sp) + addi s0,sp,32 + li a5,3 + sw a5,-20(s0) + li a5,4 + sw a5,-24(s0) + lw a5,-20(s0) + mv a4,a5 + lw a5,-24(s0) + addw a5,a4,a5 + sext.w a5,a5 + mv a0,a5 + ld ra,24(sp) + ld s0,16(sp) + addi sp,sp,32 + jr ra + "; + let translated_asm = binary_translate(riscv_asm); + let expected_output = " + Addi + Sd + Ld + Addi + Li + Sw + Li + Sw + Lw + Mv + Lw + Addw + SextW + Mv + Ld + Ld + Addi + Jr + "; + assert_eq!(translated_asm, expected_output); + } +} From 4034b1dfbd426f9281a016c58e6523d2edb05f3b Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 21:55:23 -0800 Subject: [PATCH 05/27] instruction: specify arguments to RISC-V ops --- src/instruction.rs | 86 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 6684fe1..ca4ec5a 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -10,38 +10,76 @@ use strum_macros::EnumString; /// RISC-V Instructions +/// https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html /// /// To make a function call in RISC-V you use the `jal` (jump and link) /// instruction. This would require us ensure that we translate the RISC-V /// calling convention into ARM. (`https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf) #[derive(Debug, EnumString)] pub enum RiscVInstruction { + /// add immediate + /// + /// `x[rd] = x[rs1] + sext(immediate)` #[strum(serialize = "addi")] Addi { dest: RiscVRegister, src: RiscVRegister, imm: i32, }, + /// Store 64-bit, values from register rs2 to memory. + /// + /// `M[x[rs1] + sext(offset)] = x[rs2][63:0]` #[strum(serialize = "sd")] - Sd, + Sd { + dest: RiscVRegister, + src: RiscVRegister, + }, + /// Loads a 64-bit value from memory into register rd for RV64I. + /// + /// `x[rd] = M[x[rs1] + sext(offset)][63:0]` #[strum(serialize = "ld")] - Ld, + Ld { dest: RiscVRegister, src: RiscVVal }, + /// Loads a 32-bit value from memory and sign-extends this to XLEN bits + /// before storing it in register rd. + /// + /// `x[rd] = sext(M[x[rs1] + sext(offset)][31:0])` #[strum(serialize = "lw")] - Lw, + Lw { dest: RiscVRegister, src: RiscVVal }, + /// Store 32-bit, values from the low bits of register rs2 to memory. + /// + /// `M[x[rs1] + sext(offset)] = x[rs2][31:0]` #[strum(serialize = "sw")] - Sw, - #[strum(serialize = "lw")] - Lw, + Sw { dest: RiscVRegister, src: RiscVVal }, + // Copy register + // `mv rd, rs1` expands to `addi rd, rs, 0` #[strum(serialize = "mv")] - Mv, + Mv { + dest: RiscVRegister, + src: RiscVRegister, + }, #[strum(serialize = "addw")] Addw, + /// Sign extend Word + /// + /// psuedo instruction which translates to `addiw rd, rs, 0` #[strum(serialize = "sext.w")] - SextW, + SextW { + dest: RiscVRegister, + src: RiscVRegister, + }, #[strum(serialize = "jr")] - Jr, + Jr { target: RiscVRegister }, + /// Load Immediate + /// This is a pseudo instruction, so it's not a real instruction + /// + /// Assembler Pseudo-instructions + /// The assembler implements a number of convenience psuedo-instructions + /// that are formed from instructions in the base ISA, but have implicit + /// arguments or in some case reversed arguments, that result in distinct + /// semantics. + /// https://michaeljclark.github.io/asm.html #[strum(serialize = "li")] - Li, + Li { imm: i32 }, } /// ARM Instructions @@ -66,19 +104,33 @@ pub enum ArmInstruction { /// B Branch R15 := address #[strum(serialize = "b")] B, + #[strum(serialize = "ldr")] + Ldr, + #[strum(serialize = "mov")] + Mov, + #[strum(serialize = "ret")] + Ret, + #[strum(serialize = "str")] + Str, + #[strum(serialize = "sub")] + Sub, } -/// RISC-V Registers -/// https://msyksphinz-self.github.io/riscv-isadoc/html/regs.html -#[derive(Debug, EnumString)] -pub enum RiscVRegister { +#[derive(Debug)] +pub enum RiscVVal { + RiscVRegister, + Immediate(i32), /// This is for arguments to opcodes which have an offset - /// I'm not sure how to make strum happy, so this doesn't auto parse. - #[strum(disabled)] Offset { register: Box, - offset: usize, + offset: i32, }, +} + +/// RISC-V Registers +/// https://msyksphinz-self.github.io/riscv-isadoc/html/regs.html +#[derive(Debug, EnumString)] +pub enum RiscVRegister { #[strum(serialize = "x0")] /// Hard-wired zero X0, From 2c4fa41c37fc46badf6519a823015d1bbb7e045a Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 8 Feb 2025 21:58:31 -0800 Subject: [PATCH 06/27] wip translations --- src/instruction.rs | 22 +++++++++++++++++++--- src/translate.rs | 13 +++++++++++-- tests/binaries/add.c | 28 ++++++++++++++-------------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index ca4ec5a..4a54cfb 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -82,6 +82,13 @@ pub enum RiscVInstruction { Li { imm: i32 }, } +#[derive(Debug)] +pub enum ArmVal { + Reg(ArmRegister), + Imm(i32), + RegOffset(ArmRegister, i32), +} + /// ARM Instructions /// `https://iitd-plos.github.io/col718/ref/arm-instructionset.pdf#page=3` #[derive(Debug, EnumString)] @@ -96,7 +103,7 @@ pub enum ArmInstruction { Add { dest: ArmRegister, arg1: ArmRegister, - arg2: ArmRegister, + arg2: ArmVal, }, /// AND AND Rd := Rn AND Op2 #[strum(serialize = "and")] @@ -110,10 +117,19 @@ pub enum ArmInstruction { Mov, #[strum(serialize = "ret")] Ret, + /// Str [r2 + offset] = r1 #[strum(serialize = "str")] - Str, + Str { + src: ArmRegister, + dst: ArmVal, + } + /// Sub Sub Rd := Rn - Op2 #[strum(serialize = "sub")] - Sub, + Sub { + dest: ArmRegister, + arg1: ArmRegister, + arg2: ArmVal, + }, } #[derive(Debug)] diff --git a/src/translate.rs b/src/translate.rs index 17d5388..ed4b153 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -1,11 +1,16 @@ -use crate::instruction::{ArmInstruction, RiscVInstruction, parse_asm}; +use crate::instruction::{parse_asm, ArmInstruction, ArmRegister, ArmVal, RiscVInstruction, RiscVRegister}; /// Run the core logic to match from RISC-V to ARM Instructions. /// Translate one instruction at a time. pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { match riscv_instr { - RiscVInstruction::Addi => todo!(), + RiscVInstruction::Addi {dest, src, imm} => + if imm >= 0 { + ArmInstruction::Add { dest: map_register(dest), arg1: map_register(src), arg2: ArmVal::Imm(imm) } + } else { + ArmInstruction::Sub { dest: map_register(dest), arg1: map_register(src), arg2: ArmVal::Imm(imm) } + }, RiscVInstruction::Sd => todo!(), RiscVInstruction::Ld => todo!(), RiscVInstruction::Sw => todo!(), @@ -18,6 +23,10 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } } +fn map_register(riscv_reg: RiscVRegister) -> ArmRegister { + todo!() +} + /// Runs binary translation /// text file -> [`Instruction`] enum array -> text file pub fn binary_translate(riscv_asm: &str) -> String { diff --git a/tests/binaries/add.c b/tests/binaries/add.c index c5750d5..f6bc037 100644 --- a/tests/binaries/add.c +++ b/tests/binaries/add.c @@ -4,20 +4,6 @@ int main(void) { return x + y; } - -//////////////// arm -// main: -// sub sp, sp, #16 -// mov w0, 3 -// str w0, [sp, 12] -// mov w0, 4 -// str w0, [sp, 8] -// ldr w1, [sp, 12] -// ldr w0, [sp, 8] -// add w0, w1, w0 -// add sp, sp, 16 -// ret - //////////// riscv // https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:8,positionColumn:1,positionLineNumber:8,selectionStartColumn:1,selectionStartLineNumber:8,startColumn:1,startLineNumber:8),source:'int+main(void)+%7B%0A%09int+x+%3D+3%3B%0A%09int+y+%3D+4%3B%0A%0A%09return+x+%2B+y%3B%0A%7D%0A%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:rv64-gcc1420,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'',overrides:!(),selection:(endColumn:19,endLineNumber:19,positionColumn:19,positionLineNumber:19,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+RISC-V+(64-bits)+gcc+14.2.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 // main: @@ -39,3 +25,17 @@ int main(void) { // ld ß s0,16(sp) // addi sp,sp,32 // jr ra + +//////////////// arm +// main: +// sub sp, sp, #16 +// mov w0, 3 +// str w0, [sp, 12] +// mov w0, 4 +// str w0, [sp, 8] +// ldr w1, [sp, 12] +// ldr w0, [sp, 8] +// add w0, w1, w0 +// add sp, sp, 16 +// ret + From 0cd26632c52d800deae0d0cfc0651abe461c7c86 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 8 Feb 2025 22:02:45 -0800 Subject: [PATCH 07/27] map_val empty --- src/instruction.rs | 2 +- src/translate.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 4a54cfb..d682c84 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -31,8 +31,8 @@ pub enum RiscVInstruction { /// `M[x[rs1] + sext(offset)] = x[rs2][63:0]` #[strum(serialize = "sd")] Sd { - dest: RiscVRegister, src: RiscVRegister, + dest: RiscVVal, }, /// Loads a 64-bit value from memory into register rd for RV64I. /// diff --git a/src/translate.rs b/src/translate.rs index ed4b153..7375c14 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -1,4 +1,4 @@ -use crate::instruction::{parse_asm, ArmInstruction, ArmRegister, ArmVal, RiscVInstruction, RiscVRegister}; +use crate::instruction::{parse_asm, ArmInstruction, ArmRegister, ArmVal, RiscVInstruction, RiscVRegister, RiscVVal}; /// Run the core logic to match from RISC-V to ARM Instructions. @@ -11,7 +11,8 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } else { ArmInstruction::Sub { dest: map_register(dest), arg1: map_register(src), arg2: ArmVal::Imm(imm) } }, - RiscVInstruction::Sd => todo!(), + RiscVInstruction::Sd { src, dest } => + ArmInstruction::Str { src: map_register(src), dst: () }, RiscVInstruction::Ld => todo!(), RiscVInstruction::Sw => todo!(), RiscVInstruction::Lw => todo!(), @@ -27,6 +28,10 @@ fn map_register(riscv_reg: RiscVRegister) -> ArmRegister { todo!() } +fn map_val(riscv_val: RiscVVal) -> ArmVal { + todo!() +} + /// Runs binary translation /// text file -> [`Instruction`] enum array -> text file pub fn binary_translate(riscv_asm: &str) -> String { From 7db7eecf544467720c7b11f7d4d3634219efee24 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 8 Feb 2025 23:57:08 -0800 Subject: [PATCH 08/27] more translations + builds now --- src/instruction.rs | 151 +++++++++++++++++++++++++++++++------- src/main.rs | 3 +- src/translate.rs | 110 +++++++++++++++++++++++---- tests/test_parse_asm.rs | 2 +- tests/test_translation.rs | 2 +- 5 files changed, 223 insertions(+), 45 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index d682c84..9516c4d 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,3 +1,5 @@ +use std::default; + /// This file defines all the supported ARM and RISC-V instructions we support. /// We use `strum` to assist in serializing asm files to our [`Instruction`] enum. /// @@ -9,6 +11,13 @@ /// https://github.com/nbdd0121/r2vm/blob/5118be6b9e757c6fef2f019385873f403c23c548/lib/riscv/src/op.rs#L30 use strum_macros::EnumString; +#[derive(Debug, Default)] +pub enum RiscVWidth { + Word, + #[default] + Double, +} + /// RISC-V Instructions /// https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html /// @@ -26,30 +35,37 @@ pub enum RiscVInstruction { src: RiscVRegister, imm: i32, }, - /// Store 64-bit, values from register rs2 to memory. + /// add register + /// either add or addw + /// (addw is 32 bits on 64 bit riscv) + /// + /// `x[rd] = sext((x[rs1] + x[rs2])[31:0])` + #[strum(serialize = "addw")] + Add { + // dest = arg1 + arg2 + width: RiscVWidth, + dest: RiscVRegister, + arg1: RiscVRegister, + arg2: RiscVRegister, + }, + /// Store values from register rs2 to memory. /// - /// `M[x[rs1] + sext(offset)] = x[rs2][63:0]` + /// `M[x[rs1] + sext(offset)] = x[rs2]` #[strum(serialize = "sd")] - Sd { + S { + width: RiscVWidth, src: RiscVRegister, dest: RiscVVal, }, - /// Loads a 64-bit value from memory into register rd for RV64I. + /// Loads a value from memory into register rd for RV64I. /// - /// `x[rd] = M[x[rs1] + sext(offset)][63:0]` + /// `x[rd] = M[x[rs1] + sext(offset)]` #[strum(serialize = "ld")] - Ld { dest: RiscVRegister, src: RiscVVal }, - /// Loads a 32-bit value from memory and sign-extends this to XLEN bits - /// before storing it in register rd. - /// - /// `x[rd] = sext(M[x[rs1] + sext(offset)][31:0])` - #[strum(serialize = "lw")] - Lw { dest: RiscVRegister, src: RiscVVal }, - /// Store 32-bit, values from the low bits of register rs2 to memory. - /// - /// `M[x[rs1] + sext(offset)] = x[rs2][31:0]` - #[strum(serialize = "sw")] - Sw { dest: RiscVRegister, src: RiscVVal }, + L { + width: RiscVWidth, + dest: RiscVRegister, + src: RiscVVal, + }, // Copy register // `mv rd, rs1` expands to `addi rd, rs, 0` #[strum(serialize = "mv")] @@ -57,8 +73,6 @@ pub enum RiscVInstruction { dest: RiscVRegister, src: RiscVRegister, }, - #[strum(serialize = "addw")] - Addw, /// Sign extend Word /// /// psuedo instruction which translates to `addiw rd, rs, 0` @@ -67,6 +81,13 @@ pub enum RiscVInstruction { dest: RiscVRegister, src: RiscVRegister, }, + /// Jump Register + /// Jump to address and place return address in rd. + /// jal rd,offset + /// + /// Psuedo instruction: + /// jr offset => jal x1, offset + /// #[strum(serialize = "jr")] Jr { target: RiscVRegister }, /// Load Immediate @@ -79,7 +100,16 @@ pub enum RiscVInstruction { /// semantics. /// https://michaeljclark.github.io/asm.html #[strum(serialize = "li")] - Li { imm: i32 }, + Li { dest: RiscVRegister, imm: i32 }, +} + +impl Default for RiscVInstruction { + fn default() -> Self { + Self::Li { + dest: RiscVRegister::X0, + imm: 0, + } + } } #[derive(Debug)] @@ -89,6 +119,28 @@ pub enum ArmVal { RegOffset(ArmRegister, i32), } +impl Default for ArmVal { + fn default() -> Self { + todo!() + } +} + +#[derive(Debug)] +pub enum ArmWidth { + Byte, + SignedByte, + Half, + SignedHalf, + Word, + Double, +} + +impl Default for ArmWidth { + fn default() -> Self { + todo!() + } +} + /// ARM Instructions /// `https://iitd-plos.github.io/col718/ref/arm-instructionset.pdf#page=3` #[derive(Debug, EnumString)] @@ -111,8 +163,15 @@ pub enum ArmInstruction { /// B Branch R15 := address #[strum(serialize = "b")] B, + /// BLR Xn + #[strum(serialize = "blr")] + Blr { target: ArmRegisterName }, #[strum(serialize = "ldr")] - Ldr, + Ldr { + width: ArmWidth, + dest: ArmRegister, + src: ArmVal, + }, #[strum(serialize = "mov")] Mov, #[strum(serialize = "ret")] @@ -120,9 +179,10 @@ pub enum ArmInstruction { /// Str [r2 + offset] = r1 #[strum(serialize = "str")] Str { + width: ArmWidth, src: ArmRegister, - dst: ArmVal, - } + dest: ArmVal, + }, /// Sub Sub Rd := Rn - Op2 #[strum(serialize = "sub")] Sub { @@ -130,11 +190,20 @@ pub enum ArmInstruction { arg1: ArmRegister, arg2: ArmVal, }, + /// sign extend to word + #[strum(serialize = "sxtw")] + Sxtw { dest: ArmRegister, src: ArmRegister }, +} + +impl Default for ArmInstruction { + fn default() -> Self { + ArmInstruction::B + } } #[derive(Debug)] pub enum RiscVVal { - RiscVRegister, + RiscVRegister(RiscVRegister), Immediate(i32), /// This is for arguments to opcodes which have an offset Offset { @@ -143,10 +212,17 @@ pub enum RiscVVal { }, } +impl Default for RiscVVal { + fn default() -> Self { + Self::Immediate(0) + } +} + /// RISC-V Registers /// https://msyksphinz-self.github.io/riscv-isadoc/html/regs.html -#[derive(Debug, EnumString)] +#[derive(Debug, EnumString, Default)] pub enum RiscVRegister { + #[default] #[strum(serialize = "x0")] /// Hard-wired zero X0, @@ -245,10 +321,22 @@ pub enum RiscVRegister { T6, } +#[derive(Debug)] +pub struct ArmRegister { + pub width: ArmWidth, + pub name: ArmRegisterName, +} + +impl Default for ArmRegister { + fn default() -> Self { + todo!() + } +} + /// ARM Registers /// https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names #[derive(Debug, EnumString)] -pub enum ArmRegister { +pub enum ArmRegisterName { #[strum(serialize = "pc")] /// Program counter. Pc, @@ -297,6 +385,14 @@ pub enum ArmRegister { #[strum(serialize = "a1")] /// Argument/result/scratch register 1. A1, + #[strum(serialize = "wzr", serialize = "xzr")] + Zero, +} + +impl Default for ArmRegisterName { + fn default() -> Self { + todo!() + } } /// Parse a text file into our enum. @@ -310,7 +406,8 @@ pub fn parse_asm(asm: &str) -> Vec { if parts.is_empty() { None } else { - RiscVInstruction::from_str(parts[0]).ok() + // RiscVInstruction::from_str(parts[0]).ok() + todo!() } }) .collect() diff --git a/src/main.rs b/src/main.rs index ee6bcba..938d608 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,7 @@ use std::str::FromStr; pub mod instruction; pub mod translate; use instruction::RiscVInstruction; - - +use translate::binary_translate; // Samir: I am using main for testing, but it not needed since you can run // `cargo test` instead. diff --git a/src/translate.rs b/src/translate.rs index 7375c14..483d2fc 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -1,26 +1,100 @@ -use crate::instruction::{parse_asm, ArmInstruction, ArmRegister, ArmVal, RiscVInstruction, RiscVRegister, RiscVVal}; +use core::panic; + +use crate::instruction::{ + parse_asm, ArmInstruction, ArmRegister, ArmRegisterName, ArmVal, ArmWidth, RiscVInstruction, + RiscVRegister, RiscVVal, RiscVWidth, +}; + +macro_rules! sorry { + () => { + todo!() + }; +} /// Run the core logic to match from RISC-V to ARM Instructions. /// Translate one instruction at a time. pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { match riscv_instr { - RiscVInstruction::Addi {dest, src, imm} => + RiscVInstruction::Addi { dest, src, imm } => { if imm >= 0 { - ArmInstruction::Add { dest: map_register(dest), arg1: map_register(src), arg2: ArmVal::Imm(imm) } + ArmInstruction::Add { + dest: map_register(dest), + arg1: map_register(src), + arg2: ArmVal::Imm(imm), + } } else { - ArmInstruction::Sub { dest: map_register(dest), arg1: map_register(src), arg2: ArmVal::Imm(imm) } + ArmInstruction::Sub { + dest: map_register(dest), + arg1: map_register(src), + arg2: ArmVal::Imm(imm), + } + } + } + RiscVInstruction::S { width, src, dest } => ArmInstruction::Str { + width: map_width(width), + src: map_register(src), + dest: map_val(dest), + }, + RiscVInstruction::L { width, dest, src } => ArmInstruction::Ldr { + width: map_width(width), + dest: map_register(dest), + src: map_val(src), + }, + RiscVInstruction::Mv { dest, src } => ArmInstruction::Add { + dest: map_register(dest), + arg1: map_register(src), + arg2: ArmVal::Imm(0), + }, + RiscVInstruction::Add { + width, + dest, + arg1, + arg2, + } => match width { + RiscVWidth::Word => ArmInstruction::Add { + dest: ArmRegister { + width: ArmWidth::Word, + name: map_register_name(dest), + }, + arg1: ArmRegister { + width: ArmWidth::Word, + name: map_register_name(arg1), + }, + arg2: ArmVal::Reg(ArmRegister { + width: ArmWidth::Word, + name: map_register_name(arg2), + }), }, - RiscVInstruction::Sd { src, dest } => - ArmInstruction::Str { src: map_register(src), dst: () }, - RiscVInstruction::Ld => todo!(), - RiscVInstruction::Sw => todo!(), - RiscVInstruction::Lw => todo!(), - RiscVInstruction::Mv => todo!(), - RiscVInstruction::Addw => todo!(), - RiscVInstruction::SextW => todo!(), - RiscVInstruction::Jr => todo!(), - RiscVInstruction::Li => todo!(), + RiscVWidth::Double => sorry!(), + }, + RiscVInstruction::SextW { dest, src } => ArmInstruction::Sxtw { + dest: ArmRegister { + width: ArmWidth::Double, + name: map_register_name(dest), + }, + src: ArmRegister { + width: ArmWidth::Word, + name: map_register_name(src), + }, + }, + RiscVInstruction::Jr { target } => ArmInstruction::Blr { + target: map_register_name(target), + }, + RiscVInstruction::Li { dest, imm } => { + if imm > 4095 || imm < 0 { + panic!("Li with imm out of range"); + } + + ArmInstruction::Add { + dest: map_register(dest), + arg1: ArmRegister { + width: ArmWidth::Double, + name: ArmRegisterName::Zero, + }, + arg2: ArmVal::Imm(imm), + } + } } } @@ -28,10 +102,18 @@ fn map_register(riscv_reg: RiscVRegister) -> ArmRegister { todo!() } +fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { + todo!() +} + fn map_val(riscv_val: RiscVVal) -> ArmVal { todo!() } +fn map_width(riscv_width: RiscVWidth) -> ArmWidth { + todo!() +} + /// Runs binary translation /// text file -> [`Instruction`] enum array -> text file pub fn binary_translate(riscv_asm: &str) -> String { diff --git a/tests/test_parse_asm.rs b/tests/test_parse_asm.rs index 0c0372f..36c8e0a 100644 --- a/tests/test_parse_asm.rs +++ b/tests/test_parse_asm.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use binary_room::instruction::parse_asm; + use binary_room::instruction::parse_asm; #[test] fn test_parse_asm() { diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 5e5011c..8ec9300 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use binary_room::translate::binary_translate; + use binary_room::translate::binary_translate; #[test] fn test_binary_translate() { From 1ecd2c99aa2629bad4d7b5159d35dd1d86cea8e6 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sun, 9 Feb 2025 00:35:59 -0800 Subject: [PATCH 09/27] test: run translation from RISCV to ARM enums --- src/instruction.rs | 2 +- src/translate.rs | 62 ++++++++++++++- tests/binaries/add.c | 3 +- tests/test_parse_asm.rs | 94 +++++++++++------------ tests/test_translation.rs | 158 +++++++++++++++++++++++++++----------- 5 files changed, 222 insertions(+), 97 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 9516c4d..0a07992 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -207,7 +207,7 @@ pub enum RiscVVal { Immediate(i32), /// This is for arguments to opcodes which have an offset Offset { - register: Box, + register: RiscVRegister, offset: i32, }, } diff --git a/src/translate.rs b/src/translate.rs index 483d2fc..e22c1c1 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -99,19 +99,73 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } fn map_register(riscv_reg: RiscVRegister) -> ArmRegister { - todo!() + match riscv_reg { + RiscVRegister::X0 => todo!("Arm doesn't have a zero register"), + // RiscVRegister::RA => ArmRegister::Lr, + // RiscVRegister::SP => ArmRegister::Sp, + // RiscVRegister::GP => ArmRegister::, + // RiscVRegister::TP => ArmRegister::, + // RiscVRegister::T0 => ArmRegister::, + // RiscVRegister::T1 => ArmRegister::, + // RiscVRegister::T2 => ArmRegister::, + // RiscVRegister::S0FP => ArmRegister::, + // RiscVRegister::S1 => ArmRegister::, + // RiscVRegister::A0 => ArmRegister::, + // RiscVRegister::A1 => ArmRegister::, + // RiscVRegister::A2 => ArmRegister::, + // RiscVRegister::A3 => ArmRegister::, + // RiscVRegister::A4 => ArmRegister::, + // RiscVRegister::A5 => ArmRegister::, + // RiscVRegister::A6 => ArmRegister::, + // RiscVRegister::A7 => ArmRegister::, + // RiscVRegister::S2 => ArmRegister::, + // RiscVRegister::S3 => ArmRegister::, + // RiscVRegister::S4 => ArmRegister::, + // RiscVRegister::S5 => ArmRegister::, + // RiscVRegister::S6 => ArmRegister::, + // RiscVRegister::S7 => ArmRegister::, + // RiscVRegister::S8 => ArmRegister::, + // RiscVRegister::S9 => ArmRegister::, + // RiscVRegister::S10 => ArmRegister::, + // RiscVRegister::S11 => ArmRegister::, + // RiscVRegister::T3 => ArmRegister::, + // RiscVRegister::T4 => ArmRegister::, + // RiscVRegister::T5 => ArmRegister::, + // RiscVRegister::T6 => ArmRegister::, + // FIXME: do real implementation + _ => ArmRegister { + width: ArmWidth::Double, + name: ArmRegisterName::Sp, + }, + } } fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { - todo!() + // todo!() + // FIXME: do real implementation + ArmRegisterName::A1 } fn map_val(riscv_val: RiscVVal) -> ArmVal { - todo!() + match riscv_val { + RiscVVal::RiscVRegister(riscv_reg) => ArmVal::Reg(map_register(riscv_reg)), + RiscVVal::Immediate(imm) => ArmVal::Imm(imm), + RiscVVal::Offset { register, offset } => ArmVal::RegOffset(map_register(register), offset), + } } fn map_width(riscv_width: RiscVWidth) -> ArmWidth { - todo!() + // todo!() + // FIXME: do real implementation + ArmWidth::Double +} + +// Translate every instruction 1:1 +pub fn translate_instrs(riscv_instrs: Vec) -> Vec { + riscv_instrs + .into_iter() + .map(|instr| translate(instr)) + .collect::>() } /// Runs binary translation diff --git a/tests/binaries/add.c b/tests/binaries/add.c index f6bc037..8485f1d 100644 --- a/tests/binaries/add.c +++ b/tests/binaries/add.c @@ -22,7 +22,7 @@ int main(void) { // sext.w a5,a5 // mv a0,a5 // ld ra,24(sp) -// ld ß s0,16(sp) +// ld s0,16(sp) // addi sp,sp,32 // jr ra @@ -38,4 +38,3 @@ int main(void) { // add w0, w1, w0 // add sp, sp, 16 // ret - diff --git a/tests/test_parse_asm.rs b/tests/test_parse_asm.rs index 36c8e0a..535fc3d 100644 --- a/tests/test_parse_asm.rs +++ b/tests/test_parse_asm.rs @@ -1,48 +1,48 @@ -#[cfg(test)] -mod tests { - use binary_room::instruction::parse_asm; +// #[cfg(test)] +// mod tests { +// use binary_room::instruction::parse_asm; - #[test] - fn test_parse_asm() { - let asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let instructions = parse_asm(asm); - assert_eq!(instructions.len(), 17); - assert_eq!(instructions[0], RiscVInstruction::Addi); - assert_eq!(instructions[1], RiscVInstruction::Sd); - assert_eq!(instructions[2], RiscVInstruction::Ld); - assert_eq!(instructions[3], RiscVInstruction::Addi); - assert_eq!(instructions[4], RiscVInstruction::Li); - assert_eq!(instructions[5], RiscVInstruction::Sw); - assert_eq!(instructions[6], RiscVInstruction::Li); - assert_eq!(instructions[7], RiscVInstruction::Sw); - assert_eq!(instructions[8], RiscVInstruction::Lw); - assert_eq!(instructions[9], RiscVInstruction::Mv); - assert_eq!(instructions[10], RiscVInstruction::Lw); - assert_eq!(instructions[11], RiscVInstruction::Addw); - assert_eq!(instructions[12], RiscVInstruction::SextW); - assert_eq!(instructions[13], RiscVInstruction::Mv); - assert_eq!(instructions[14], RiscVInstruction::Ld); - assert_eq!(instructions[15], RiscVInstruction::Ld); - assert_eq!(instructions[16], RiscVInstruction::Addi); - assert_eq!(instructions[17], RiscVInstruction::Jr); - } -} +// #[test] +// fn test_parse_asm() { +// let asm = " +// addi sp,sp,-32 +// sd ra,24(sp) +// ld s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld s0,16(sp) +// addi sp,sp,32 +// jr ra +// "; +// let instructions = parse_asm(asm); +// assert_eq!(instructions.len(), 17); +// assert_eq!(instructions[0], RiscVInstruction::Addi); +// assert_eq!(instructions[1], RiscVInstruction::Sd); +// assert_eq!(instructions[2], RiscVInstruction::Ld); +// assert_eq!(instructions[3], RiscVInstruction::Addi); +// assert_eq!(instructions[4], RiscVInstruction::Li); +// assert_eq!(instructions[5], RiscVInstruction::Sw); +// assert_eq!(instructions[6], RiscVInstruction::Li); +// assert_eq!(instructions[7], RiscVInstruction::Sw); +// assert_eq!(instructions[8], RiscVInstruction::Lw); +// assert_eq!(instructions[9], RiscVInstruction::Mv); +// assert_eq!(instructions[10], RiscVInstruction::Lw); +// assert_eq!(instructions[11], RiscVInstruction::Addw); +// assert_eq!(instructions[12], RiscVInstruction::SextW); +// assert_eq!(instructions[13], RiscVInstruction::Mv); +// assert_eq!(instructions[14], RiscVInstruction::Ld); +// assert_eq!(instructions[15], RiscVInstruction::Ld); +// assert_eq!(instructions[16], RiscVInstruction::Addi); +// assert_eq!(instructions[17], RiscVInstruction::Jr); +// } +// } diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 8ec9300..7ed8ac6 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -1,50 +1,122 @@ #[cfg(test)] mod tests { - use binary_room::translate::binary_translate; + use binary_room::instruction::*; + use binary_room::translate::*; #[test] fn test_binary_translate() { - let riscv_asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let translated_asm = binary_translate(riscv_asm); - let expected_output = " - Addi - Sd - Ld - Addi - Li - Sw - Li - Sw - Lw - Mv - Lw - Addw - SextW - Mv - Ld - Ld - Addi - Jr - "; - assert_eq!(translated_asm, expected_output); + let riscv_asm: Vec = vec![ + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: -32, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::RA, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 24, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::S0FP, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 16, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::S0FP, + src: RiscVRegister::SP, + imm: 32, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 3, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 4, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::Add { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A0, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::RA, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 24, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::S0FP, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 16, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: 32, + }, + RiscVInstruction::Jr { + target: RiscVRegister::RA, + }, + ]; + + println!("{:?}", translate_instrs(riscv_asm)) + // assert_eq!(translated_asm, expected_output); } } From 4f573fe673dc3a1172a4ab84746fcd0d4f9a6da4 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Wed, 19 Feb 2025 14:27:45 -0800 Subject: [PATCH 10/27] map_register use helpers --- src/translate.rs | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/src/translate.rs b/src/translate.rs index e22c1c1..6329f1c 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -98,45 +98,10 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } } -fn map_register(riscv_reg: RiscVRegister) -> ArmRegister { - match riscv_reg { - RiscVRegister::X0 => todo!("Arm doesn't have a zero register"), - // RiscVRegister::RA => ArmRegister::Lr, - // RiscVRegister::SP => ArmRegister::Sp, - // RiscVRegister::GP => ArmRegister::, - // RiscVRegister::TP => ArmRegister::, - // RiscVRegister::T0 => ArmRegister::, - // RiscVRegister::T1 => ArmRegister::, - // RiscVRegister::T2 => ArmRegister::, - // RiscVRegister::S0FP => ArmRegister::, - // RiscVRegister::S1 => ArmRegister::, - // RiscVRegister::A0 => ArmRegister::, - // RiscVRegister::A1 => ArmRegister::, - // RiscVRegister::A2 => ArmRegister::, - // RiscVRegister::A3 => ArmRegister::, - // RiscVRegister::A4 => ArmRegister::, - // RiscVRegister::A5 => ArmRegister::, - // RiscVRegister::A6 => ArmRegister::, - // RiscVRegister::A7 => ArmRegister::, - // RiscVRegister::S2 => ArmRegister::, - // RiscVRegister::S3 => ArmRegister::, - // RiscVRegister::S4 => ArmRegister::, - // RiscVRegister::S5 => ArmRegister::, - // RiscVRegister::S6 => ArmRegister::, - // RiscVRegister::S7 => ArmRegister::, - // RiscVRegister::S8 => ArmRegister::, - // RiscVRegister::S9 => ArmRegister::, - // RiscVRegister::S10 => ArmRegister::, - // RiscVRegister::S11 => ArmRegister::, - // RiscVRegister::T3 => ArmRegister::, - // RiscVRegister::T4 => ArmRegister::, - // RiscVRegister::T5 => ArmRegister::, - // RiscVRegister::T6 => ArmRegister::, - // FIXME: do real implementation - _ => ArmRegister { - width: ArmWidth::Double, - name: ArmRegisterName::Sp, - }, +fn map_register(riscv_reg: RiscVRegister, riscv_width: RiscVWidth) -> ArmRegister { + ArmRegister { + width: map_width(riscv_width), + name: map_register_name(riscv_reg) } } From f5ac84e3c815a51173060d8e606142c7955c6cde Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Wed, 19 Feb 2025 14:45:06 -0800 Subject: [PATCH 11/27] update calls to map_register with widths --- src/translate.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/translate.rs b/src/translate.rs index 6329f1c..15594fb 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -17,34 +17,38 @@ macro_rules! sorry { pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { match riscv_instr { RiscVInstruction::Addi { dest, src, imm } => { + let width = RiscVWidth::Word; if imm >= 0 { ArmInstruction::Add { - dest: map_register(dest), - arg1: map_register(src), + dest: map_register(dest, width), + arg1: map_register(src, width), arg2: ArmVal::Imm(imm), } } else { ArmInstruction::Sub { - dest: map_register(dest), - arg1: map_register(src), + dest: map_register(dest, width), + arg1: map_register(src, width), arg2: ArmVal::Imm(imm), } } } RiscVInstruction::S { width, src, dest } => ArmInstruction::Str { width: map_width(width), - src: map_register(src), - dest: map_val(dest), + src: map_register(src, width), + dest: map_val(dest, width), }, RiscVInstruction::L { width, dest, src } => ArmInstruction::Ldr { width: map_width(width), - dest: map_register(dest), - src: map_val(src), + dest: map_register(dest, width), + src: map_val(src, width), }, - RiscVInstruction::Mv { dest, src } => ArmInstruction::Add { - dest: map_register(dest), - arg1: map_register(src), - arg2: ArmVal::Imm(0), + RiscVInstruction::Mv { dest, src } => { + let width = RiscVWidth::Double; + ArmInstruction::Add { + dest: map_register(dest, width), + arg1: map_register(src, width), + arg2: ArmVal::Imm(0), + } }, RiscVInstruction::Add { width, @@ -87,7 +91,7 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } ArmInstruction::Add { - dest: map_register(dest), + dest: map_register(dest, RiscVWidth::Double), arg1: ArmRegister { width: ArmWidth::Double, name: ArmRegisterName::Zero, @@ -111,11 +115,11 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { ArmRegisterName::A1 } -fn map_val(riscv_val: RiscVVal) -> ArmVal { +fn map_val(riscv_val: RiscVVal, riscv_width: RiscVWidth) -> ArmVal { match riscv_val { - RiscVVal::RiscVRegister(riscv_reg) => ArmVal::Reg(map_register(riscv_reg)), + RiscVVal::RiscVRegister(riscv_reg) => ArmVal::Reg(map_register(riscv_reg, riscv_width)), RiscVVal::Immediate(imm) => ArmVal::Imm(imm), - RiscVVal::Offset { register, offset } => ArmVal::RegOffset(map_register(register), offset), + RiscVVal::Offset { register, offset } => ArmVal::RegOffset(map_register(register, riscv_width), offset), } } From 5fd4018c04e495a56c6ab273e8db81c9c283de2d Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Wed, 19 Feb 2025 14:52:02 -0800 Subject: [PATCH 12/27] fix move of width values --- src/translate.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/translate.rs b/src/translate.rs index 15594fb..7ac562a 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -20,33 +20,33 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { let width = RiscVWidth::Word; if imm >= 0 { ArmInstruction::Add { - dest: map_register(dest, width), - arg1: map_register(src, width), + dest: map_register(dest, &width), + arg1: map_register(src, &width), arg2: ArmVal::Imm(imm), } } else { ArmInstruction::Sub { - dest: map_register(dest, width), - arg1: map_register(src, width), + dest: map_register(dest, &width), + arg1: map_register(src, &width), arg2: ArmVal::Imm(imm), } } } RiscVInstruction::S { width, src, dest } => ArmInstruction::Str { - width: map_width(width), - src: map_register(src, width), - dest: map_val(dest, width), + width: map_width(&width), + src: map_register(src, &width), + dest: map_val(dest, &width), }, RiscVInstruction::L { width, dest, src } => ArmInstruction::Ldr { - width: map_width(width), - dest: map_register(dest, width), - src: map_val(src, width), + width: map_width(&width), + dest: map_register(dest, &width), + src: map_val(src, &width), }, RiscVInstruction::Mv { dest, src } => { let width = RiscVWidth::Double; ArmInstruction::Add { - dest: map_register(dest, width), - arg1: map_register(src, width), + dest: map_register(dest, &width), + arg1: map_register(src, &width), arg2: ArmVal::Imm(0), } }, @@ -91,7 +91,7 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } ArmInstruction::Add { - dest: map_register(dest, RiscVWidth::Double), + dest: map_register(dest, &RiscVWidth::Double), arg1: ArmRegister { width: ArmWidth::Double, name: ArmRegisterName::Zero, @@ -102,7 +102,7 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } } -fn map_register(riscv_reg: RiscVRegister, riscv_width: RiscVWidth) -> ArmRegister { +fn map_register(riscv_reg: RiscVRegister, riscv_width: &RiscVWidth) -> ArmRegister { ArmRegister { width: map_width(riscv_width), name: map_register_name(riscv_reg) @@ -115,7 +115,7 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { ArmRegisterName::A1 } -fn map_val(riscv_val: RiscVVal, riscv_width: RiscVWidth) -> ArmVal { +fn map_val(riscv_val: RiscVVal, riscv_width: &RiscVWidth) -> ArmVal { match riscv_val { RiscVVal::RiscVRegister(riscv_reg) => ArmVal::Reg(map_register(riscv_reg, riscv_width)), RiscVVal::Immediate(imm) => ArmVal::Imm(imm), @@ -123,7 +123,7 @@ fn map_val(riscv_val: RiscVVal, riscv_width: RiscVWidth) -> ArmVal { } } -fn map_width(riscv_width: RiscVWidth) -> ArmWidth { +fn map_width(riscv_width: &RiscVWidth) -> ArmWidth { // todo!() // FIXME: do real implementation ArmWidth::Double From 550b8d8bd569e9495db04735f8ba710c7483a3a6 Mon Sep 17 00:00:00 2001 From: David Tran Date: Wed, 19 Feb 2025 14:55:14 -0800 Subject: [PATCH 13/27] map width --- src/translate.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/translate.rs b/src/translate.rs index e22c1c1..3a1db1f 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -155,9 +155,11 @@ fn map_val(riscv_val: RiscVVal) -> ArmVal { } fn map_width(riscv_width: RiscVWidth) -> ArmWidth { - // todo!() - // FIXME: do real implementation - ArmWidth::Double + match riscv_width { + RiscVWidth::Word => ArmWidth::Word, + RiscVWidth::Double => ArmWidth::Double, + // todo!() + } } // Translate every instruction 1:1 From 7a5d2059984f99fb7eef6b5d1f3be1a50d7f7392 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Wed, 19 Feb 2025 14:57:49 -0800 Subject: [PATCH 14/27] translate: `map_register_name` with semantic meanings Corrected the translation between registers for our 64 bit architectures. --- src/instruction.rs | 96 +++++++++++++++++++++++----------------------- src/translate.rs | 39 +++++++++++++++++-- 2 files changed, 85 insertions(+), 50 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 0a07992..f3440a6 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -248,7 +248,7 @@ pub enum RiscVRegister { /// Temporaries T2, #[strum(serialize = "s0", serialize = "fp")] - /// Saved register/frame pointer + /// Saved register/frame pointer R29 S0FP, #[strum(serialize = "s1")] /// Saved registers @@ -335,58 +335,60 @@ impl Default for ArmRegister { /// ARM Registers /// https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names +/// Image of instructions https://duetorun.com/blog/arm/images/AArch64-registers.png +/// - https://duetorun.com/blog/20230601/a64-regs/#user_program_registers #[derive(Debug, EnumString)] pub enum ArmRegisterName { + #[strum(serialize = "wzr", serialize = "xzr")] + /// Zero register. Hardware special. + Zero, #[strum(serialize = "pc")] - /// Program counter. + /// Program counter. Hardware special register. Pc, - #[strum(serialize = "lr")] - /// Link register. - Lr, #[strum(serialize = "sp")] - /// Stack pointer. + /// Stack pointer. Hardware special register. Sp, - #[strum(serialize = "ip")] - /// Intra-procedure-call scratch register. - Ip, - #[strum(serialize = "v8")] - /// ARM-state variable register 8. - V8, - #[strum(serialize = "sl")] - /// ARM-state variable register 7. Stack limit pointer in stack-checked variants. - Sl, - #[strum(serialize = "sb")] - /// ARM-state variable register 6. Static base in RWPI variants. - Sb, - #[strum(serialize = "v5")] - /// ARM-state variable register 5. - V5, - #[strum(serialize = "v4")] - /// Variable register 4. - V4, - #[strum(serialize = "v3")] - /// Variable register 3. - V3, - #[strum(serialize = "v2")] - /// Variable register 2. - V2, - #[strum(serialize = "v1")] - /// Variable register 1. - V1, - #[strum(serialize = "a4")] - /// Argument/result/scratch register 4. - A4, - #[strum(serialize = "a3")] - /// Argument/result/scratch register 3. - A3, - #[strum(serialize = "a2")] - /// Argument/result/scratch register 2. - A2, - #[strum(serialize = "a1")] - /// Argument/result/scratch register 1. - A1, - #[strum(serialize = "wzr", serialize = "xzr")] - Zero, + #[strum(serialize = "lr")] + /// Link register. X30. Hardware special register. + Lr, + // Parameter passing and/or scratch registers (volatile) + X0, + X1, + X2, + X3, + X4, + X5, + X6, + X7, + // Caller-Saved scratch registers (volatile) + /// XR + X8, + X9, + X10, + X11, + X12, + X13, + X14, + X15, + /// IP0 + X16, + /// IP1 + X17, + /// PR + X18, + // Caller-Saved registers (non-volatile) + X19, + X20, + X21, + X22, + X23, + X24, + X25, + X26, + X27, + X28, + /// FP + X29, } impl Default for ArmRegisterName { diff --git a/src/translate.rs b/src/translate.rs index 7ac562a..199133b 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -109,10 +109,43 @@ fn map_register(riscv_reg: RiscVRegister, riscv_width: &RiscVWidth) -> ArmRegist } } +/// Semantic meaning of registers +/// https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf#page=3 fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { - // todo!() - // FIXME: do real implementation - ArmRegisterName::A1 + match riscv_reg { + RiscVRegister::X0 => ArmRegisterName::Zero, + RiscVRegister::RA => ArmRegisterName::Lr, + RiscVRegister::SP => ArmRegisterName::Sp, + RiscVRegister::GP => ArmRegisterName::X0, + RiscVRegister::TP => ArmRegisterName::X1, + RiscVRegister::T0 => ArmRegisterName::X2, + RiscVRegister::T1 => ArmRegisterName::X3, + RiscVRegister::T2 => ArmRegisterName::X4, + RiscVRegister::S0FP => ArmRegisterName::X5, + RiscVRegister::S1 => ArmRegisterName::X6, + RiscVRegister::A0 => ArmRegisterName::X7, + RiscVRegister::A1 => ArmRegisterName::X8, + RiscVRegister::A2 => ArmRegisterName::X9, + RiscVRegister::A3 => ArmRegisterName::X10, + RiscVRegister::A4 => ArmRegisterName::X11, + RiscVRegister::A5 => ArmRegisterName::X12, + RiscVRegister::A6 => ArmRegisterName::X13, + RiscVRegister::A7 => ArmRegisterName::X14, + RiscVRegister::S2 => ArmRegisterName::X15, + RiscVRegister::S3 => ArmRegisterName::X16, + RiscVRegister::S4 => ArmRegisterName::X17, + RiscVRegister::S5 => ArmRegisterName::X18, + RiscVRegister::S6 => ArmRegisterName::X19, + RiscVRegister::S7 => ArmRegisterName::X20, + RiscVRegister::S8 => ArmRegisterName::X21, + RiscVRegister::S9 => ArmRegisterName::X22, + RiscVRegister::S10 => ArmRegisterName::X23, + RiscVRegister::S11 => ArmRegisterName::X24, + RiscVRegister::T3 => ArmRegisterName::X25, + RiscVRegister::T4 => ArmRegisterName::X26, + RiscVRegister::T5 => ArmRegisterName::X27, + RiscVRegister::T6 => ArmRegisterName::X28, + } } fn map_val(riscv_val: RiscVVal, riscv_width: &RiscVWidth) -> ArmVal { From 2273195d974c155274fa2625237e87c3c69e3c3d Mon Sep 17 00:00:00 2001 From: David Tran Date: Wed, 19 Feb 2025 14:59:42 -0800 Subject: [PATCH 15/27] map width --- src/translate.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/translate.rs b/src/translate.rs index 199133b..13677be 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -159,7 +159,10 @@ fn map_val(riscv_val: RiscVVal, riscv_width: &RiscVWidth) -> ArmVal { fn map_width(riscv_width: &RiscVWidth) -> ArmWidth { // todo!() // FIXME: do real implementation - ArmWidth::Double + match riscv_width { + RiscVWidth::Double => ArmWidth::Double, + RiscVWidth::Word => ArmWidth::Word + } } // Translate every instruction 1:1 From aaeb3c8a742c6f34a8db74f644ab5445f4f2c055 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Wed, 19 Feb 2025 15:35:07 -0800 Subject: [PATCH 16/27] starting instruction encoding --- src/instruction.rs | 250 ++++++++++++++++++++++++++++++++++++++ tests/test_translation.rs | 7 +- 2 files changed, 256 insertions(+), 1 deletion(-) diff --git a/src/instruction.rs b/src/instruction.rs index f3440a6..d0197c7 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,4 +1,6 @@ +use std::convert::Into; use std::default; +use std::fmt::{write, Display}; /// This file defines all the supported ARM and RISC-V instructions we support. /// We use `strum` to assist in serializing asm files to our [`Instruction`] enum. @@ -414,3 +416,251 @@ pub fn parse_asm(asm: &str) -> Vec { }) .collect() } + +impl Into for ArmInstruction { + fn into(self) -> String { + match self { + ArmInstruction::Adc => todo!(), + ArmInstruction::Add { dest, arg1, arg2 } => { + format!("add {} {} {}", dest, arg1, arg2) + }, + ArmInstruction::And => todo!(), + ArmInstruction::B => todo!(), + ArmInstruction::Blr { target } => todo!(), + ArmInstruction::Ldr { width, dest, src } => todo!(), + ArmInstruction::Mov => todo!(), + ArmInstruction::Ret => todo!(), + ArmInstruction::Str { width, src, dest } => todo!(), + ArmInstruction::Sub { dest, arg1, arg2 } => + { + format!("sub {} {} {}", dest, arg1, arg2) + }, + ArmInstruction::Sxtw { dest, src } => todo!(), + } + } +} + +impl Display for ArmRegister { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match (&self.width, &self.name) { + (ArmWidth::Byte, ArmRegisterName::Zero) => todo!(), + (ArmWidth::Byte, ArmRegisterName::Pc) => todo!(), + (ArmWidth::Byte, ArmRegisterName::Sp) => todo!(), + (ArmWidth::Byte, ArmRegisterName::Lr) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X0) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X1) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X2) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X3) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X4) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X5) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X6) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X7) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X8) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X9) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X10) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X11) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X12) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X13) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X14) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X15) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X16) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X17) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X18) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X19) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X20) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X21) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X22) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X23) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X24) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X25) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X26) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X27) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X28) => todo!(), + (ArmWidth::Byte, ArmRegisterName::X29) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::Zero) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::Pc) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::Sp) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::Lr) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X0) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X1) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X2) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X3) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X4) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X5) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X6) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X7) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X8) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X9) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X10) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X11) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X12) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X13) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X14) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X15) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X16) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X17) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X18) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X19) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X20) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X21) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X22) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X23) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X24) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X25) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X26) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X27) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X28) => todo!(), + (ArmWidth::SignedByte, ArmRegisterName::X29) => todo!(), + (ArmWidth::Half, ArmRegisterName::Zero) => todo!(), + (ArmWidth::Half, ArmRegisterName::Pc) => todo!(), + (ArmWidth::Half, ArmRegisterName::Sp) => todo!(), + (ArmWidth::Half, ArmRegisterName::Lr) => todo!(), + (ArmWidth::Half, ArmRegisterName::X0) => todo!(), + (ArmWidth::Half, ArmRegisterName::X1) => todo!(), + (ArmWidth::Half, ArmRegisterName::X2) => todo!(), + (ArmWidth::Half, ArmRegisterName::X3) => todo!(), + (ArmWidth::Half, ArmRegisterName::X4) => todo!(), + (ArmWidth::Half, ArmRegisterName::X5) => todo!(), + (ArmWidth::Half, ArmRegisterName::X6) => todo!(), + (ArmWidth::Half, ArmRegisterName::X7) => todo!(), + (ArmWidth::Half, ArmRegisterName::X8) => todo!(), + (ArmWidth::Half, ArmRegisterName::X9) => todo!(), + (ArmWidth::Half, ArmRegisterName::X10) => todo!(), + (ArmWidth::Half, ArmRegisterName::X11) => todo!(), + (ArmWidth::Half, ArmRegisterName::X12) => todo!(), + (ArmWidth::Half, ArmRegisterName::X13) => todo!(), + (ArmWidth::Half, ArmRegisterName::X14) => todo!(), + (ArmWidth::Half, ArmRegisterName::X15) => todo!(), + (ArmWidth::Half, ArmRegisterName::X16) => todo!(), + (ArmWidth::Half, ArmRegisterName::X17) => todo!(), + (ArmWidth::Half, ArmRegisterName::X18) => todo!(), + (ArmWidth::Half, ArmRegisterName::X19) => todo!(), + (ArmWidth::Half, ArmRegisterName::X20) => todo!(), + (ArmWidth::Half, ArmRegisterName::X21) => todo!(), + (ArmWidth::Half, ArmRegisterName::X22) => todo!(), + (ArmWidth::Half, ArmRegisterName::X23) => todo!(), + (ArmWidth::Half, ArmRegisterName::X24) => todo!(), + (ArmWidth::Half, ArmRegisterName::X25) => todo!(), + (ArmWidth::Half, ArmRegisterName::X26) => todo!(), + (ArmWidth::Half, ArmRegisterName::X27) => todo!(), + (ArmWidth::Half, ArmRegisterName::X28) => todo!(), + (ArmWidth::Half, ArmRegisterName::X29) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::Zero) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::Pc) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::Sp) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::Lr) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X0) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X1) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X2) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X3) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X4) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X5) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X6) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X7) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X8) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X9) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X10) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X11) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X12) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X13) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X14) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X15) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X16) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X17) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X18) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X19) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X20) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X21) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X22) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X23) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X24) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X25) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X26) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X27) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X28) => todo!(), + (ArmWidth::SignedHalf, ArmRegisterName::X29) => todo!(), + (ArmWidth::Word, ArmRegisterName::Zero) => todo!(), + (ArmWidth::Word, ArmRegisterName::Pc) => todo!(), + (ArmWidth::Word, ArmRegisterName::Sp) => todo!(), + (ArmWidth::Word, ArmRegisterName::Lr) => todo!(), + (ArmWidth::Word, ArmRegisterName::X0) => todo!(), + (ArmWidth::Word, ArmRegisterName::X1) => todo!(), + (ArmWidth::Word, ArmRegisterName::X2) => todo!(), + (ArmWidth::Word, ArmRegisterName::X3) => todo!(), + (ArmWidth::Word, ArmRegisterName::X4) => todo!(), + (ArmWidth::Word, ArmRegisterName::X5) => todo!(), + (ArmWidth::Word, ArmRegisterName::X6) => todo!(), + (ArmWidth::Word, ArmRegisterName::X7) => todo!(), + (ArmWidth::Word, ArmRegisterName::X8) => todo!(), + (ArmWidth::Word, ArmRegisterName::X9) => todo!(), + (ArmWidth::Word, ArmRegisterName::X10) => todo!(), + (ArmWidth::Word, ArmRegisterName::X11) => todo!(), + (ArmWidth::Word, ArmRegisterName::X12) => todo!(), + (ArmWidth::Word, ArmRegisterName::X13) => todo!(), + (ArmWidth::Word, ArmRegisterName::X14) => todo!(), + (ArmWidth::Word, ArmRegisterName::X15) => todo!(), + (ArmWidth::Word, ArmRegisterName::X16) => todo!(), + (ArmWidth::Word, ArmRegisterName::X17) => todo!(), + (ArmWidth::Word, ArmRegisterName::X18) => todo!(), + (ArmWidth::Word, ArmRegisterName::X19) => todo!(), + (ArmWidth::Word, ArmRegisterName::X20) => todo!(), + (ArmWidth::Word, ArmRegisterName::X21) => todo!(), + (ArmWidth::Word, ArmRegisterName::X22) => todo!(), + (ArmWidth::Word, ArmRegisterName::X23) => todo!(), + (ArmWidth::Word, ArmRegisterName::X24) => todo!(), + (ArmWidth::Word, ArmRegisterName::X25) => todo!(), + (ArmWidth::Word, ArmRegisterName::X26) => todo!(), + (ArmWidth::Word, ArmRegisterName::X27) => todo!(), + (ArmWidth::Word, ArmRegisterName::X28) => todo!(), + (ArmWidth::Word, ArmRegisterName::X29) => todo!(), + (ArmWidth::Double, ArmRegisterName::Zero) => todo!(), + (ArmWidth::Double, ArmRegisterName::Pc) => todo!(), + (ArmWidth::Double, ArmRegisterName::Sp) => todo!(), + (ArmWidth::Double, ArmRegisterName::Lr) => todo!(), + (ArmWidth::Double, ArmRegisterName::X0) => todo!(), + (ArmWidth::Double, ArmRegisterName::X1) => todo!(), + (ArmWidth::Double, ArmRegisterName::X2) => todo!(), + (ArmWidth::Double, ArmRegisterName::X3) => todo!(), + (ArmWidth::Double, ArmRegisterName::X4) => todo!(), + (ArmWidth::Double, ArmRegisterName::X5) => todo!(), + (ArmWidth::Double, ArmRegisterName::X6) => todo!(), + (ArmWidth::Double, ArmRegisterName::X7) => todo!(), + (ArmWidth::Double, ArmRegisterName::X8) => todo!(), + (ArmWidth::Double, ArmRegisterName::X9) => todo!(), + (ArmWidth::Double, ArmRegisterName::X10) => todo!(), + (ArmWidth::Double, ArmRegisterName::X11) => todo!(), + (ArmWidth::Double, ArmRegisterName::X12) => todo!(), + (ArmWidth::Double, ArmRegisterName::X13) => todo!(), + (ArmWidth::Double, ArmRegisterName::X14) => todo!(), + (ArmWidth::Double, ArmRegisterName::X15) => todo!(), + (ArmWidth::Double, ArmRegisterName::X16) => todo!(), + (ArmWidth::Double, ArmRegisterName::X17) => todo!(), + (ArmWidth::Double, ArmRegisterName::X18) => todo!(), + (ArmWidth::Double, ArmRegisterName::X19) => todo!(), + (ArmWidth::Double, ArmRegisterName::X20) => todo!(), + (ArmWidth::Double, ArmRegisterName::X21) => todo!(), + (ArmWidth::Double, ArmRegisterName::X22) => todo!(), + (ArmWidth::Double, ArmRegisterName::X23) => todo!(), + (ArmWidth::Double, ArmRegisterName::X24) => todo!(), + (ArmWidth::Double, ArmRegisterName::X25) => todo!(), + (ArmWidth::Double, ArmRegisterName::X26) => todo!(), + (ArmWidth::Double, ArmRegisterName::X27) => todo!(), + (ArmWidth::Double, ArmRegisterName::X28) => todo!(), + (ArmWidth::Double, ArmRegisterName::X29) => todo!(), + } + // let s: String = self.into(); + // write!(f, "{}", s) + } +} + +impl Display for ArmVal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ArmVal::Reg(arm_register) => arm_register.fmt(f), + ArmVal::Imm(x) => write!(f, "{}", x), + ArmVal::RegOffset(arm_register, offset) => { + write!(f, "[{}, {}]", arm_register, offset) + }, + } + } +} \ No newline at end of file diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 7ed8ac6..f6b05fe 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -116,7 +116,12 @@ mod tests { }, ]; - println!("{:?}", translate_instrs(riscv_asm)) + let arm_instrs = translate_instrs(riscv_asm); + println!("{:?}", arm_instrs); // assert_eq!(translated_asm, expected_output); + for instr in arm_instrs { + let x: String = instr.into(); + println!("{}", x); + } } } From 44b6a69018c38021b60317bfb66650c94463cbdd Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Fri, 21 Feb 2025 13:26:40 -0800 Subject: [PATCH 17/27] have assembly output now --- .gitignore | 2 + src/instruction.rs | 454 +++++++++++++++++++----------------- src/lib.rs | 1 + src/main.rs | 1 + src/utils.rs | 15 ++ test_binary_translate_add.S | 18 ++ tests/binaries/flake.lock | 8 +- tests/binaries/flake.nix | 30 +-- tests/test_translation.rs | 12 +- 9 files changed, 300 insertions(+), 241 deletions(-) create mode 100644 src/utils.rs create mode 100644 test_binary_translate_add.S diff --git a/.gitignore b/.gitignore index af1043f..92bc8d3 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ Cargo.lock # temporary files *.bin + +.vscode/ diff --git a/src/instruction.rs b/src/instruction.rs index d0197c7..c65811d 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -127,7 +127,7 @@ impl Default for ArmVal { } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum ArmWidth { Byte, SignedByte, @@ -323,7 +323,7 @@ pub enum RiscVRegister { T6, } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct ArmRegister { pub width: ArmWidth, pub name: ArmRegisterName, @@ -339,7 +339,7 @@ impl Default for ArmRegister { /// https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names /// Image of instructions https://duetorun.com/blog/arm/images/AArch64-registers.png /// - https://duetorun.com/blog/20230601/a64-regs/#user_program_registers -#[derive(Debug, EnumString)] +#[derive(Debug, EnumString, Copy, Clone)] pub enum ArmRegisterName { #[strum(serialize = "wzr", serialize = "xzr")] /// Zero register. Hardware special. @@ -422,232 +422,248 @@ impl Into for ArmInstruction { match self { ArmInstruction::Adc => todo!(), ArmInstruction::Add { dest, arg1, arg2 } => { - format!("add {} {} {}", dest, arg1, arg2) + format!("add {}, {}, {}", dest, arg1, arg2) }, ArmInstruction::And => todo!(), ArmInstruction::B => todo!(), - ArmInstruction::Blr { target } => todo!(), - ArmInstruction::Ldr { width, dest, src } => todo!(), + ArmInstruction::Blr { target } => { + format!("blr {}", Into::::into(target)) + }, + ArmInstruction::Ldr { width, dest, src } => { + match width { + ArmWidth::Word | ArmWidth::Double => format!("ldr {}, {}", dest, src), + _ => todo!() + } + }, ArmInstruction::Mov => todo!(), ArmInstruction::Ret => todo!(), - ArmInstruction::Str { width, src, dest } => todo!(), + ArmInstruction::Str { width, src, dest } => { + match width { + ArmWidth::Word => format!("str {}, {}", src, dest), + ArmWidth::Double => format!("str {}, {}", src, dest), + _ => todo!("{:?}", width) + } + }, ArmInstruction::Sub { dest, arg1, arg2 } => { - format!("sub {} {} {}", dest, arg1, arg2) + format!("sub {}, {}, {}", dest, arg1, arg2) + }, + ArmInstruction::Sxtw { dest, src } => { + format!("sxtw {}, {}", dest, src) }, - ArmInstruction::Sxtw { dest, src } => todo!(), } } } + +impl Into for ArmRegister { + fn into(self) -> String { + let s: &str = match (self.name, self.width) { + (ArmRegisterName::Zero, ArmWidth::Word) => "wzr", + (ArmRegisterName::Zero, ArmWidth::Double) => "xzr", + (ArmRegisterName::Zero, _) => panic!("invalid width for zero register"), + (ArmRegisterName::Pc, ArmWidth::Byte) => todo!(), + (ArmRegisterName::Pc, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::Pc, ArmWidth::Half) => todo!(), + (ArmRegisterName::Pc, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::Pc, ArmWidth::Word) => todo!(), + (ArmRegisterName::Pc, ArmWidth::Double) => todo!(), + (ArmRegisterName::Sp, _) => "sp", + (ArmRegisterName::Lr, ArmWidth::Byte) => todo!(), + (ArmRegisterName::Lr, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::Lr, ArmWidth::Half) => todo!(), + (ArmRegisterName::Lr, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::Lr, ArmWidth::Word) => todo!(), + (ArmRegisterName::Lr, ArmWidth::Double) => "lr", + (ArmRegisterName::X0, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X0, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X0, ArmWidth::Half) => todo!(), + (ArmRegisterName::X0, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X0, ArmWidth::Word) => todo!(), + (ArmRegisterName::X0, ArmWidth::Double) => todo!(), + (ArmRegisterName::X1, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X1, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X1, ArmWidth::Half) => todo!(), + (ArmRegisterName::X1, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X1, ArmWidth::Word) => todo!(), + (ArmRegisterName::X1, ArmWidth::Double) => todo!(), + (ArmRegisterName::X2, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X2, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X2, ArmWidth::Half) => todo!(), + (ArmRegisterName::X2, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X2, ArmWidth::Word) => todo!(), + (ArmRegisterName::X2, ArmWidth::Double) => todo!(), + (ArmRegisterName::X3, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X3, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X3, ArmWidth::Half) => todo!(), + (ArmRegisterName::X3, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X3, ArmWidth::Word) => todo!(), + (ArmRegisterName::X3, ArmWidth::Double) => todo!(), + (ArmRegisterName::X4, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X4, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X4, ArmWidth::Half) => todo!(), + (ArmRegisterName::X4, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X4, ArmWidth::Word) => todo!(), + (ArmRegisterName::X4, ArmWidth::Double) => todo!(), + (ArmRegisterName::X5, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X5, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X5, ArmWidth::Half) => todo!(), + (ArmRegisterName::X5, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X5, ArmWidth::Word) => "w5", + (ArmRegisterName::X5, ArmWidth::Double) => "x5", + (ArmRegisterName::X6, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X6, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X6, ArmWidth::Half) => todo!(), + (ArmRegisterName::X6, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X6, ArmWidth::Word) => todo!(), + (ArmRegisterName::X6, ArmWidth::Double) => todo!(), + (ArmRegisterName::X7, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X7, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X7, ArmWidth::Half) => todo!(), + (ArmRegisterName::X7, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X7, ArmWidth::Word) => "w7", + (ArmRegisterName::X7, ArmWidth::Double) => "x7", + (ArmRegisterName::X8, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X8, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X8, ArmWidth::Half) => todo!(), + (ArmRegisterName::X8, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X8, ArmWidth::Word) => todo!(), + (ArmRegisterName::X8, ArmWidth::Double) => todo!(), + (ArmRegisterName::X9, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X9, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X9, ArmWidth::Half) => todo!(), + (ArmRegisterName::X9, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X9, ArmWidth::Word) => todo!(), + (ArmRegisterName::X9, ArmWidth::Double) => todo!(), + (ArmRegisterName::X10, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X10, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X10, ArmWidth::Half) => todo!(), + (ArmRegisterName::X10, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X10, ArmWidth::Word) => todo!(), + (ArmRegisterName::X10, ArmWidth::Double) => todo!(), + (ArmRegisterName::X11, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X11, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X11, ArmWidth::Half) => todo!(), + (ArmRegisterName::X11, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X11, ArmWidth::Word) => "w11", + (ArmRegisterName::X11, ArmWidth::Double) => "x11", + (ArmRegisterName::X12, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X12, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X12, ArmWidth::Half) => todo!(), + (ArmRegisterName::X12, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X12, ArmWidth::Word) => "w12", + (ArmRegisterName::X12, ArmWidth::Double) => "x12", + (ArmRegisterName::X13, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X13, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X13, ArmWidth::Half) => todo!(), + (ArmRegisterName::X13, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X13, ArmWidth::Word) => todo!(), + (ArmRegisterName::X13, ArmWidth::Double) => todo!(), + (ArmRegisterName::X14, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X14, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X14, ArmWidth::Half) => todo!(), + (ArmRegisterName::X14, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X14, ArmWidth::Word) => todo!(), + (ArmRegisterName::X14, ArmWidth::Double) => todo!(), + (ArmRegisterName::X15, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X15, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X15, ArmWidth::Half) => todo!(), + (ArmRegisterName::X15, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X15, ArmWidth::Word) => todo!(), + (ArmRegisterName::X15, ArmWidth::Double) => todo!(), + (ArmRegisterName::X16, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X16, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X16, ArmWidth::Half) => todo!(), + (ArmRegisterName::X16, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X16, ArmWidth::Word) => todo!(), + (ArmRegisterName::X16, ArmWidth::Double) => todo!(), + (ArmRegisterName::X17, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X17, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X17, ArmWidth::Half) => todo!(), + (ArmRegisterName::X17, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X17, ArmWidth::Word) => todo!(), + (ArmRegisterName::X17, ArmWidth::Double) => todo!(), + (ArmRegisterName::X18, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X18, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X18, ArmWidth::Half) => todo!(), + (ArmRegisterName::X18, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X18, ArmWidth::Word) => todo!(), + (ArmRegisterName::X18, ArmWidth::Double) => todo!(), + (ArmRegisterName::X19, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X19, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X19, ArmWidth::Half) => todo!(), + (ArmRegisterName::X19, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X19, ArmWidth::Word) => todo!(), + (ArmRegisterName::X19, ArmWidth::Double) => todo!(), + (ArmRegisterName::X20, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X20, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X20, ArmWidth::Half) => todo!(), + (ArmRegisterName::X20, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X20, ArmWidth::Word) => todo!(), + (ArmRegisterName::X20, ArmWidth::Double) => todo!(), + (ArmRegisterName::X21, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X21, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X21, ArmWidth::Half) => todo!(), + (ArmRegisterName::X21, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X21, ArmWidth::Word) => todo!(), + (ArmRegisterName::X21, ArmWidth::Double) => todo!(), + (ArmRegisterName::X22, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X22, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X22, ArmWidth::Half) => todo!(), + (ArmRegisterName::X22, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X22, ArmWidth::Word) => todo!(), + (ArmRegisterName::X22, ArmWidth::Double) => todo!(), + (ArmRegisterName::X23, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X23, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X23, ArmWidth::Half) => todo!(), + (ArmRegisterName::X23, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X23, ArmWidth::Word) => todo!(), + (ArmRegisterName::X23, ArmWidth::Double) => todo!(), + (ArmRegisterName::X24, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X24, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X24, ArmWidth::Half) => todo!(), + (ArmRegisterName::X24, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X24, ArmWidth::Word) => todo!(), + (ArmRegisterName::X24, ArmWidth::Double) => todo!(), + (ArmRegisterName::X25, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X25, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X25, ArmWidth::Half) => todo!(), + (ArmRegisterName::X25, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X25, ArmWidth::Word) => todo!(), + (ArmRegisterName::X25, ArmWidth::Double) => todo!(), + (ArmRegisterName::X26, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X26, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X26, ArmWidth::Half) => todo!(), + (ArmRegisterName::X26, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X26, ArmWidth::Word) => todo!(), + (ArmRegisterName::X26, ArmWidth::Double) => todo!(), + (ArmRegisterName::X27, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X27, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X27, ArmWidth::Half) => todo!(), + (ArmRegisterName::X27, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X27, ArmWidth::Word) => todo!(), + (ArmRegisterName::X27, ArmWidth::Double) => todo!(), + (ArmRegisterName::X28, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X28, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X28, ArmWidth::Half) => todo!(), + (ArmRegisterName::X28, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X28, ArmWidth::Word) => todo!(), + (ArmRegisterName::X28, ArmWidth::Double) => todo!(), + (ArmRegisterName::X29, ArmWidth::Byte) => todo!(), + (ArmRegisterName::X29, ArmWidth::SignedByte) => todo!(), + (ArmRegisterName::X29, ArmWidth::Half) => todo!(), + (ArmRegisterName::X29, ArmWidth::SignedHalf) => todo!(), + (ArmRegisterName::X29, ArmWidth::Word) => todo!(), + (ArmRegisterName::X29, ArmWidth::Double) => todo!(), + }; + s.to_string() + } +} + impl Display for ArmRegister { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match (&self.width, &self.name) { - (ArmWidth::Byte, ArmRegisterName::Zero) => todo!(), - (ArmWidth::Byte, ArmRegisterName::Pc) => todo!(), - (ArmWidth::Byte, ArmRegisterName::Sp) => todo!(), - (ArmWidth::Byte, ArmRegisterName::Lr) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X0) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X1) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X2) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X3) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X4) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X5) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X6) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X7) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X8) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X9) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X10) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X11) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X12) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X13) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X14) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X15) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X16) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X17) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X18) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X19) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X20) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X21) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X22) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X23) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X24) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X25) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X26) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X27) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X28) => todo!(), - (ArmWidth::Byte, ArmRegisterName::X29) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::Zero) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::Pc) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::Sp) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::Lr) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X0) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X1) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X2) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X3) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X4) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X5) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X6) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X7) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X8) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X9) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X10) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X11) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X12) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X13) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X14) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X15) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X16) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X17) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X18) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X19) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X20) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X21) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X22) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X23) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X24) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X25) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X26) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X27) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X28) => todo!(), - (ArmWidth::SignedByte, ArmRegisterName::X29) => todo!(), - (ArmWidth::Half, ArmRegisterName::Zero) => todo!(), - (ArmWidth::Half, ArmRegisterName::Pc) => todo!(), - (ArmWidth::Half, ArmRegisterName::Sp) => todo!(), - (ArmWidth::Half, ArmRegisterName::Lr) => todo!(), - (ArmWidth::Half, ArmRegisterName::X0) => todo!(), - (ArmWidth::Half, ArmRegisterName::X1) => todo!(), - (ArmWidth::Half, ArmRegisterName::X2) => todo!(), - (ArmWidth::Half, ArmRegisterName::X3) => todo!(), - (ArmWidth::Half, ArmRegisterName::X4) => todo!(), - (ArmWidth::Half, ArmRegisterName::X5) => todo!(), - (ArmWidth::Half, ArmRegisterName::X6) => todo!(), - (ArmWidth::Half, ArmRegisterName::X7) => todo!(), - (ArmWidth::Half, ArmRegisterName::X8) => todo!(), - (ArmWidth::Half, ArmRegisterName::X9) => todo!(), - (ArmWidth::Half, ArmRegisterName::X10) => todo!(), - (ArmWidth::Half, ArmRegisterName::X11) => todo!(), - (ArmWidth::Half, ArmRegisterName::X12) => todo!(), - (ArmWidth::Half, ArmRegisterName::X13) => todo!(), - (ArmWidth::Half, ArmRegisterName::X14) => todo!(), - (ArmWidth::Half, ArmRegisterName::X15) => todo!(), - (ArmWidth::Half, ArmRegisterName::X16) => todo!(), - (ArmWidth::Half, ArmRegisterName::X17) => todo!(), - (ArmWidth::Half, ArmRegisterName::X18) => todo!(), - (ArmWidth::Half, ArmRegisterName::X19) => todo!(), - (ArmWidth::Half, ArmRegisterName::X20) => todo!(), - (ArmWidth::Half, ArmRegisterName::X21) => todo!(), - (ArmWidth::Half, ArmRegisterName::X22) => todo!(), - (ArmWidth::Half, ArmRegisterName::X23) => todo!(), - (ArmWidth::Half, ArmRegisterName::X24) => todo!(), - (ArmWidth::Half, ArmRegisterName::X25) => todo!(), - (ArmWidth::Half, ArmRegisterName::X26) => todo!(), - (ArmWidth::Half, ArmRegisterName::X27) => todo!(), - (ArmWidth::Half, ArmRegisterName::X28) => todo!(), - (ArmWidth::Half, ArmRegisterName::X29) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::Zero) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::Pc) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::Sp) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::Lr) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X0) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X1) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X2) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X3) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X4) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X5) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X6) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X7) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X8) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X9) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X10) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X11) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X12) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X13) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X14) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X15) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X16) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X17) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X18) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X19) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X20) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X21) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X22) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X23) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X24) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X25) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X26) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X27) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X28) => todo!(), - (ArmWidth::SignedHalf, ArmRegisterName::X29) => todo!(), - (ArmWidth::Word, ArmRegisterName::Zero) => todo!(), - (ArmWidth::Word, ArmRegisterName::Pc) => todo!(), - (ArmWidth::Word, ArmRegisterName::Sp) => todo!(), - (ArmWidth::Word, ArmRegisterName::Lr) => todo!(), - (ArmWidth::Word, ArmRegisterName::X0) => todo!(), - (ArmWidth::Word, ArmRegisterName::X1) => todo!(), - (ArmWidth::Word, ArmRegisterName::X2) => todo!(), - (ArmWidth::Word, ArmRegisterName::X3) => todo!(), - (ArmWidth::Word, ArmRegisterName::X4) => todo!(), - (ArmWidth::Word, ArmRegisterName::X5) => todo!(), - (ArmWidth::Word, ArmRegisterName::X6) => todo!(), - (ArmWidth::Word, ArmRegisterName::X7) => todo!(), - (ArmWidth::Word, ArmRegisterName::X8) => todo!(), - (ArmWidth::Word, ArmRegisterName::X9) => todo!(), - (ArmWidth::Word, ArmRegisterName::X10) => todo!(), - (ArmWidth::Word, ArmRegisterName::X11) => todo!(), - (ArmWidth::Word, ArmRegisterName::X12) => todo!(), - (ArmWidth::Word, ArmRegisterName::X13) => todo!(), - (ArmWidth::Word, ArmRegisterName::X14) => todo!(), - (ArmWidth::Word, ArmRegisterName::X15) => todo!(), - (ArmWidth::Word, ArmRegisterName::X16) => todo!(), - (ArmWidth::Word, ArmRegisterName::X17) => todo!(), - (ArmWidth::Word, ArmRegisterName::X18) => todo!(), - (ArmWidth::Word, ArmRegisterName::X19) => todo!(), - (ArmWidth::Word, ArmRegisterName::X20) => todo!(), - (ArmWidth::Word, ArmRegisterName::X21) => todo!(), - (ArmWidth::Word, ArmRegisterName::X22) => todo!(), - (ArmWidth::Word, ArmRegisterName::X23) => todo!(), - (ArmWidth::Word, ArmRegisterName::X24) => todo!(), - (ArmWidth::Word, ArmRegisterName::X25) => todo!(), - (ArmWidth::Word, ArmRegisterName::X26) => todo!(), - (ArmWidth::Word, ArmRegisterName::X27) => todo!(), - (ArmWidth::Word, ArmRegisterName::X28) => todo!(), - (ArmWidth::Word, ArmRegisterName::X29) => todo!(), - (ArmWidth::Double, ArmRegisterName::Zero) => todo!(), - (ArmWidth::Double, ArmRegisterName::Pc) => todo!(), - (ArmWidth::Double, ArmRegisterName::Sp) => todo!(), - (ArmWidth::Double, ArmRegisterName::Lr) => todo!(), - (ArmWidth::Double, ArmRegisterName::X0) => todo!(), - (ArmWidth::Double, ArmRegisterName::X1) => todo!(), - (ArmWidth::Double, ArmRegisterName::X2) => todo!(), - (ArmWidth::Double, ArmRegisterName::X3) => todo!(), - (ArmWidth::Double, ArmRegisterName::X4) => todo!(), - (ArmWidth::Double, ArmRegisterName::X5) => todo!(), - (ArmWidth::Double, ArmRegisterName::X6) => todo!(), - (ArmWidth::Double, ArmRegisterName::X7) => todo!(), - (ArmWidth::Double, ArmRegisterName::X8) => todo!(), - (ArmWidth::Double, ArmRegisterName::X9) => todo!(), - (ArmWidth::Double, ArmRegisterName::X10) => todo!(), - (ArmWidth::Double, ArmRegisterName::X11) => todo!(), - (ArmWidth::Double, ArmRegisterName::X12) => todo!(), - (ArmWidth::Double, ArmRegisterName::X13) => todo!(), - (ArmWidth::Double, ArmRegisterName::X14) => todo!(), - (ArmWidth::Double, ArmRegisterName::X15) => todo!(), - (ArmWidth::Double, ArmRegisterName::X16) => todo!(), - (ArmWidth::Double, ArmRegisterName::X17) => todo!(), - (ArmWidth::Double, ArmRegisterName::X18) => todo!(), - (ArmWidth::Double, ArmRegisterName::X19) => todo!(), - (ArmWidth::Double, ArmRegisterName::X20) => todo!(), - (ArmWidth::Double, ArmRegisterName::X21) => todo!(), - (ArmWidth::Double, ArmRegisterName::X22) => todo!(), - (ArmWidth::Double, ArmRegisterName::X23) => todo!(), - (ArmWidth::Double, ArmRegisterName::X24) => todo!(), - (ArmWidth::Double, ArmRegisterName::X25) => todo!(), - (ArmWidth::Double, ArmRegisterName::X26) => todo!(), - (ArmWidth::Double, ArmRegisterName::X27) => todo!(), - (ArmWidth::Double, ArmRegisterName::X28) => todo!(), - (ArmWidth::Double, ArmRegisterName::X29) => todo!(), - } + let x: String = self.clone().into(); + write!(f, "{}", x) // let s: String = self.into(); // write!(f, "{}", s) } @@ -663,4 +679,10 @@ impl Display for ArmVal { }, } } -} \ No newline at end of file +} + +impl Into for ArmRegisterName { + fn into(self) -> ArmRegister { + ArmRegister { width: ArmWidth::Double, name: self } + } +} diff --git a/src/lib.rs b/src/lib.rs index 28612f2..1f3c912 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod instruction; pub mod translate; +pub mod utils; diff --git a/src/main.rs b/src/main.rs index 938d608..f2648a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::fs; use std::str::FromStr; pub mod instruction; pub mod translate; +pub mod utils; use instruction::RiscVInstruction; use translate::binary_translate; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..25547b2 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,15 @@ +use std::fs; + +use crate::{instruction::RiscVInstruction, translate::translate_instrs}; + + +pub fn translate_to_file(instrs: Vec, path: String) { + let arm_instrs = translate_instrs(instrs); + let mut contents = String::new(); + for instr in arm_instrs { + let x: String = instr.into(); + contents.push_str(&x); + contents.push_str("\n"); + } + fs::write(path, contents).expect("Unable to write file"); +} \ No newline at end of file diff --git a/test_binary_translate_add.S b/test_binary_translate_add.S new file mode 100644 index 0000000..100bfc8 --- /dev/null +++ b/test_binary_translate_add.S @@ -0,0 +1,18 @@ +sub sp, sp, -32 +str lr, [sp, 24] +str x5, [sp, 16] +add w5, sp, 32 +add x12, xzr, 3 +str w12, [w5, -20] +add x12, xzr, 4 +str w12, [w5, -24] +ldr w12, [w5, -20] +add x11, x12, 0 +ldr w12, [w5, -24] +add w12, w11, w12 +sxtw x12, w12 +add x7, x12, 0 +ldr lr, [sp, 24] +ldr x5, [sp, 16] +add sp, sp, 32 +blr lr diff --git a/tests/binaries/flake.lock b/tests/binaries/flake.lock index 3bc2a40..24105b1 100644 --- a/tests/binaries/flake.lock +++ b/tests/binaries/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1737885589, - "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", + "lastModified": 1739923778, + "narHash": "sha256-BqUY8tz0AQ4to2Z4+uaKczh81zsGZSYxjgvtw+fvIfM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", + "rev": "36864ed72f234b9540da4cf7a0c49e351d30d3f1", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-unstable", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } diff --git a/tests/binaries/flake.nix b/tests/binaries/flake.nix index 451d912..d408be5 100644 --- a/tests/binaries/flake.nix +++ b/tests/binaries/flake.nix @@ -2,23 +2,25 @@ description = "A very basic flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; }; - outputs = { self, nixpkgs }: let - pkgs = import nixpkgs { - # inherit system; - system = "x86_64-linux"; - crossSystem.config = "riscv64-linux-gnu"; - }; - in { - devShells.x86_64-linux.default = pkgs.mkShell { - # Use the same mkShell as documented above + outputs = { self, nixpkgs }: + let + pkgs = import nixpkgs { + # inherit system; + system = "x86_64-linux"; + crossSystem.config = "aarch64-linux-gnu"; + }; + in + { + devShells.x86_64-linux.default = pkgs.mkShell { + # Use the same mkShell as documented above packages = with pkgs; [ -gcc - # pkgs.clang-tools - ]; + gcc + # pkgs.clang-tools + ]; + }; }; - }; } diff --git a/tests/test_translation.rs b/tests/test_translation.rs index f6b05fe..9335be1 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -2,6 +2,8 @@ mod tests { use binary_room::instruction::*; use binary_room::translate::*; + use binary_room::utils; + use binary_room::utils::translate_to_file; #[test] fn test_binary_translate() { @@ -116,12 +118,8 @@ mod tests { }, ]; - let arm_instrs = translate_instrs(riscv_asm); - println!("{:?}", arm_instrs); - // assert_eq!(translated_asm, expected_output); - for instr in arm_instrs { - let x: String = instr.into(); - println!("{}", x); - } + translate_to_file(riscv_asm, "test_binary_translate_add.S".to_string()); + + } } From 6ced896c5e6175f47adec50febfa419e31db2398 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sun, 2 Mar 2025 20:45:29 -0800 Subject: [PATCH 18/27] patched and assembled aarch64 add --- tests/binaries/add_aarch64_assembled.out | Bin 0 -> 752 bytes tests/binaries/patched_binary_translate_add.S | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100755 tests/binaries/add_aarch64_assembled.out create mode 100644 tests/binaries/patched_binary_translate_add.S diff --git a/tests/binaries/add_aarch64_assembled.out b/tests/binaries/add_aarch64_assembled.out new file mode 100755 index 0000000000000000000000000000000000000000..746730f7d974dc17ee780af945daeb89924e9ce7 GIT binary patch literal 752 zcmb<-^>JfjWMqH=MuzPS2p&w7fx!St&;cy$z`)MH#_+$HVd6i2hM!Nlfw-ALFo&Vx z(wYNuJ9 Date: Mon, 3 Mar 2025 20:20:32 -0800 Subject: [PATCH 19/27] fix patched add example --- tests/binaries/patched_binary_translate_add.S | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/binaries/patched_binary_translate_add.S b/tests/binaries/patched_binary_translate_add.S index c3e0e29..a9468a9 100644 --- a/tests/binaries/patched_binary_translate_add.S +++ b/tests/binaries/patched_binary_translate_add.S @@ -1,18 +1,29 @@ -sub sp, sp, -32 +.text + +.global _start + +_start: +bl main +mov x8, #93 +svc #0 + +main: +sub sp, sp, 32 str lr, [sp, 24] -str x5, [sp, 16] -add w5, wsp, 32 +str fp, [sp, 16] +add fp, sp, 32 mov x12, 3 -str w12, [x5, -20] +str w12, [fp, -20] mov x12, 4 -str w12, [x5, -24] -ldr w12, [x5, -20] +str w12, [fp, -24] +ldr w12, [fp, -20] add x11, x12, 0 -ldr w12, [x5, -24] +ldr w12, [fp, -24] add w12, w11, w12 sxtw x12, w12 -add x7, x12, 0 +add x0, x12, 0 ldr lr, [sp, 24] -ldr x5, [sp, 16] +ldr fp, [sp, 16] add sp, sp, 32 -blr lr +ret + From 6fa93fff8dd8dcbbc6340783a458b63e36639345 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Wed, 5 Mar 2025 15:04:58 -0800 Subject: [PATCH 20/27] fixed width/segfault issues --- run.sh | 6 ++++++ src/instruction.rs | 35 +++++++++++++++++++++++++++-------- src/translate.rs | 41 ++++++++++++++++++++++++++++++----------- src/utils.rs | 14 +++++++++++++- 4 files changed, 76 insertions(+), 20 deletions(-) create mode 100755 run.sh diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..49c6be3 --- /dev/null +++ b/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +aarch64-linux-gnu-as test_binary_translate_add.S +aarch64-linux-gnu-ld a.out -o a.bin +./a.bin +echo $? diff --git a/src/instruction.rs b/src/instruction.rs index c65811d..ddb471c 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -75,6 +75,13 @@ pub enum RiscVInstruction { dest: RiscVRegister, src: RiscVRegister, }, + // Copy immediate + // `mv rd, rs1` expands to `addi rd, rs, 0` + #[strum(serialize = "mvi")] + Mvi { + dest: RiscVRegister, + imm: i32, + }, /// Sign extend Word /// /// psuedo instruction which translates to `addiw rd, rs, 0` @@ -175,7 +182,11 @@ pub enum ArmInstruction { src: ArmVal, }, #[strum(serialize = "mov")] - Mov, + Mov { + width: ArmWidth, + dest: ArmRegister, + src: ArmVal + }, #[strum(serialize = "ret")] Ret, /// Str [r2 + offset] = r1 @@ -435,7 +446,9 @@ impl Into for ArmInstruction { _ => todo!() } }, - ArmInstruction::Mov => todo!(), + ArmInstruction::Mov { width, dest, src } => { + format!("mov {}, {}", dest, src) + }, ArmInstruction::Ret => todo!(), ArmInstruction::Str { width, src, dest } => { match width { @@ -468,7 +481,9 @@ impl Into for ArmRegister { (ArmRegisterName::Pc, ArmWidth::SignedHalf) => todo!(), (ArmRegisterName::Pc, ArmWidth::Word) => todo!(), (ArmRegisterName::Pc, ArmWidth::Double) => todo!(), - (ArmRegisterName::Sp, _) => "sp", + (ArmRegisterName::Sp, ArmWidth::Word) => "wsp", + (ArmRegisterName::Sp, ArmWidth::Double) => "sp", + (ArmRegisterName::Sp, _) => todo!(), (ArmRegisterName::Lr, ArmWidth::Byte) => todo!(), (ArmRegisterName::Lr, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::Lr, ArmWidth::Half) => todo!(), @@ -479,8 +494,8 @@ impl Into for ArmRegister { (ArmRegisterName::X0, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X0, ArmWidth::Half) => todo!(), (ArmRegisterName::X0, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X0, ArmWidth::Word) => todo!(), - (ArmRegisterName::X0, ArmWidth::Double) => todo!(), + (ArmRegisterName::X0, ArmWidth::Word) => "w0", + (ArmRegisterName::X0, ArmWidth::Double) => "x0", (ArmRegisterName::X1, ArmWidth::Byte) => todo!(), (ArmRegisterName::X1, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X1, ArmWidth::Half) => todo!(), @@ -653,8 +668,8 @@ impl Into for ArmRegister { (ArmRegisterName::X29, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X29, ArmWidth::Half) => todo!(), (ArmRegisterName::X29, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X29, ArmWidth::Word) => todo!(), - (ArmRegisterName::X29, ArmWidth::Double) => todo!(), + (ArmRegisterName::X29, ArmWidth::Word) => "w29", + (ArmRegisterName::X29, ArmWidth::Double) => "x29", }; s.to_string() } @@ -675,7 +690,11 @@ impl Display for ArmVal { ArmVal::Reg(arm_register) => arm_register.fmt(f), ArmVal::Imm(x) => write!(f, "{}", x), ArmVal::RegOffset(arm_register, offset) => { - write!(f, "[{}, {}]", arm_register, offset) + let double_reg = ArmRegister { + name: arm_register.name, + width: ArmWidth::Double + }; + write!(f, "[{}, {}]", double_reg, offset) }, } } diff --git a/src/translate.rs b/src/translate.rs index 13677be..3a0d6c7 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -17,7 +17,11 @@ macro_rules! sorry { pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { match riscv_instr { RiscVInstruction::Addi { dest, src, imm } => { - let width = RiscVWidth::Word; + if let RiscVRegister::X0 = src { + return translate(RiscVInstruction::Mvi { dest, imm }); + } + + let width = RiscVWidth::Double; if imm >= 0 { ArmInstruction::Add { dest: map_register(dest, &width), @@ -28,7 +32,7 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { ArmInstruction::Sub { dest: map_register(dest, &width), arg1: map_register(src, &width), - arg2: ArmVal::Imm(imm), + arg2: ArmVal::Imm(imm.abs()), } } } @@ -50,6 +54,14 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { arg2: ArmVal::Imm(0), } }, + RiscVInstruction::Mvi { dest, imm } => { + let width = RiscVWidth::Double; + ArmInstruction::Mov { + width: map_width(&width), + dest: map_register(dest, &width), + src: ArmVal::Imm(imm) + } + }, RiscVInstruction::Add { width, dest, @@ -90,14 +102,20 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { panic!("Li with imm out of range"); } - ArmInstruction::Add { - dest: map_register(dest, &RiscVWidth::Double), - arg1: ArmRegister { - width: ArmWidth::Double, - name: ArmRegisterName::Zero, - }, - arg2: ArmVal::Imm(imm), + let width = RiscVWidth::Double; + ArmInstruction::Mov { + width: map_width(&width), + dest: map_register(dest, &width), + src: ArmVal::Imm(imm) } + // ArmInstruction::Add { + // dest: map_register(dest, &RiscVWidth::Double), + // arg1: ArmRegister { + // width: ArmWidth::Double, + // name: ArmRegisterName::Zero, + // }, + // arg2: ArmVal::Imm(imm), + // } } } } @@ -121,9 +139,9 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { RiscVRegister::T0 => ArmRegisterName::X2, RiscVRegister::T1 => ArmRegisterName::X3, RiscVRegister::T2 => ArmRegisterName::X4, - RiscVRegister::S0FP => ArmRegisterName::X5, + // skipped X5 RiscVRegister::S1 => ArmRegisterName::X6, - RiscVRegister::A0 => ArmRegisterName::X7, + RiscVRegister::A0 => ArmRegisterName::X0, RiscVRegister::A1 => ArmRegisterName::X8, RiscVRegister::A2 => ArmRegisterName::X9, RiscVRegister::A3 => ArmRegisterName::X10, @@ -145,6 +163,7 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { RiscVRegister::T4 => ArmRegisterName::X26, RiscVRegister::T5 => ArmRegisterName::X27, RiscVRegister::T6 => ArmRegisterName::X28, + RiscVRegister::S0FP => ArmRegisterName::X29, } } diff --git a/src/utils.rs b/src/utils.rs index 25547b2..b3f8c9e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,10 +2,22 @@ use std::fs; use crate::{instruction::RiscVInstruction, translate::translate_instrs}; +const start: &str = r#" +.text + +.global _start + +_start: +bl main +mov x8, #93 +svc #0 + +main: +"#; pub fn translate_to_file(instrs: Vec, path: String) { let arm_instrs = translate_instrs(instrs); - let mut contents = String::new(); + let mut contents = String::from(start); for instr in arm_instrs { let x: String = instr.into(); contents.push_str(&x); From 2c692d6205f73c4c34aa0a3c0d849d06f82ff7c4 Mon Sep 17 00:00:00 2001 From: David Tran Date: Tue, 11 Mar 2025 16:40:06 -0700 Subject: [PATCH 21/27] call syscall --- src/instruction.rs | 82 +++++++++++++++++++++++++---- src/translate.rs | 66 ++++++++++++++++------- tests/test_translation.rs | 107 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+), 28 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index ddb471c..a347356 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,6 +1,6 @@ use std::convert::Into; use std::default; -use std::fmt::{write, Display}; +use std::fmt::{format, write, Display}; /// This file defines all the supported ARM and RISC-V instructions we support. /// We use `strum` to assist in serializing asm files to our [`Instruction`] enum. @@ -37,6 +37,12 @@ pub enum RiscVInstruction { src: RiscVRegister, imm: i32, }, + /// add label/offset addr (not a real RISC-V instr) + Addl { + dest: RiscVRegister, + src: RiscVRegister, + label: RiscVVal + }, /// add register /// either add or addw /// (addw is 32 bits on 64 bit riscv) @@ -50,6 +56,11 @@ pub enum RiscVInstruction { arg1: RiscVRegister, arg2: RiscVRegister, }, + /// call label + #[strum(serialize = "call")] + Call { + label: RiscVVal + }, /// Store values from register rs2 to memory. /// /// `M[x[rs1] + sext(offset)] = x[rs2]` @@ -68,6 +79,18 @@ pub enum RiscVInstruction { dest: RiscVRegister, src: RiscVVal, }, + Directive { + name: String, + operands: String + }, + Label { + name: String + }, + #[strum(serialize = "lui")] + Lui { + dest: RiscVRegister, + src: RiscVVal + }, // Copy register // `mv rd, rs1` expands to `addi rd, rs, 0` #[strum(serialize = "mv")] @@ -126,6 +149,7 @@ pub enum ArmVal { Reg(ArmRegister), Imm(i32), RegOffset(ArmRegister, i32), + LabelOffset(String, i32) } impl Default for ArmVal { @@ -169,12 +193,28 @@ pub enum ArmInstruction { /// AND AND Rd := Rn AND Op2 #[strum(serialize = "and")] And, + /// ADRP Rd := page_addr(label) + #[strum(serialize = "adrp")] + Adrp { + dest: ArmRegister, + label: ArmVal + }, /// B Branch R15 := address #[strum(serialize = "b")] B, /// BLR Xn #[strum(serialize = "blr")] Blr { target: ArmRegisterName }, + /// BL label + #[strum(serialize = "bl")] + Bl {target: ArmVal}, + /// label: + Label { name: String }, + /// .directive operands + Directive { + name: String, + operands: String + }, #[strum(serialize = "ldr")] Ldr { width: ArmWidth, @@ -223,6 +263,10 @@ pub enum RiscVVal { register: RiscVRegister, offset: i32, }, + LabelOffset { + label: String, + offset: i32 + } } impl Default for RiscVVal { @@ -436,6 +480,9 @@ impl Into for ArmInstruction { format!("add {}, {}, {}", dest, arg1, arg2) }, ArmInstruction::And => todo!(), + ArmInstruction::Adrp { dest, label } => { + format!("adrp {}, {}", dest, label) + } ArmInstruction::B => todo!(), ArmInstruction::Blr { target } => { format!("blr {}", Into::::into(target)) @@ -464,6 +511,15 @@ impl Into for ArmInstruction { ArmInstruction::Sxtw { dest, src } => { format!("sxtw {}, {}", dest, src) }, + ArmInstruction::Bl { target } => { + format!("bl {}", target) + }, + ArmInstruction::Label { name } => { + format!("{}:", name) + }, + ArmInstruction::Directive { name, operands } => { + format!(".{} {}", name, operands) + } } } } @@ -500,26 +556,26 @@ impl Into for ArmRegister { (ArmRegisterName::X1, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X1, ArmWidth::Half) => todo!(), (ArmRegisterName::X1, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X1, ArmWidth::Word) => todo!(), - (ArmRegisterName::X1, ArmWidth::Double) => todo!(), + (ArmRegisterName::X1, ArmWidth::Word) => "w1", + (ArmRegisterName::X1, ArmWidth::Double) => "x1", (ArmRegisterName::X2, ArmWidth::Byte) => todo!(), (ArmRegisterName::X2, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X2, ArmWidth::Half) => todo!(), (ArmRegisterName::X2, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X2, ArmWidth::Word) => todo!(), - (ArmRegisterName::X2, ArmWidth::Double) => todo!(), + (ArmRegisterName::X2, ArmWidth::Word) => "w2", + (ArmRegisterName::X2, ArmWidth::Double) => "x2", (ArmRegisterName::X3, ArmWidth::Byte) => todo!(), (ArmRegisterName::X3, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X3, ArmWidth::Half) => todo!(), (ArmRegisterName::X3, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X3, ArmWidth::Word) => todo!(), - (ArmRegisterName::X3, ArmWidth::Double) => todo!(), + (ArmRegisterName::X3, ArmWidth::Word) => "w3", + (ArmRegisterName::X3, ArmWidth::Double) => "x3", (ArmRegisterName::X4, ArmWidth::Byte) => todo!(), (ArmRegisterName::X4, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X4, ArmWidth::Half) => todo!(), (ArmRegisterName::X4, ArmWidth::SignedHalf) => todo!(), - (ArmRegisterName::X4, ArmWidth::Word) => todo!(), - (ArmRegisterName::X4, ArmWidth::Double) => todo!(), + (ArmRegisterName::X4, ArmWidth::Word) => "w4", + (ArmRegisterName::X4, ArmWidth::Double) => "x4", (ArmRegisterName::X5, ArmWidth::Byte) => todo!(), (ArmRegisterName::X5, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X5, ArmWidth::Half) => todo!(), @@ -696,6 +752,14 @@ impl Display for ArmVal { }; write!(f, "[{}, {}]", double_reg, offset) }, + ArmVal::LabelOffset(name, offset) => { + match offset { + 0 => write!(f, "{}", name), + 9998 => write!(f, "{}", name), // %hi in riscv is adrp with no offset in arm + 9999 => write!(f, ":lo12:{}", name), // reserved for 12 low bits of label addr + _ => write!(f, "[{}, {}]", name, offset) + } + } } } } diff --git a/src/translate.rs b/src/translate.rs index 3a0d6c7..ad3e6ae 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -46,22 +46,27 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { dest: map_register(dest, &width), src: map_val(src, &width), }, - RiscVInstruction::Mv { dest, src } => { + RiscVInstruction::Directive { name, operands } => { + let arm_operands = operands.replace("@", "%"); + ArmInstruction::Directive { name, operands: arm_operands } + } + RiscVInstruction::Label { name } => ArmInstruction::Label { name }, + RiscVInstruction::Mv { dest, src } => { let width = RiscVWidth::Double; ArmInstruction::Add { dest: map_register(dest, &width), arg1: map_register(src, &width), arg2: ArmVal::Imm(0), } - }, - RiscVInstruction::Mvi { dest, imm } => { + } + RiscVInstruction::Mvi { dest, imm } => { let width = RiscVWidth::Double; ArmInstruction::Mov { width: map_width(&width), dest: map_register(dest, &width), - src: ArmVal::Imm(imm) + src: ArmVal::Imm(imm), } - }, + } RiscVInstruction::Add { width, dest, @@ -103,10 +108,10 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { } let width = RiscVWidth::Double; - ArmInstruction::Mov { - width: map_width(&width), - dest: map_register(dest, &width), - src: ArmVal::Imm(imm) + ArmInstruction::Mov { + width: map_width(&width), + dest: map_register(dest, &width), + src: ArmVal::Imm(imm), } // ArmInstruction::Add { // dest: map_register(dest, &RiscVWidth::Double), @@ -116,6 +121,28 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { // }, // arg2: ArmVal::Imm(imm), // } + }, + RiscVInstruction::Addl { dest, src, label } => { + let width = RiscVWidth::Double; + ArmInstruction::Add { + dest: map_register(dest, &width), + arg1: map_register(src, &width), + arg2: map_val(label, &width), + } + }, + RiscVInstruction::Lui { dest, src } => { + // only used to load upper bits or adrp in arm + let width = RiscVWidth::Double; + ArmInstruction::Adrp { + dest: map_register(dest, &width), + label: map_val(src, &width), + } + }, + RiscVInstruction::Call { label } => { + let width = RiscVWidth::Double; + ArmInstruction::Bl { + target: map_val(label, &width), + } } } } @@ -123,7 +150,7 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { fn map_register(riscv_reg: RiscVRegister, riscv_width: &RiscVWidth) -> ArmRegister { ArmRegister { width: map_width(riscv_width), - name: map_register_name(riscv_reg) + name: map_register_name(riscv_reg), } } @@ -142,13 +169,13 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { // skipped X5 RiscVRegister::S1 => ArmRegisterName::X6, RiscVRegister::A0 => ArmRegisterName::X0, - RiscVRegister::A1 => ArmRegisterName::X8, - RiscVRegister::A2 => ArmRegisterName::X9, - RiscVRegister::A3 => ArmRegisterName::X10, - RiscVRegister::A4 => ArmRegisterName::X11, - RiscVRegister::A5 => ArmRegisterName::X12, - RiscVRegister::A6 => ArmRegisterName::X13, - RiscVRegister::A7 => ArmRegisterName::X14, + RiscVRegister::A1 => ArmRegisterName::X1, + RiscVRegister::A2 => ArmRegisterName::X2, + RiscVRegister::A3 => ArmRegisterName::X3, + RiscVRegister::A4 => ArmRegisterName::X4, + RiscVRegister::A5 => ArmRegisterName::X5, + RiscVRegister::A6 => ArmRegisterName::X6, + RiscVRegister::A7 => ArmRegisterName::X7, RiscVRegister::S2 => ArmRegisterName::X15, RiscVRegister::S3 => ArmRegisterName::X16, RiscVRegister::S4 => ArmRegisterName::X17, @@ -172,15 +199,16 @@ fn map_val(riscv_val: RiscVVal, riscv_width: &RiscVWidth) -> ArmVal { RiscVVal::RiscVRegister(riscv_reg) => ArmVal::Reg(map_register(riscv_reg, riscv_width)), RiscVVal::Immediate(imm) => ArmVal::Imm(imm), RiscVVal::Offset { register, offset } => ArmVal::RegOffset(map_register(register, riscv_width), offset), + RiscVVal::LabelOffset { label, offset } => ArmVal::LabelOffset(label, offset), } } fn map_width(riscv_width: &RiscVWidth) -> ArmWidth { // todo!() - // FIXME: do real implementation + // FIXME: do real implementation match riscv_width { RiscVWidth::Double => ArmWidth::Double, - RiscVWidth::Word => ArmWidth::Word + RiscVWidth::Word => ArmWidth::Word, } } diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 9335be1..72e8f3e 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -119,7 +119,114 @@ mod tests { ]; translate_to_file(riscv_asm, "test_binary_translate_add.S".to_string()); + } + #[test] + fn test_syscall_translate() { + let riscv_asm: Vec = vec![ + RiscVInstruction::Label { name: ".LC0".to_string() }, + RiscVInstruction::Directive { + name: "string".to_string(), + operands: "\"hello, world!\\n\"" .to_string() + }, + RiscVInstruction::Directive { + name: "align".to_string(), + operands: "2".to_string() + }, + RiscVInstruction::Directive { + name: "global".to_string(), + operands: "main".to_string() + }, + RiscVInstruction::Directive { + name: "type".to_string(), + operands: "main, @function".to_string() + }, + RiscVInstruction::Label { name: "main".to_string() }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: -16, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::RA, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 8, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::S0FP, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 0 + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::S0FP, + src: RiscVRegister::SP, + imm: 16, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A3, + imm: 14, + }, + RiscVInstruction::Lui { + dest: RiscVRegister::A5, + src: RiscVVal::LabelOffset { + label: ".LC0".to_string(), + offset: 9998, // %hi riscv + }, + }, + RiscVInstruction::Addl { + dest: RiscVRegister::A2, + src: RiscVRegister::A5, + label: RiscVVal::LabelOffset { + label: ".LC0".to_string(), + offset: 9999, // %lo riscv, :lo12: arm + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A1, + imm: 1, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A0, + imm: 64, + }, + RiscVInstruction::Call { + label: RiscVVal::LabelOffset { + label: "syscall".to_string(), + offset: 0, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::RA, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 8, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::S0FP, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 0, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: 16, + }, + RiscVInstruction::Jr { + target: RiscVRegister::RA, + }, + ]; + translate_to_file(riscv_asm, "test_binary_translate_write.S".to_string()); } } From b02600a08fb4e68b920e4555e44218207609ab2d Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 11 Mar 2025 17:28:24 -0700 Subject: [PATCH 22/27] merge and working print --- flake.nix | 1 + run.sh | 9 +- src/instruction.rs | 48 ++++++- src/translate.rs | 127 +++++++++++------- src/utils.rs | 5 +- test_binary_translate_add.S | 39 ++++-- tests/binaries/patched_binary_translate_add.S | 2 +- tests/binaries/riscv/flake.lock | 27 ++++ tests/binaries/riscv/flake.nix | 26 ++++ tests/test_translation.rs | 6 +- 10 files changed, 218 insertions(+), 72 deletions(-) create mode 100644 tests/binaries/riscv/flake.lock create mode 100644 tests/binaries/riscv/flake.nix diff --git a/flake.nix b/flake.nix index 9633d6d..b3a2d2b 100644 --- a/flake.nix +++ b/flake.nix @@ -35,6 +35,7 @@ ]; packages = with pkgs; [ rust-analyzer-nightly + clang-tools ]; }; } diff --git a/run.sh b/run.sh index 49c6be3..45ea602 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash -aarch64-linux-gnu-as test_binary_translate_add.S -aarch64-linux-gnu-ld a.out -o a.bin -./a.bin +ASM_FILE=$1 + + +aarch64-linux-gnu-as $ASM_FILE -o $ASM_FILE.as +aarch64-linux-gnu-ld $ASM_FILE.as -o $ASM_FILE.bin +./$ASM_FILE.bin echo $? diff --git a/src/instruction.rs b/src/instruction.rs index a347356..b66f16f 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -13,6 +13,20 @@ use std::fmt::{format, write, Display}; /// https://github.com/nbdd0121/r2vm/blob/5118be6b9e757c6fef2f019385873f403c23c548/lib/riscv/src/op.rs#L30 use strum_macros::EnumString; +pub enum RiscVSyscalls { + WRITE, + EXIT +} + +impl RiscVSyscalls { + const fn value(&self) -> i32 { + match self { + Self::WRITE => 64, + Self::EXIT => 0, + } + } +} + #[derive(Debug, Default)] pub enum RiscVWidth { Word, @@ -133,6 +147,11 @@ pub enum RiscVInstruction { /// https://michaeljclark.github.io/asm.html #[strum(serialize = "li")] Li { dest: RiscVRegister, imm: i32 }, + /// System Call + #[strum(serialize = "ecall")] + ECall, + #[strum(serialize = "verbatim")] + Verbatim { text: String }, } impl Default for RiscVInstruction { @@ -144,6 +163,20 @@ impl Default for RiscVInstruction { } } +pub enum ArmSyscalls { + WRITE, + EXIT +} + +impl ArmSyscalls { + const fn value(&self) -> i32 { + match self { + Self::WRITE => 64, + Self::EXIT => 0, + } + } +} + #[derive(Debug)] pub enum ArmVal { Reg(ArmRegister), @@ -246,6 +279,12 @@ pub enum ArmInstruction { /// sign extend to word #[strum(serialize = "sxtw")] Sxtw { dest: ArmRegister, src: ArmRegister }, + /// service call + #[strum(serialize = "svc")] + Svc { id: i32 }, + /// compare + Cmp { op1: ArmRegister, op2: ArmVal }, + Verbatim { text: String }, } impl Default for ArmInstruction { @@ -520,6 +559,13 @@ impl Into for ArmInstruction { ArmInstruction::Directive { name, operands } => { format!(".{} {}", name, operands) } + ArmInstruction::Svc { id } => { + format!("svc {}", id) + }, + ArmInstruction::Cmp { op1, op2 } => { + format!("cmp {}, {}", op1, op2) + } + ArmInstruction::Verbatim { text } => text } } } @@ -599,7 +645,7 @@ impl Into for ArmRegister { (ArmRegisterName::X8, ArmWidth::Half) => todo!(), (ArmRegisterName::X8, ArmWidth::SignedHalf) => todo!(), (ArmRegisterName::X8, ArmWidth::Word) => todo!(), - (ArmRegisterName::X8, ArmWidth::Double) => todo!(), + (ArmRegisterName::X8, ArmWidth::Double) => "x8", (ArmRegisterName::X9, ArmWidth::Byte) => todo!(), (ArmRegisterName::X9, ArmWidth::SignedByte) => todo!(), (ArmRegisterName::X9, ArmWidth::Half) => todo!(), diff --git a/src/translate.rs b/src/translate.rs index ad3e6ae..8703126 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -14,7 +14,7 @@ macro_rules! sorry { /// Run the core logic to match from RISC-V to ARM Instructions. /// Translate one instruction at a time. -pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { +pub fn translate(riscv_instr: RiscVInstruction) -> Vec { match riscv_instr { RiscVInstruction::Addi { dest, src, imm } => { if let RiscVRegister::X0 = src { @@ -23,57 +23,57 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { let width = RiscVWidth::Double; if imm >= 0 { - ArmInstruction::Add { + vec![ArmInstruction::Add { dest: map_register(dest, &width), arg1: map_register(src, &width), arg2: ArmVal::Imm(imm), - } + }] } else { - ArmInstruction::Sub { + vec![ArmInstruction::Sub { dest: map_register(dest, &width), arg1: map_register(src, &width), arg2: ArmVal::Imm(imm.abs()), - } + }] } } - RiscVInstruction::S { width, src, dest } => ArmInstruction::Str { + RiscVInstruction::S { width, src, dest } => vec![ArmInstruction::Str { width: map_width(&width), src: map_register(src, &width), dest: map_val(dest, &width), - }, - RiscVInstruction::L { width, dest, src } => ArmInstruction::Ldr { + }], + RiscVInstruction::L { width, dest, src } => vec![ArmInstruction::Ldr { width: map_width(&width), dest: map_register(dest, &width), src: map_val(src, &width), - }, + }], RiscVInstruction::Directive { name, operands } => { let arm_operands = operands.replace("@", "%"); - ArmInstruction::Directive { name, operands: arm_operands } + vec![ArmInstruction::Directive { name, operands: arm_operands }] } - RiscVInstruction::Label { name } => ArmInstruction::Label { name }, + RiscVInstruction::Label { name } => vec![ArmInstruction::Label { name }], RiscVInstruction::Mv { dest, src } => { let width = RiscVWidth::Double; - ArmInstruction::Add { + vec![ArmInstruction::Add { dest: map_register(dest, &width), arg1: map_register(src, &width), arg2: ArmVal::Imm(0), - } - } - RiscVInstruction::Mvi { dest, imm } => { + }] + }, + RiscVInstruction::Mvi { dest, imm } => { let width = RiscVWidth::Double; - ArmInstruction::Mov { + vec![ArmInstruction::Mov { width: map_width(&width), dest: map_register(dest, &width), - src: ArmVal::Imm(imm), - } - } + src: ArmVal::Imm(imm) + }] + }, RiscVInstruction::Add { width, dest, arg1, arg2, } => match width { - RiscVWidth::Word => ArmInstruction::Add { + RiscVWidth::Word => vec![ArmInstruction::Add { dest: ArmRegister { width: ArmWidth::Word, name: map_register_name(dest), @@ -86,10 +86,10 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { width: ArmWidth::Word, name: map_register_name(arg2), }), - }, + }], RiscVWidth::Double => sorry!(), }, - RiscVInstruction::SextW { dest, src } => ArmInstruction::Sxtw { + RiscVInstruction::SextW { dest, src } => vec![ArmInstruction::Sxtw { dest: ArmRegister { width: ArmWidth::Double, name: map_register_name(dest), @@ -98,21 +98,21 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { width: ArmWidth::Word, name: map_register_name(src), }, - }, - RiscVInstruction::Jr { target } => ArmInstruction::Blr { + }], + RiscVInstruction::Jr { target } => vec![ArmInstruction::Blr { target: map_register_name(target), - }, + }], RiscVInstruction::Li { dest, imm } => { if imm > 4095 || imm < 0 { panic!("Li with imm out of range"); } let width = RiscVWidth::Double; - ArmInstruction::Mov { + vec![ArmInstruction::Mov { width: map_width(&width), dest: map_register(dest, &width), src: ArmVal::Imm(imm), - } + }] // ArmInstruction::Add { // dest: map_register(dest, &RiscVWidth::Double), // arg1: ArmRegister { @@ -124,26 +124,44 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { }, RiscVInstruction::Addl { dest, src, label } => { let width = RiscVWidth::Double; - ArmInstruction::Add { + vec![ArmInstruction::Add { dest: map_register(dest, &width), arg1: map_register(src, &width), arg2: map_val(label, &width), - } + }] }, RiscVInstruction::Lui { dest, src } => { // only used to load upper bits or adrp in arm let width = RiscVWidth::Double; - ArmInstruction::Adrp { + vec![ArmInstruction::Adrp { dest: map_register(dest, &width), label: map_val(src, &width), - } + }] }, RiscVInstruction::Call { label } => { let width = RiscVWidth::Double; - ArmInstruction::Bl { + vec![ArmInstruction::Bl { target: map_val(label, &width), - } + }] + } + RiscVInstruction::ECall => { + let syscall_num_reg = ArmRegister{ + width: ArmWidth::Double, + name: ArmRegisterName::X8 + }; + vec![ + // ArmInstruction::Cmp(syscall_num_reg, ArmVal::Imm(RISCV_WRITE)), // if (x8 == RISCV_WRITE) { + // ArmInstruction::Bne("else"), + // ArmInstruction::Mov { width: ArmWidth::Double, dest: x8, src: ArmVal::Imm(SYS_WRITE) }, // x8 = ARM_WRITE; + // ArmInstruction::B("done"), + // ArmInstruction::Label("else"), // } else { + // ArmInstruction::Mov { width: ArmWidth::Double, dest: x8, src: ArmVal::Imm(__) }, // x8 = ARM_EXIT + // // } + // ArmInstruction::Label("done"), + ArmInstruction::Svc { id: 0 } + ] } + RiscVInstruction::Verbatim { text } => vec![ArmInstruction::Verbatim { text }] } } @@ -161,21 +179,30 @@ fn map_register_name(riscv_reg: RiscVRegister) -> ArmRegisterName { RiscVRegister::X0 => ArmRegisterName::Zero, RiscVRegister::RA => ArmRegisterName::Lr, RiscVRegister::SP => ArmRegisterName::Sp, - RiscVRegister::GP => ArmRegisterName::X0, - RiscVRegister::TP => ArmRegisterName::X1, - RiscVRegister::T0 => ArmRegisterName::X2, - RiscVRegister::T1 => ArmRegisterName::X3, - RiscVRegister::T2 => ArmRegisterName::X4, + RiscVRegister::GP => ArmRegisterName::X12, + RiscVRegister::TP => ArmRegisterName::X14, + RiscVRegister::T0 => ArmRegisterName::X9, + RiscVRegister::T1 => ArmRegisterName::X10, + RiscVRegister::T2 => ArmRegisterName::X11, // skipped X5 - RiscVRegister::S1 => ArmRegisterName::X6, - RiscVRegister::A0 => ArmRegisterName::X0, - RiscVRegister::A1 => ArmRegisterName::X1, - RiscVRegister::A2 => ArmRegisterName::X2, - RiscVRegister::A3 => ArmRegisterName::X3, - RiscVRegister::A4 => ArmRegisterName::X4, - RiscVRegister::A5 => ArmRegisterName::X5, - RiscVRegister::A6 => ArmRegisterName::X6, - RiscVRegister::A7 => ArmRegisterName::X7, +// RiscVRegister::S1 => ArmRegisterName::X6, +// RiscVRegister::A0 => ArmRegisterName::X0, +// RiscVRegister::A1 => ArmRegisterName::X1, +// RiscVRegister::A2 => ArmRegisterName::X2, +// RiscVRegister::A3 => ArmRegisterName::X3, +// RiscVRegister::A4 => ArmRegisterName::X4, +// RiscVRegister::A5 => ArmRegisterName::X5, +// RiscVRegister::A6 => ArmRegisterName::X6, +// RiscVRegister::A7 => ArmRegisterName::X7, + RiscVRegister::S1 => ArmRegisterName::X13, + RiscVRegister::A0 => ArmRegisterName::X0, // return value/syscall arg 0 + RiscVRegister::A1 => ArmRegisterName::X1, // syscall arg 1 + RiscVRegister::A2 => ArmRegisterName::X2, // syscall arg 2 + RiscVRegister::A3 => ArmRegisterName::X3, // syscall arg 3 + RiscVRegister::A4 => ArmRegisterName::X4, // syscall arg 4 + RiscVRegister::A5 => ArmRegisterName::X5, // syscall arg 5 + RiscVRegister::A6 => ArmRegisterName::X6, // syscall arg 6 + RiscVRegister::A7 => ArmRegisterName::X8, // syscall number RiscVRegister::S2 => ArmRegisterName::X15, RiscVRegister::S3 => ArmRegisterName::X16, RiscVRegister::S4 => ArmRegisterName::X17, @@ -216,8 +243,10 @@ fn map_width(riscv_width: &RiscVWidth) -> ArmWidth { pub fn translate_instrs(riscv_instrs: Vec) -> Vec { riscv_instrs .into_iter() - .map(|instr| translate(instr)) - .collect::>() + .map(translate).fold(vec![], |mut acc, x|{ + acc.extend(x); + acc + }) } /// Runs binary translation diff --git a/src/utils.rs b/src/utils.rs index b3f8c9e..e1fe8f8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,7 +2,7 @@ use std::fs; use crate::{instruction::RiscVInstruction, translate::translate_instrs}; -const start: &str = r#" +pub const START: &str = r#" .text .global _start @@ -15,9 +15,10 @@ svc #0 main: "#; + pub fn translate_to_file(instrs: Vec, path: String) { let arm_instrs = translate_instrs(instrs); - let mut contents = String::from(start); + let mut contents = String::new(); for instr in arm_instrs { let x: String = instr.into(); contents.push_str(&x); diff --git a/test_binary_translate_add.S b/test_binary_translate_add.S index 100bfc8..e18b534 100644 --- a/test_binary_translate_add.S +++ b/test_binary_translate_add.S @@ -1,18 +1,29 @@ -sub sp, sp, -32 + +.text + +.global _start + +_start: +bl main +mov x8, #93 +svc #0 + +main: +sub sp, sp, 32 str lr, [sp, 24] -str x5, [sp, 16] -add w5, sp, 32 -add x12, xzr, 3 -str w12, [w5, -20] -add x12, xzr, 4 -str w12, [w5, -24] -ldr w12, [w5, -20] -add x11, x12, 0 -ldr w12, [w5, -24] -add w12, w11, w12 -sxtw x12, w12 -add x7, x12, 0 +str x29, [sp, 16] +add x29, sp, 32 +mov x5, 3 +str w5, [x29, -20] +mov x5, 4 +str w5, [x29, -24] +ldr w5, [x29, -20] +add x4, x5, 0 +ldr w5, [x29, -24] +add w5, w4, w5 +sxtw x5, w5 +add x0, x5, 0 ldr lr, [sp, 24] -ldr x5, [sp, 16] +ldr x29, [sp, 16] add sp, sp, 32 blr lr diff --git a/tests/binaries/patched_binary_translate_add.S b/tests/binaries/patched_binary_translate_add.S index a9468a9..f791d64 100644 --- a/tests/binaries/patched_binary_translate_add.S +++ b/tests/binaries/patched_binary_translate_add.S @@ -25,5 +25,5 @@ add x0, x12, 0 ldr lr, [sp, 24] ldr fp, [sp, 16] add sp, sp, 32 -ret +blr lr diff --git a/tests/binaries/riscv/flake.lock b/tests/binaries/riscv/flake.lock new file mode 100644 index 0000000..eeec239 --- /dev/null +++ b/tests/binaries/riscv/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1741600792, + "narHash": "sha256-yfDy6chHcM7pXpMF4wycuuV+ILSTG486Z/vLx/Bdi6Y=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "ebe2788eafd539477f83775ef93c3c7e244421d3", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/tests/binaries/riscv/flake.nix b/tests/binaries/riscv/flake.nix new file mode 100644 index 0000000..3a391c7 --- /dev/null +++ b/tests/binaries/riscv/flake.nix @@ -0,0 +1,26 @@ +{ + description = "A very basic flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; + }; + + + outputs = { self, nixpkgs }: + let + pkgs = import nixpkgs { + # inherit system; + system = "x86_64-linux"; + crossSystem.config = "riscv64-linux-gnu"; + }; + in + { + devShells.x86_64-linux.default = pkgs.mkShell { + # Use the same mkShell as documented above + packages = with pkgs; [ + gcc + # pkgs.clang-tools + ]; + }; + }; +} diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 72e8f3e..c79f588 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -4,10 +4,12 @@ mod tests { use binary_room::translate::*; use binary_room::utils; use binary_room::utils::translate_to_file; + use binary_room::utils::START; #[test] fn test_binary_translate() { let riscv_asm: Vec = vec![ + RiscVInstruction::Verbatim { text: START.to_string() }, RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, @@ -175,7 +177,7 @@ mod tests { RiscVInstruction::Lui { dest: RiscVRegister::A5, src: RiscVVal::LabelOffset { - label: ".LC0".to_string(), + label: ".buf".to_string(), offset: 9998, // %hi riscv }, }, @@ -183,7 +185,7 @@ mod tests { dest: RiscVRegister::A2, src: RiscVRegister::A5, label: RiscVVal::LabelOffset { - label: ".LC0".to_string(), + label: ".buf".to_string(), offset: 9999, // %lo riscv, :lo12: arm }, }, From 6025db85199b3b5e20dd53a200239c5e94e12419 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 11 Mar 2025 17:45:20 -0700 Subject: [PATCH 23/27] print and echo tests --- tests/test_echo.rs | 40 ++++++++++++++++++++++++++++++++++++++++ tests/test_print.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/test_echo.rs create mode 100644 tests/test_print.rs diff --git a/tests/test_echo.rs b/tests/test_echo.rs new file mode 100644 index 0000000..46f37e1 --- /dev/null +++ b/tests/test_echo.rs @@ -0,0 +1,40 @@ +#[cfg(test)] +mod tests { + use binary_room::instruction::*; + use binary_room::translate::*; + use binary_room::utils; + use binary_room::utils::translate_to_file; + use binary_room::utils::START; + +const buf: &str = r#" +.buf: + .string "hello world" +"#; + + #[test] + fn test_print_translate() { + let riscv_asm: Vec = vec![ + // RiscVInstruction::Verbatim { text: buf.to_string() }, + RiscVInstruction::Verbatim { text: START.to_string() }, + // read syscall + RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: -32 }, // sub stack pointer + RiscVInstruction::Li { dest: RiscVRegister::A7, imm: 63 }, // read syscall # + RiscVInstruction::Li { dest: RiscVRegister::A2, imm: 32 }, // read 5 bytes + RiscVInstruction::Mv { dest: RiscVRegister::A1, src: RiscVRegister::SP }, + RiscVInstruction::Li { dest: RiscVRegister::A0, imm: 0 }, + RiscVInstruction::ECall, + // write syscall + RiscVInstruction::Li { dest: RiscVRegister::A7, imm: 64 }, + RiscVInstruction::Li { dest: RiscVRegister::A2, imm: 14 }, + RiscVInstruction::Mv { dest: RiscVRegister::A1, src: RiscVRegister::SP }, + RiscVInstruction::Li { dest: RiscVRegister::A0, imm: 1 }, + RiscVInstruction::ECall, + // exit syscall + RiscVInstruction::Li { dest: RiscVRegister::A7, imm: 93 }, + // RiscVInstruction::Li { dest: RiscVRegister::A0, imm: 0 }, + RiscVInstruction::ECall + ]; + + translate_to_file(riscv_asm, "test_echo.S".to_string()); + } +} diff --git a/tests/test_print.rs b/tests/test_print.rs new file mode 100644 index 0000000..e073b44 --- /dev/null +++ b/tests/test_print.rs @@ -0,0 +1,41 @@ +#[cfg(test)] +mod tests { + use binary_room::instruction::*; + use binary_room::translate::*; + use binary_room::utils; + use binary_room::utils::translate_to_file; + use binary_room::utils::START; + +const buf: &str = r#" +.buf: + .string "hello world\n" +"#; + + #[test] + fn test_print_translate() { + let riscv_asm: Vec = vec![ + RiscVInstruction::Verbatim { text: buf.to_string() }, + RiscVInstruction::Verbatim { text: START.to_string() }, + // write syscall + RiscVInstruction::Li { dest: RiscVRegister::A7, imm: 64 }, + RiscVInstruction::Li { dest: RiscVRegister::A2, imm: 14 }, + RiscVInstruction::Lui { dest: RiscVRegister::A0, src: RiscVVal::LabelOffset { label: ".buf".to_string(), offset: 9998 } }, + RiscVInstruction::Addl { + dest: RiscVRegister::A1, + src: RiscVRegister::A0, + label: RiscVVal::LabelOffset { + label: ".buf".to_string(), + offset: 9999 + } + }, + RiscVInstruction::Li { dest: RiscVRegister::A0, imm: 1 }, + RiscVInstruction::ECall, + // exit syscall + RiscVInstruction::Li { dest: RiscVRegister::A7, imm: 93 }, + // RiscVInstruction::Li { dest: RiscVRegister::A0, imm: 0 }, + RiscVInstruction::ECall + ]; + + translate_to_file(riscv_asm, "test_print.S".to_string()); + } +} From b6e409917a08ff53b89bd64c11fc686133ffad50 Mon Sep 17 00:00:00 2001 From: David Tran Date: Tue, 11 Mar 2025 18:54:29 -0700 Subject: [PATCH 24/27] basic control flow --- src/instruction.rs | 28 +++++++++++++++++++++++++--- src/translate.rs | 13 ++++++++++++- tests/test_translation.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index a347356..ee1a787 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -56,6 +56,13 @@ pub enum RiscVInstruction { arg1: RiscVRegister, arg2: RiscVRegister, }, + /// branch if less than or equal + #[strum(serialize = "call")] + Ble { + arg1: RiscVRegister, + arg2: RiscVRegister, + target: RiscVVal + }, /// call label #[strum(serialize = "call")] Call { @@ -113,6 +120,9 @@ pub enum RiscVInstruction { dest: RiscVRegister, src: RiscVRegister, }, + /// Jump label + #[strum(serialize = "j")] + J { target: RiscVVal }, /// Jump Register /// Jump to address and place return address in rd. /// jal rd,offset @@ -201,10 +211,13 @@ pub enum ArmInstruction { }, /// B Branch R15 := address #[strum(serialize = "b")] - B, + B { target: ArmVal }, /// BLR Xn #[strum(serialize = "blr")] Blr { target: ArmRegisterName }, + /// BLE label + #[strum(serialize = "ble")] + Ble { arg1: ArmRegister, arg2: ArmRegister, target: ArmVal }, /// BL label #[strum(serialize = "bl")] Bl {target: ArmVal}, @@ -250,7 +263,11 @@ pub enum ArmInstruction { impl Default for ArmInstruction { fn default() -> Self { - ArmInstruction::B + ArmInstruction::Mov { + width: ArmWidth::Double, + dest: ArmRegister { width: ArmWidth::Double, name: ArmRegisterName::X0 }, + src: ArmVal::Reg(ArmRegister { width: ArmWidth::Double, name: ArmRegisterName::X0 }) + } } } @@ -483,7 +500,12 @@ impl Into for ArmInstruction { ArmInstruction::Adrp { dest, label } => { format!("adrp {}, {}", dest, label) } - ArmInstruction::B => todo!(), + ArmInstruction::B { target } => { + format!("b {}", target) + }, + ArmInstruction::Ble { arg1, arg2, target } => { + format!("cmp {}, {}\n blt {}", arg1, arg2, target) + }, ArmInstruction::Blr { target } => { format!("blr {}", Into::::into(target)) }, diff --git a/src/translate.rs b/src/translate.rs index ad3e6ae..04e9126 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -35,7 +35,18 @@ pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { arg2: ArmVal::Imm(imm.abs()), } } - } + }, + RiscVInstruction::Ble { arg1, arg2, target } => { + let width = RiscVWidth::Double; + ArmInstruction::Ble { + arg1: map_register(arg1, &width), + arg2: map_register(arg2, &width), + target: map_val(target, &width) + } + }, + RiscVInstruction::J { target } => ArmInstruction::B { + target: map_val(target, &RiscVWidth::Double) + }, RiscVInstruction::S { width, src, dest } => ArmInstruction::Str { width: map_width(&width), src: map_register(src, &width), diff --git a/tests/test_translation.rs b/tests/test_translation.rs index 72e8f3e..b5044fa 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -229,4 +229,33 @@ mod tests { translate_to_file(riscv_asm, "test_binary_translate_write.S".to_string()); } + + #[test] + fn test_loop() { + let riscv_asm: Vec = vec![ + RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: -32 }, + RiscVInstruction::S { width: RiscVWidth::Double, src: RiscVRegister::S0FP, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: 24 } }, + RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: 32 }, + RiscVInstruction::S { width: RiscVWidth::Word, src: RiscVRegister::X0, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -20 } }, + RiscVInstruction::J { target: RiscVVal::LabelOffset { label: ".L2".to_string(), offset: 0 }}, + RiscVInstruction::Label { name: ".L3".to_string() }, + RiscVInstruction::L { width: RiscVWidth::Word, dest: RiscVRegister::A5, src: RiscVVal::Offset { register:RiscVRegister::S0FP, offset: -24 } }, + RiscVInstruction::Addi { dest: RiscVRegister::A5, src: RiscVRegister::A5, imm: 1 }, + RiscVInstruction::S { width: RiscVWidth::Word, src: RiscVRegister::A5, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -24 } }, + RiscVInstruction::L { width: RiscVWidth::Word, dest: RiscVRegister::A5, src: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -20 } }, + RiscVInstruction::Addi { dest: RiscVRegister::A5, src: RiscVRegister::A5, imm: 1 }, + RiscVInstruction::S { width: RiscVWidth::Word, src: RiscVRegister::A5, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -20 } }, + RiscVInstruction::Label { name: ".L2".to_string() }, + RiscVInstruction::L { width: RiscVWidth::Word, dest: RiscVRegister::A5, src: RiscVVal::Offset { register:RiscVRegister::S0FP, offset: -20 } }, + RiscVInstruction::SextW { dest: RiscVRegister::A4, src: RiscVRegister::A5 }, + RiscVInstruction::Li { dest:RiscVRegister::A5, imm: 4 }, + RiscVInstruction::Ble { arg1: RiscVRegister::A4, arg2: RiscVRegister::A5, target: RiscVVal::LabelOffset { label: ".L3".to_string(), offset: 0 } }, + RiscVInstruction::L { width: RiscVWidth::Word, dest: RiscVRegister::A5, src: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -24 } }, + RiscVInstruction::Mv { dest: RiscVRegister::A0, src: RiscVRegister::A5 }, + RiscVInstruction::L { width: RiscVWidth::Double, dest: RiscVRegister::S0FP, src: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: 24 } }, + RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: 32 }, + RiscVInstruction::Jr { target: RiscVRegister::RA }, + ]; + translate_to_file(riscv_asm, "test_binary_translate_loop.S".to_string()); + } } From 9e5f1176c98644227dd6b53b586d08807d3c29db Mon Sep 17 00:00:00 2001 From: David Tran Date: Tue, 11 Mar 2025 19:21:38 -0700 Subject: [PATCH 25/27] fix count to 5 test --- src/instruction.rs | 2 +- tests/test_translation.rs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 3f376e5..67d8789 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -543,7 +543,7 @@ impl Into for ArmInstruction { format!("b {}", target) }, ArmInstruction::Ble { arg1, arg2, target } => { - format!("cmp {}, {}\n blt {}", arg1, arg2, target) + format!("cmp {}, {}\nble {}", arg1, arg2, target) }, ArmInstruction::Blr { target } => { format!("blr {}", Into::::into(target)) diff --git a/tests/test_translation.rs b/tests/test_translation.rs index fbd1d3b..6780d8c 100644 --- a/tests/test_translation.rs +++ b/tests/test_translation.rs @@ -9,7 +9,6 @@ mod tests { #[test] fn test_binary_translate() { let riscv_asm: Vec = vec![ - RiscVInstruction::Verbatim { text: START.to_string() }, RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, @@ -177,7 +176,7 @@ mod tests { RiscVInstruction::Lui { dest: RiscVRegister::A5, src: RiscVVal::LabelOffset { - label: ".buf".to_string(), + label: ".LC0".to_string(), offset: 9998, // %hi riscv }, }, @@ -185,7 +184,7 @@ mod tests { dest: RiscVRegister::A2, src: RiscVRegister::A5, label: RiscVVal::LabelOffset { - label: ".buf".to_string(), + label: ".LC0".to_string(), offset: 9999, // %lo riscv, :lo12: arm }, }, @@ -235,9 +234,11 @@ mod tests { #[test] fn test_loop() { let riscv_asm: Vec = vec![ + RiscVInstruction::Verbatim { text: START.to_string() }, + RiscVInstruction::Label { name: "main".to_string() }, RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: -32 }, - RiscVInstruction::S { width: RiscVWidth::Double, src: RiscVRegister::S0FP, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: 24 } }, - RiscVInstruction::Addi { dest: RiscVRegister::SP, src: RiscVRegister::SP, imm: 32 }, + RiscVInstruction::S { width: RiscVWidth::Double, src: RiscVRegister::S0FP, dest: RiscVVal::Offset { register: RiscVRegister::SP, offset: 24 } }, + RiscVInstruction::Addi { dest: RiscVRegister::S0FP, src: RiscVRegister::SP, imm: 32 }, RiscVInstruction::S { width: RiscVWidth::Word, src: RiscVRegister::X0, dest: RiscVVal::Offset { register: RiscVRegister::S0FP, offset: -20 } }, RiscVInstruction::J { target: RiscVVal::LabelOffset { label: ".L2".to_string(), offset: 0 }}, RiscVInstruction::Label { name: ".L3".to_string() }, From 3036e69fa46611a83861a2f610f642953b96f263 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Tue, 11 Mar 2025 21:04:52 -0700 Subject: [PATCH 26/27] meta: add final documentation --- README.md | 10 ++++++++++ flake.nix | 3 +++ tests/binaries/jump.c | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/binaries/jump.c diff --git a/README.md b/README.md index 2ee8076..04db2aa 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # binary-room + Binary translator from RISC-V to ARM written in Rust + + +## Testing + +To get all the cross-compiling dependencies, enter the nix shell using `nix develop`. + +`cargo test -- --nocapture` + +Then run `./run.sh filename` to assemble and run the file. diff --git a/flake.nix b/flake.nix index b3a2d2b..cdc6e88 100644 --- a/flake.nix +++ b/flake.nix @@ -1,3 +1,5 @@ +# dual cross compile toolchain +# https://github.com/noteed/riscv-hello-asm/blob/main/shell.nix { description = "binary-room"; @@ -36,6 +38,7 @@ packages = with pkgs; [ rust-analyzer-nightly clang-tools + hyperfine # benchmarking tool ]; }; } diff --git a/tests/binaries/jump.c b/tests/binaries/jump.c new file mode 100644 index 0000000..d5f3e73 --- /dev/null +++ b/tests/binaries/jump.c @@ -0,0 +1,17 @@ +#include + +void fn(void){} +void fn2(void){} + +int main(int x) { + if (x == 5) { + fn(); + } else { + fn2(); + } + printf("hello there"); + + return 0; +} + + From cf287156c962b234e3ca99c9145a0774ff6dce90 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 11 Mar 2025 21:08:37 -0700 Subject: [PATCH 27/27] tests badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 04db2aa..e14c446 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # binary-room +[![Tests](https://github.com/Samir-Rashid/binary-room/actions/workflows/cargo_test.yml/badge.svg)](https://github.com/Samir-Rashid/binary-room/actions/workflows/cargo_test.yml) + Binary translator from RISC-V to ARM written in Rust