asmkit/lib.rs
1//! # asmkit
2//!
3//! ### Overview
4//! asmkit is a portable assembler toolkit designed for decoding and encoding various assembly architectures. It aims to provide a small, efficient, and cross-platform library that can be used to build and manipulate assembly code without being tied to a specific platform or architecture. The library is written in Rust and supports several architectures including X64, RISC-V, and ARM (work-in-progress). Key features include:
5//! - **Multi-Architecture Support**: Supports multiple architectures such as X64, RISC-V, ARM (WIP), PPC (WIP), and plans to support PPC64 and OpenPOWER in the future.
6//! - **Minimal Dependencies**: Relies on a minimal set of dependencies to ensure portability and efficiency:
7//! - - `libc` and `intrusive-collections`` - For JIT support.
8//! - - `paste` and `derive-more` - Utility crates that simplify repetitive code.
9//! - - `smallvec` - A crate used to manage collections that avoid too frequent heap allocations during code generation.
10//!
11//! - **Code Relocations**: Provides a CodeBuffer interface to handle relocations, allowing the insertion of symbols into the API seamlessly.
12//! - **Auto-Generated Assemblers**: The goal is to support a wide range of platforms and provide auto-generated assemblers for as many architectures as possible.
13//! - **Portability**: Built to run on any platform, with the architecture-specific parts of the library being independent of the platform on which asmkit is built.
14//! #![no_std]
15//!
16//!
17//! ### Usage
18//!
19//! To use the library simply import a module for architecture you want to emit code for e.g `use asmkit::x86::*;`; This would
20//! include all the required code to generate code for platform.
21//!
22//! Example:
23//!
24//! ```rust
25//! use asmkit::core::buffer::CodeBuffer;
26//! use asmkit::core::jit_allocator::JitAllocator;
27//! use asmkit::x86::*;
28//!
29//! fn main() {
30//! let mut buf = CodeBuffer::new();
31//! let mut asm = Assembler::new(&mut buf);
32//!
33//! let dst = RDI;
34//! let arg0 = RSI;
35//! let arg1 = RDX;
36//!
37//! asm.sse_movdqurm(XMM0, ptr64(arg0, 0)); // load 4 ints from [arg0] to XMM0
38//! asm.sse_movdqurm(XMM1, ptr64(arg1, 0)); // load 4 ints from [arg1] to XMM1
39//! asm.sse_paddwrr(XMM0, XMM1); // add 4 ints
40//! asm.sse_movdqumr(ptr64(dst, 0), XMM0); // store result in [dst]
41//! asm.ret(); // return from function
42//!
43//! let result = buf.finish();
44//! let mut jit = JitAllocator::new(Default::default());
45//! // you can also use jit.alloc + jit.write manually.
46//! let span = result
47//! .allocate(&mut jit)
48//! .expect("failed to allocate JIT-code");
49//!
50//! // JIT Allocator uses dual-mapping: it allocates two pages which map to same physical space
51//! // and you write to executable code through `span.rw()` pointer while you can execute `span.rx()`.
52//! let f: extern "C" fn(*mut i32, *const i32, *const i32) = unsafe { std::mem::transmute(span.rx()) };
53//! #[cfg(all(unix, target_arch="x86_64"))] // can run only on x64 and on SystemV platforms.
54//! {
55//! let mut res = [0; 4];
56//! f(res.as_mut_ptr(), [4, 3, 2, 1].as_ptr(), [1, 5, 2, 8].as_ptr());
57//!
58//! println!("{:?}", res);
59//! }
60//! }
61
62//!```
63
64extern crate alloc;
65
66pub mod core;
67pub mod aarch64;
68pub mod ppc;
69pub mod riscv;
70pub mod util;
71pub mod x86;
72
73#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
74pub enum AsmError {
75 InvalidPrefix,
76 InvalidOperand,
77 InvalidInstruction,
78 OutOfMemory,
79 InvalidState,
80 TooManyHandles,
81 InvalidArgument,
82 FailedToOpenAnonymousMemory,
83 TooLarge,
84}