Skip to main content

Crate rvtime

Crate rvtime 

Source
Expand description

A RISC-V compiler with a wasmtime-like interface.

Load a statically linked RV64IMAC ELF, compile it to native code with Cranelift, call its exported functions from Rust, and let it call back.

use rvtime::{Caller, Config, Engine, Linker, Module, Store};

let engine = Engine::new(&Config::default())?;
let module = Module::from_file(&engine, "guest.elf")?;

let mut store = Store::new(&engine, 0u64);
let mut linker = Linker::new(&engine);

// The guest reaches this with `ecall` and `a7 == 1`.
linker.func_wrap(1, |mut caller: Caller<'_, u64>, a: u64, b: u64| {
    *caller.data_mut() += 1;
    Ok(a + b)
})?;

let instance = linker.instantiate(&mut store, &module)?;
let add = instance.get_typed_func::<(u64, u64), u64>("op_add")?;
assert_eq!(add.call(&mut store, (10, 3))?, 13);

§How this differs from wasmtime

  • Host functions are keyed by number, not name. A guest calls them with ecall, taking the number from a7. An ELF has no symbolic import table to resolve names against.
  • A store holds one instance. A program image is one address space and one register file; there is nothing to gain from sharing a store.
  • Signatures are not checked. Arguments are plain 64-bit words in a0..a7, so the type parameters on get_typed_func choose how many registers to use rather than describing something the guest declared.

§Guest memory

Each store reserves a guest address space of Config::memory_size bytes — 64 MiB by default. The reservation is lazy, so an unused tail costs address space rather than resident memory, but it is still per-store address space, which matters when many guests run at once.

The size must be a power of two. Guest addresses are confined by masking with memory_size - 1, which is what keeps a program inside its own memory; any other size would leave part of the mask’s range pointing past the reservation. The mask is compiled into the code, so a Module is tied to the size its Engine was configured with, and a Store always maps at the module’s size.

One consequence worth knowing: confinement is not a precise bounds check. An address past the end of the space wraps and may land on a mapped page rather than faulting. The guest still cannot reach anything outside its own memory.

The space is laid out as:

[ image ][ heap ][ guard ]        ...        [ stack ]
0                                                size

The heap is committed read-write and zeroed, and is what a guest allocator manages. rvtime does not carve it up or hand it to the guest: read the bounds with Store::heap and pass them in however your host interface prefers — a host function you register, or arguments to an init export. Committing it costs address space rather than memory, since pages are faulted in only when touched.

§Guest requirements

The image must be a statically linked RV64IMAC ELF linked with --emit-relocs. The relocations are what identify which functions have their address taken, and therefore where an indirect call may legally land. Without them a computed jump has no way to be checked.

Structs§

Caller
A host function’s view of the guest that called it.
Config
How an Engine behaves.
Engine
A compilation target and the configuration it was built with.
Instance
A module instantiated into a store.
Interrupt
Stops a running guest.
Linker
Defines the host functions a guest can call.
Module
A compiled RISC-V program.
Reg
Guest registers, re-exported for host functions that work on them directly. A RISC-V general-purpose register, x0..x31.
Store
Owns the guest’s memory, registers, and the embedder’s own data.
TypedFunc
An exported guest function with a Rust signature.

Enums§

OptLevel
How hard Cranelift should work.
Strategy
When functions get compiled.
Trap
Why a guest stopped short.

Traits§

IntoHostFunc
Converts a closure into a HostFn by reading its arguments out of the argument registers and writing its results back.
Regs
A value or tuple carried in the argument registers.

Type Aliases§

HostFn
A host function, erased down to the register file it operates on.