asm-rs
A pure Rust multi-architecture assembly engine for offensive security.
๐ Documentation ยท ๐ API Reference ยท ๐ฆ Crate
Zero
unsafe,no_std-compatible, designed for embedding in exploit compilers, JIT engines, security tools, and shellcode generators.
โจ Features
- ๐ฆ Pure Rust โ
#![forbid(unsafe_code)], no C dependencies - ๐ฆ
no_stdsupport โ embedded and WASM environments (withalloc) - ๐๏ธ Multi-architecture โ x86, x86-64, ARM32, Thumb/Thumb-2, AArch64, RISC-V
- ๐ Intel, AT&T & UAL syntax โ GAS-compatible AT&T via
.syntax att, plus UAL#immediateand@///comments for ARM/Thumb/AArch64 - ๐ท๏ธ Labels & constants โ forward/backward references, numeric labels,
.equ/.set - ๐ Branch relaxation โ Szymanski's algorithm for optimal branch encoding
- ๐ Preprocessor โ
.macro/.rept/.irp/.if/.ifdefdirectives - โก Peephole optimizer โ MOV narrowing and REX elimination by default, all semantics-preserving; FLAGS-clobbering rewrites are opt-in
- ๐ก๏ธ Bounded by construction โ configurable limits on statements, labels, output size, recursion and macro expansion for untrusted input
- ๐ง Compile-time macros โ
asm_bytes!/asm_array!for zero-overhead assembly - ๐ฏ Literal pools โ
LDR Xn/Rn, =valuewith automatic pool management (AArch64/ARM32) - ๐ Listing output โ human-readable address/hex/source listing for debugging
- ๐ Applied relocations โ full relocation info exposed for tooling
- ๐งฌ Serde support โ optional serialization for all public types
๐๏ธ Supported Architectures
| Architecture | Variants | Highlights |
|---|---|---|
| x86 | 32-bit, 16-bit real mode | Full ISA, .code16/.code32 |
| x86-64 | 64-bit | SSEโSSE4.2, AVX/AVX2, AVX-512, AES-NI, BMI1/2, FMA3 |
| ARM32 | A32 (ARMv7) | Condition codes, barrel shifter, register ranges, literal pools |
| Thumb | T16/T32 | Auto 16/32-bit encoding, IT blocks, register ranges |
| AArch64 | A64 (ARMv8+) | NEON/AdvSIMD, LSE atomics, shifted/extended/unscaled operands, vector lanes, literal pools |
| RISC-V | RV32I, RV64I | M/A/C extensions, auto-compression |
๐ Quick Start
One-Shot Assembly
use ;
let bytes = assemble.unwrap;
assert_eq!; // mov eax, imm32
Builder API
use ;
let mut asm = new;
asm.emit.unwrap;
asm.emit.unwrap;
asm.emit.unwrap;
// ... function body ...
asm.emit.unwrap;
asm.emit.unwrap;
asm.emit.unwrap;
let result = asm.finish.unwrap;
println!;
AT&T / GAS Syntax
use ;
let mut asm = new;
asm.syntax;
asm.emit.unwrap;
ARM / AArch64 with UAL Syntax
use ;
// `#` is the immediate prefix for ARM/Thumb/AArch64 (as in GNU as and the
// Arm reference manuals); `@` and `//` start comments.
let bytes = assemble.unwrap;
// The prefix is optional โ these assemble identically.
assert_eq!;
// Barrel shifts and register extends are trailing operands, register lists
// accept ranges, and vector lanes are addressable.
assemble.unwrap;
assemble.unwrap;
assemble.unwrap;
assemble.unwrap;
assemble.unwrap;
Multi-Architecture Shellcode
use ;
// x86-64
let bytes = assemble.unwrap;
// AArch64
let mut asm = new;
asm.emit.unwrap;
// ARM32
let mut asm = new;
asm.emit.unwrap;
// RISC-V
let bytes = assemble.unwrap;
Compile-Time Assembly
use ;
const SHELLCODE: & = asm_bytes!;
const NOP: = asm_array!;
const ARM_CODE: & = asm_bytes!;
See
crates/asm-rs-macros/README.mdfor full proc-macro documentation.
๐งช Testing
Extensive test suite covering unit, integration, property-based (proptest), and fuzz testing (cargo-fuzz), with zero warnings.
Machine code is cross-validated against independent decoders rather than against itself โ iced-x86 for x86/x86-64, bad64 and yaxpeax-arm for AArch64/ARM/Thumb, riscv-decode for RISC-V โ at two levels:
- Encoding โ each instruction is assembled standalone and decoded back.
- Relocation โ branches to labels are swept across their full displacement range, including the sign boundary and the ends of each encoding, and the address the reference decoder computes is compared to the intended target. Relocation bugs are invisible near zero displacement, so only a sweep finds them.
- Differential fuzzing โ a fuzz target generates a branch to a known address and asks an independent decoder where it actually goes. Asserting "does not panic" cannot catch machine code that is well-formed but means the wrong thing; this can.
- Documentation โ every instruction in the reference pages is assembled by a test, so the docs cannot drift away from what the library supports.
โ๏ธ Configuration
Cargo Features
| Feature | Default | Description |
|---|---|---|
std |
โ | Standard library support |
x86 |
โ | x86 (32-bit) backend |
x86_64 |
โ | x86-64 backend |
arm |
โ | ARM32 + Thumb/Thumb-2 backend |
aarch64 |
โ | AArch64 backend |
riscv |
โ | RISC-V backend |
avx |
โ | AVX/AVX2/FMA |
avx512 |
โ | AVX-512/EVEX |
neon |
โ | AArch64 NEON/AdvSIMD |
sve |
โ | AArch64 SVE |
riscv_f |
โ | RISC-V F/D floating-point |
riscv_v |
โ | RISC-V V vector |
serde |
โ | Serialize/Deserialize for public types |
MSRV
Rust 1.75 or later.
๐ Learn More
For the full reference โ architecture details, ISA instruction tables, directives, API docs, and configuration options โ visit the documentation site.
๐ License
Licensed under either of:
at your option.