nub_linker/lib.rs
1//! RISC-V ELF → PVM2 linker.
2//!
3//! Converts a linked RV64EMC (+Zbb/Zba/Zbs/Zicond/Zicclsm/custom-0) ELF
4//! — as produced by the `riscv64emc-pvm2` target — into a
5//! [`nub_program::ProgramBlob`] the interpreter and recompiler can run
6//! directly.
7//!
8//! This is ISA work, not policy work: section concatenation, AUIPC-pair
9//! resolution, ecall-marker rewriting, fallthrough injection and PVM2
10//! validation. Nothing here knows about capabilities, cnodes or content
11//! hashing. A personality that wants those wraps the emitted blob —
12//! `javm-transpiler` does exactly that to produce a cap `Image`.
13//!
14//! ```no_run
15//! let elf = std::fs::read("guest.elf").unwrap();
16//! let blob = nub_linker::link_elf(&elf).unwrap();
17//! std::fs::write("guest.nubp", blob.to_bytes()).unwrap();
18//! ```
19
20pub mod elf;
21mod link;
22
23pub use link::link_elf;
24
25use thiserror::Error;
26
27/// Why an ELF could not be linked into a [`nub_program::ProgramBlob`].
28#[derive(Error, Debug)]
29pub enum LinkError {
30 #[error("ELF parse error: {0}")]
31 ElfParse(String),
32 #[error("unsupported RISC-V instruction at offset {offset:#x}: {detail}")]
33 UnsupportedInstruction { offset: usize, detail: String },
34 #[error("unsupported relocation: {0}")]
35 UnsupportedRelocation(String),
36 #[error("register mapping error: RISC-V register {0} has no PVM equivalent")]
37 RegisterMapping(u8),
38 #[error("code too large: {0} bytes")]
39 CodeTooLarge(usize),
40 #[error("invalid section: {0}")]
41 InvalidSection(String),
42 /// The linked result violates a [`nub_program::ProgramBlob`]
43 /// invariant — code overlapping `DATA_BASE`, data past the 4 GiB
44 /// guest range, or a program with no endpoints.
45 #[error("invalid program: {0}")]
46 InvalidProgram(#[from] nub_program::InvalidProgram),
47}