object_lang/lib.rs
1//! # object-lang
2//!
3//! Writes and reads the files operating systems run. A format-neutral [`Object`] —
4//! sections, symbols, relocations, and for executables an entry point — goes in, and
5//! ELF64 bytes for x86-64 or AArch64 come out: relocatable objects a linker can
6//! consume, or static executables the kernel loads directly, with no system linker or
7//! assembler involved. Reading turns ELF bytes back into the same model, strictly and
8//! within budgets, without panicking on any input.
9//!
10//! ## Quick start
11//!
12//! A static Linux x86-64 program that exits with status 42, from hand-assembled bytes:
13//!
14//! ```
15//! use object_lang::Architecture;
16//!
17//! let code = [
18//! 0xbf, 0x2a, 0x00, 0x00, 0x00, // mov edi, 42
19//! 0xb8, 0x3c, 0x00, 0x00, 0x00, // mov eax, 60 (exit)
20//! 0x0f, 0x05, // syscall
21//! ];
22//! let program = object_lang::elf::executable(Architecture::X86_64, &code)?;
23//! assert_eq!(&program[..4], b"\x7fELF");
24//! # Ok::<(), object_lang::WriteError>(())
25//! ```
26//!
27//! A relocatable object, written and read back:
28//!
29//! ```
30//! use object_lang::{
31//! Architecture, Object, Relocation, RelocationTarget, Section, SectionKind, Symbol,
32//! X86_64Reloc,
33//! };
34//!
35//! let mut obj = Object::relocatable(Architecture::X86_64);
36//! // main: call helper; ret
37//! let text = obj.add_section(
38//! Section::new(".text", SectionKind::Text)
39//! .with_align(16)
40//! .with_data(vec![0xe8, 0, 0, 0, 0, 0xc3]),
41//! );
42//! obj.add_symbol(Symbol::function("main", text, 0, 6));
43//! let helper = obj.add_symbol(Symbol::undefined("helper"));
44//! obj.add_relocation(
45//! text,
46//! Relocation::new(1, X86_64Reloc::Plt32, RelocationTarget::Symbol(helper), -4),
47//! )?;
48//!
49//! let bytes = object_lang::elf::write(&obj)?;
50//! assert_eq!(object_lang::elf::read(&bytes)?, obj);
51//! # Ok::<(), Box<dyn std::error::Error>>(())
52//! ```
53//!
54//! ## The model
55//!
56//! - An [`Object`] is a [`FileKind`] (relocatable or executable), an [`Architecture`],
57//! [`Section`]s, [`Symbol`]s, and an entry point.
58//! - A [`Section`] has a [`SectionKind`], [`SectionFlags`], an alignment, an address,
59//! and either bytes or (for BSS) a size, plus the [`Relocation`]s that patch it.
60//! - A [`Relocation`] patches `offset` with a [`RelocationKind`] computed from a
61//! [`RelocationTarget`] (a symbol or a section) and an explicit addend.
62//! - [`Object::validate`] checks every rule; writers run it first and readers run it on
63//! what they read, so errors are values ([`ModelError`], [`WriteError`],
64//! [`ReadError`]), never malformed files.
65//!
66//! Nothing in the model is ELF-specific: kinds are named for what they mean, not for
67//! one format's numbering, so COFF/PE and Mach-O writers fit the same model.
68//!
69//! ## Features
70//!
71//! - `std` (default): nothing beyond `alloc` is used; without it the crate is
72//! `no_std` and the API is identical.
73
74#![cfg_attr(not(feature = "std"), no_std)]
75#![cfg_attr(docsrs, feature(doc_cfg))]
76#![forbid(unsafe_code)]
77#![deny(
78 warnings,
79 missing_docs,
80 unsafe_op_in_unsafe_fn,
81 unused_must_use,
82 unused_results,
83 clippy::unwrap_used,
84 clippy::expect_used,
85 clippy::panic,
86 clippy::todo,
87 clippy::unimplemented,
88 clippy::unreachable,
89 clippy::dbg_macro,
90 clippy::print_stdout,
91 clippy::print_stderr,
92 clippy::undocumented_unsafe_blocks
93)]
94
95extern crate alloc;
96
97pub mod elf;
98mod error;
99mod limits;
100mod model;
101mod reloc;
102mod section;
103mod symbol;
104mod validate;
105
106pub use error::{
107 ModelError, ReadError, RelocationProblem, SectionProblem, SymbolProblem, WriteError,
108};
109pub use limits::Limits;
110pub use model::{Architecture, FileKind, Object, SectionId, SymbolId};
111pub use reloc::{Aarch64Reloc, Relocation, RelocationKind, RelocationTarget, X86_64Reloc};
112pub use section::{Section, SectionFlags, SectionKind};
113pub use symbol::{Binding, Symbol, SymbolKind, SymbolSection, Visibility};
114
115/// Compiles and runs the `rust` code blocks in `README.md` and `docs/API.md` as
116/// part of `cargo test`, so the published examples cannot drift from the API.
117///
118/// Present only while collecting doctests (`#[cfg(doctest)]`); it is not part of
119/// the public surface and does not appear in the built library or its docs.
120#[cfg(doctest)]
121#[doc = include_str!("../README.md")]
122#[doc = include_str!("../docs/API.md")]
123pub struct MarkdownDocTests;