isa_lang/lib.rs
1//! # isa_lang
2//!
3//! Machine instructions to bytes and back, driven by target-description
4//! tables. Each instruction form is one row of data — an encoding recipe and
5//! an operand signature written as the architecture manual writes them — and
6//! one table-driven encoder, decoder, and Intel-syntax disassembler interpret
7//! the rows. Adding a form is adding a row.
8//!
9//! This release covers the x86-64 integer, control-flow, and memory core in
10//! [`x86_64`]. AArch64 follows in the same model (see the roadmap).
11//!
12//! ## Quick start
13//!
14//! ```
15//! use isa_lang::x86_64::{decode, encode, Inst, Mem, Mnemonic, Reg, Size};
16//!
17//! // mov rax, qword ptr [rdi+0x10]
18//! let load = Inst::new(Mnemonic::Mov, [Reg::RAX.into(), Mem::new(Size::Qword, Reg::RDI).with_disp(16).into()]);
19//! let bytes = encode(&load)?;
20//! assert_eq!(&*bytes, [0x48, 0x8B, 0x47, 0x10]);
21//!
22//! let decoded = decode(&bytes).unwrap();
23//! assert_eq!(decoded.inst(), load);
24//! assert_eq!(decoded.inst().to_string(), "mov rax, qword ptr [rdi+0x10]");
25//! # Ok::<(), isa_lang::x86_64::EncodeError>(())
26//! ```
27//!
28//! With labels:
29//!
30//! ```
31//! use isa_lang::x86_64::{Assembler, Cond, Inst, Mnemonic, Operand, Reg};
32//!
33//! let mut asm = Assembler::new();
34//! let positive = asm.label();
35//! asm.emit(&Inst::new(Mnemonic::Mov, [Reg::EAX.into(), Reg::EDI.into()]))?;
36//! asm.emit(&Inst::new(Mnemonic::Test, [Reg::EAX.into(), Reg::EAX.into()]))?;
37//! asm.jcc(Cond::Ns, positive)?;
38//! asm.emit(&Inst::new(Mnemonic::Neg, [Reg::EAX.into()]))?;
39//! asm.bind(positive)?;
40//! asm.emit(&Inst::new(Mnemonic::Ret, []))?;
41//! let code = asm.finish()?;
42//! assert_eq!(code.bytes(), [0x89, 0xF8, 0x85, 0xC0, 0x79, 0x02, 0xF7, 0xD8, 0xC3]);
43//! # Ok::<(), isa_lang::x86_64::AsmError>(())
44//! ```
45//!
46//! ## Guarantees
47//!
48//! - `decode(encode(i)) == i` for every instruction the encoder accepts,
49//! checked over every form's whole operand space.
50//! - Anything the decoder accepts, the encoder can encode back to the same
51//! instruction.
52//! - The decoder never panics, on any input, and every error names the byte
53//! at fault.
54//! - Encodings match the Intel SDM byte for byte (known-answer tests).
55//!
56//! ## Features
57//!
58//! - `std` (default): no effect today; the crate is `no_std` and needs only
59//! `alloc` (for [`x86_64::Assembler`]).
60
61#![cfg_attr(not(feature = "std"), no_std)]
62#![cfg_attr(docsrs, feature(doc_cfg))]
63#![forbid(unsafe_code)]
64#![deny(missing_docs)]
65#![deny(unused_must_use)]
66#![deny(unused_results)]
67#![deny(clippy::unwrap_used)]
68#![deny(clippy::expect_used)]
69#![deny(clippy::todo)]
70#![deny(clippy::unimplemented)]
71#![deny(clippy::print_stdout)]
72#![deny(clippy::print_stderr)]
73#![deny(clippy::dbg_macro)]
74#![deny(clippy::unreachable)]
75
76extern crate alloc;
77
78pub mod x86_64;
79
80/// Compiles and runs the `rust` code blocks in `README.md` and `docs/API.md` as
81/// part of `cargo test`, so the published examples cannot drift from the API.
82///
83/// Present only while collecting doctests (`#[cfg(doctest)]`); it is not part of
84/// the public surface and does not appear in the built library or its docs.
85#[cfg(doctest)]
86#[doc = include_str!("../README.md")]
87#[doc = include_str!("../docs/API.md")]
88pub struct MarkdownDocTests;