asm_rs/lib.rs
1//! # asm-rs — Pure Rust Multi-Architecture Assembly Engine
2//!
3//! `asm-rs` is a pure Rust, zero-C-dependency, multi-architecture runtime assembler
4//! that turns human-readable assembly text into machine-code bytes.
5//!
6//! ## Quick Start
7//!
8//! ```rust
9//! use asm_rs::{assemble, Arch};
10//!
11//! let code = assemble("nop", Arch::X86_64).unwrap();
12//! assert_eq!(code, vec![0x90]);
13//! ```
14//!
15//! ## Features
16//!
17//! - **Pure Rust** — no C/C++ FFI, no LLVM, no system assembler at runtime.
18//! - **Multi-arch** — x86, x86-64, ARM, AArch64, RISC-V (feature-gated).
19//! - **Runtime text parsing** — assemble from strings at runtime.
20//! - **`no_std` + `alloc`** — embeddable in firmware, kernels, WASM.
21//! - **Labels & branch relaxation** — automatic forward/backward label resolution.
22
23#![cfg_attr(not(feature = "std"), no_std)]
24#![forbid(unsafe_code)]
25// ── Pedantic lint policy ─────────────────────────────────────────────────
26// An assembler intentionally performs many narrowing / sign-changing casts
27// between integer widths (i128→u8, u8→u32, etc.) and uses dense hex literals
28// without separators (0xFFD0, 0x0F38F6). The lints below are expected and
29// acceptable in this context.
30#![allow(
31 clippy::cast_possible_truncation,
32 clippy::cast_sign_loss,
33 clippy::cast_lossless,
34 clippy::cast_possible_wrap,
35 clippy::unreadable_literal,
36 clippy::match_same_arms,
37 clippy::redundant_closure_for_method_calls,
38 clippy::bool_to_int_with_if,
39 clippy::wildcard_imports,
40 clippy::enum_glob_use,
41 clippy::needless_raw_string_hashes,
42 clippy::semicolon_if_nothing_returned,
43 clippy::must_use_candidate,
44 clippy::module_name_repetitions,
45 clippy::uninlined_format_args,
46 clippy::doc_markdown,
47 clippy::similar_names,
48 clippy::case_sensitive_file_extension_comparisons,
49 clippy::fn_params_excessive_bools,
50 clippy::too_many_lines,
51 clippy::single_match_else,
52 clippy::manual_let_else,
53 clippy::unnecessary_wraps,
54 clippy::unused_self,
55 clippy::map_unwrap_or,
56 clippy::many_single_char_names,
57 clippy::redundant_else,
58 clippy::return_self_not_must_use,
59 clippy::missing_errors_doc,
60 clippy::needless_continue
61)]
62
63extern crate alloc;
64
65#[cfg(feature = "aarch64")]
66pub(crate) mod aarch64;
67#[cfg(feature = "arm")]
68pub(crate) mod arm;
69/// Public assembler API — builder pattern, one-shot assembly, and `AssemblyResult`.
70pub mod assembler;
71/// x86-64 instruction encoder (REX, ModR/M, SIB, immediate, relocation).
72pub mod encoder;
73/// Error types and source-span diagnostics.
74pub mod error;
75/// Intermediate representation: registers, operands, instructions, directives.
76pub mod ir;
77/// Zero-copy lexer (tokenizer) with span tracking.
78pub mod lexer;
79/// Fragment-based linker: label resolution, branch relaxation, patching.
80pub mod linker;
81/// Peephole optimizations for instruction encoding.
82pub mod optimize;
83/// Intel-syntax parser producing IR statements.
84pub mod parser;
85/// Preprocessor: macros, repeat loops, and conditional assembly.
86pub mod preprocessor;
87#[cfg(feature = "riscv")]
88pub(crate) mod riscv;
89#[cfg(any(feature = "x86", feature = "x86_64"))]
90pub(crate) mod x86;
91
92// Re-exports
93pub use assembler::{Assembler, AssemblyResult, ResourceLimits};
94pub use encoder::RelocKind;
95pub use error::{ArchName, AsmError, Span};
96pub use ir::{
97 AddrMode, AlignDirective, Arch, BroadcastMode, ConstDef, DataDecl, DataSize, DataValue, Expr,
98 FillDirective, Instruction, MemoryOperand, Mnemonic, Operand, OperandList, OperandSize,
99 OptLevel, OrgDirective, Prefix, PrefixList, Register, SpaceDirective, Statement, SvePredQual,
100 Syntax, VectorArrangement, X86Mode,
101};
102pub use linker::AppliedRelocation;
103pub use preprocessor::Preprocessor;
104
105use alloc::vec::Vec;
106
107/// Assemble a string of assembly into machine code bytes.
108///
109/// Semicolons or newlines separate instructions.
110/// Labels are defined with a trailing colon: `loop:`
111///
112/// # Errors
113///
114/// Returns [`AsmError`] if the input contains syntax errors, unknown
115/// mnemonics, invalid operand combinations, undefined labels, or any
116/// other encoding issue.
117///
118/// # Examples
119///
120/// ```rust
121/// use asm_rs::{assemble, Arch};
122///
123/// let code = assemble("nop", Arch::X86_64).unwrap();
124/// assert_eq!(code, vec![0x90]);
125/// ```
126pub fn assemble(source: &str, arch: Arch) -> Result<Vec<u8>, AsmError> {
127 assemble_at(source, arch, 0)
128}
129
130/// Assemble with an explicit base virtual address.
131///
132/// # Errors
133///
134/// Returns [`AsmError`] on assembly failure (see [`assemble`] for details).
135///
136/// # Examples
137///
138/// ```rust
139/// use asm_rs::{assemble_at, Arch};
140///
141/// let code = assemble_at("nop", Arch::X86_64, 0x1000).unwrap();
142/// assert_eq!(code, vec![0x90]);
143/// ```
144pub fn assemble_at(source: &str, arch: Arch, base_addr: u64) -> Result<Vec<u8>, AsmError> {
145 let mut asm = Assembler::new(arch);
146 asm.base_address(base_addr);
147 asm.emit(source)?;
148 let result = asm.finish()?;
149 Ok(result.into_bytes())
150}
151
152/// Assemble with external labels pre-defined at known addresses.
153///
154/// # Errors
155///
156/// Returns [`AsmError`] on assembly failure (see [`assemble`] for details).
157///
158/// # Examples
159///
160/// ```rust
161/// use asm_rs::{assemble_with, Arch};
162///
163/// let code = assemble_with("nop", Arch::X86_64, 0x0, &[]).unwrap();
164/// assert_eq!(code, vec![0x90]);
165/// ```
166pub fn assemble_with(
167 source: &str,
168 arch: Arch,
169 base_addr: u64,
170 external_labels: &[(&str, u64)],
171) -> Result<Vec<u8>, AsmError> {
172 let mut asm = Assembler::new(arch);
173 asm.base_address(base_addr);
174 for &(name, addr) in external_labels {
175 asm.define_external(name, addr);
176 }
177 asm.emit(source)?;
178 let result = asm.finish()?;
179 Ok(result.into_bytes())
180}