#[path = "abi_metadata.rs"]
pub(super) mod abi_metadata;
pub(crate) fn leb(mut value: u32, output: &mut Vec<u8>) {
loop {
let mut byte = (value & 0x7f) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
output.push(byte);
if value == 0 {
return;
}
}
}
pub(crate) fn text(value: &str, output: &mut Vec<u8>) {
leb(value.len() as u32, output);
output.extend(value.as_bytes());
}
pub(crate) fn section(id: u8, contents: Vec<u8>, output: &mut Vec<u8>) {
output.push(id);
leb(contents.len() as u32, output);
output.extend(contents);
}
pub(crate) fn custom(name: &str, contents: &[u8], output: &mut Vec<u8>) {
let mut body = Vec::new();
text(name, &mut body);
body.extend(contents);
section(0, body, output);
}
pub(crate) fn threaded_root_wasm(
proc_exit: Option<i32>,
rejected: bool,
fault: bool,
loop_root: bool,
) -> Vec<u8> {
let mut wasm = b"\0asm\x01\0\0\0".to_vec();
let mut types = Vec::new();
leb(9, &mut types);
types.extend([
0x60, 0, 0, 0x60, 1, 0x7f, 1, 0x7f, 0x60, 3, 0x7f, 0x7e, 0x7f, 1, 0x7f, 0x60, 2, 0x7f,
0x7f, 1, 0x7f, 0x60, 4, 0x7f, 0x7f, 0x7f, 0x7f, 1, 0x7f, 0x60, 1, 0x7f, 0, 0x60, 0, 1,
0x7f, 0x60, 0, 1, 0x7f, 0x60, 2, 0x7f, 0x7f, 0,
]);
section(1, types, &mut wasm);
let mut imports = Vec::new();
leb(9, &mut imports);
text("env", &mut imports);
text("memory", &mut imports);
imports.extend([2, 3]);
leb(17, &mut imports);
leb(16_384, &mut imports);
text("kernal-api:v1", &mut imports);
text("kernel_yield", &mut imports);
imports.extend([0, 0]);
text("wasi", &mut imports);
text("thread-spawn", &mut imports);
imports.extend([0, 1]);
for (name, ty) in [
("clock_time_get", 2),
("environ_get", 3),
("environ_sizes_get", 3),
("fd_write", 4),
("proc_exit", 5),
("sched_yield", 6),
] {
text("wasi_snapshot_preview1", &mut imports);
text(name, &mut imports);
imports.push(0);
leb(ty, &mut imports);
}
section(2, imports, &mut wasm);
let mut functions = Vec::new();
leb(5, &mut functions);
for ty in [0, 7, 8, 7, 0] {
leb(ty, &mut functions);
}
section(3, functions, &mut wasm);
let mut exports = Vec::new();
leb(5, &mut exports);
text("memory", &mut exports);
exports.push(2);
leb(0, &mut exports);
for (name, index) in [
("_start", 8),
("__main_void", 9),
("wasi_thread_start", 10),
("kernal-api-run", 11),
] {
text(name, &mut exports);
exports.push(0);
leb(index, &mut exports);
}
section(7, exports, &mut wasm);
section(8, vec![12], &mut wasm);
let mut code = Vec::new();
leb(5, &mut code);
if rejected {
code.extend([
32, 0, 0x41, 0, 0x10, 1, 0x41, 0, 0x4a, 0x45, 0x04, 0x40, 0x41, 6, 0x10, 6, 0x0b, 0x41,
1, 0x10, 1, 0x41, 0x7f, 0x46, 0x45, 0x04, 0x40, 0x41, 7, 0x10, 6, 0x0b, 0x0b, 4, 0,
0x41, 0, 0x0b, 6, 0, 0x20, 1, 0x10, 6, 0x0b, 4, 0, 0x41, 0, 0x0b,
]);
} else if loop_root {
code.extend([
7, 0, 0x03, 0x40, 0x0c, 0, 0x0b, 0x0b, 4, 0, 0x41, 0, 0x0b, 2, 0, 0x0b, 4, 0, 0x41, 0,
0x0b,
]);
} else {
code.extend([
2, 0, 0x0b, 4, 0, 0x41, 0, 0x0b, 2, 0, 0x0b, 4, 0, 0x41, 0, 0x0b,
]);
}
if let Some(exit) = proc_exit {
code.extend([6, 0, 0x41, exit as u8, 0x10, 6, 0x0b]);
} else if rejected {
code.extend([2, 0, 0x0b]);
} else if fault {
code.extend([
32, 0, 0x41, 1, 0x41, 0x7f, 0x41, 1, 0x41, 0, 0x10, 5, 0x41, 21, 0x47, 0x04, 0x40,
0x00, 0x0b, 0x41, 0, 0xfe, 0x10, 2, 0, 0x41, 42, 0x47, 0x04, 0x40, 0x00, 0x0b, 0x0b,
]);
} else {
code.extend([2, 0, 0x0b]);
}
section(10, code, &mut wasm);
if fault {
section(11, vec![1, 0, 0x41, 0, 0x0b, 4, 42, 0, 0, 0], &mut wasm);
}
let mut features = Vec::new();
let names = [
"atomics",
"bulk-memory",
"bulk-memory-opt",
"call-indirect-overlong",
"extended-const",
"multivalue",
"mutable-globals",
"nontrapping-fptoint",
"reference-types",
"sign-ext",
];
leb(names.len() as u32, &mut features);
for name in names {
features.push(b'+');
text(name, &mut features);
}
custom("target_features", &features, &mut wasm);
custom("kernal-api.abi", abi_metadata::METADATA, &mut wasm);
wasm
}
#[allow(dead_code)] pub(crate) fn looping_root_wasm() -> Vec<u8> {
threaded_root_wasm(None, false, false, true)
}
#[allow(dead_code)] pub(crate) fn unreachable_root_wasm() -> Vec<u8> {
threaded_code_fixture([
vec![0, 0x00, 0x0b],
vec![0, 0x41, 0, 0x0b],
vec![0, 0x0b],
vec![0, 0x00, 0x0b],
vec![0, 0x0b],
])
}
#[allow(dead_code)] pub(crate) fn atomic_wait32_wasm() -> Vec<u8> {
threaded_code_fixture([
vec![
0, 0x10, 0, 0x41, 0, 0x41, 0, 0x42, 0x7f, 0xfe, 0x01, 0x02, 0, 0x1a, 0x0b,
],
vec![0, 0x41, 0, 0x0b],
vec![0, 0x0b],
vec![0, 0x41, 0, 0x0b],
vec![0, 0x0b],
])
}
#[allow(dead_code)] fn threaded_code_fixture(bodies: [Vec<u8>; 5]) -> Vec<u8> {
let bytes = threaded_root_wasm(None, false, false, false);
let mut section_offset = 8;
loop {
let id = bytes[section_offset];
let mut body_at = section_offset + 1;
let mut length = 0_usize;
let mut shift = 0;
loop {
let byte = bytes[body_at];
body_at += 1;
length |= usize::from(byte & 0x7f) << shift;
if byte & 0x80 == 0 {
break;
}
shift += 7;
}
let end = body_at + length;
if id == 10 {
let mut code = Vec::new();
leb(bodies.len() as u32, &mut code);
for body in bodies {
leb(body.len() as u32, &mut code);
code.extend(body);
}
let mut output = bytes[..section_offset].to_vec();
section(10, code, &mut output);
output.extend_from_slice(&bytes[end..]);
return output;
}
section_offset = end;
}
}