diff --git a/harm-runtime/src/lib.rs b/harm-runtime/src/lib.rs index 4af3596..b0acf60 100644 --- a/harm-runtime/src/lib.rs +++ b/harm-runtime/src/lib.rs @@ -5,5 +5,9 @@ pub mod builder; pub mod labels; +#[macro_use] +mod macros; pub mod memory; pub mod runtime; + +pub use self::runtime::{Assembler, AssemblerError}; diff --git a/harm-runtime/src/macros.rs b/harm-runtime/src/macros.rs new file mode 100644 index 0000000..ce07759 --- /dev/null +++ b/harm-runtime/src/macros.rs @@ -0,0 +1,55 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +/// A helper macro to append multiple instructions to the assembler, and return the first error if any of them fails. +#[macro_export] +macro_rules! harm { + ($asm:expr; $($inst:expr),*) => { + { + let asm = &mut $asm; + 'block: { + $( + if let Err(e) = asm.append($inst) { + break 'block Err(e); + } + )* + Ok(()) + } + } + }; + + ($asm:expr; $($inst:expr,)*) => { + harm!{ $asm; $($inst),* } + }; +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "memmap2")] + fn test_harm_macro() -> Result<(), Box> { + use crate::*; + use harm::{ + instructions::{dpimm::movz, logical::and}, + register::Reg64, + }; + + use crate::memory::MmapBuffer; + + let mem = MmapBuffer::allocate(16).unwrap(); + let mut asm = Assembler::new(mem); + + harm! { + asm; + movz(Reg64::X0, 0), + and(Reg64::X3, Reg64::X3, 8)? // instruction-level error. + } + .unwrap(); // memory buffer level error. + + asm.build::<_, ()>().unwrap(); + + Ok(()) + } +} diff --git a/harm-runtime/src/runtime.rs b/harm-runtime/src/runtime.rs index 0336d9f..44a8794 100644 --- a/harm-runtime/src/runtime.rs +++ b/harm-runtime/src/runtime.rs @@ -22,6 +22,7 @@ pub enum AssemblerError { #[error("executable memory error: {0}")] ExecutableMemory(EMErr), } + // N.B. we keep here internal relocation type, and convert it to external on serialization. #[derive(Default)] pub struct Assembler { @@ -167,11 +168,19 @@ mod tests { addend: 0, }; - asm.append(add(Reg64::X0, Reg64::X0, Reg64::X1)); - asm.append(b(finish_ref)); - asm.append(movz(Reg64::X0, 0)); + harm! { + asm; + add(Reg64::X0, Reg64::X0, Reg64::X1), + b(finish_ref), + movz(Reg64::X0, 0), + } + .unwrap(); asm.assign_forward_label(finish_label); - asm.append(ret()); + harm! { + asm; + ret() + } + .unwrap(); let (fm, _) = asm.build::().unwrap(); @@ -201,11 +210,19 @@ mod tests { }; let _start = asm.current_named_label("_start"); - asm.append(add(Reg64::X0, Reg64::X0, Reg64::X1)).unwrap(); - asm.append(b(finish_ref)).unwrap(); - asm.append(movz(Reg64::X0, 0)).unwrap(); + harm! { + asm; + add(Reg64::X0, Reg64::X0, Reg64::X1), + b(finish_ref), + movz(Reg64::X0, 0), + } + .unwrap(); asm.assign_forward_label(finish_label); - asm.append(ret()).unwrap(); + harm! { + asm; + ret() + } + .unwrap(); let (fm, labels) = asm.compile().unwrap(); let start_addr = labels.get("_start").cloned().unwrap() as usize;