diff --git a/Cargo.lock b/Cargo.lock index 56b9e38..3e625f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1630,6 +1630,7 @@ version = "0.4.0" dependencies = [ "anyhow", "structopt", + "wasm-encoder 0.38.1", "wasmparser 0.106.0", "wizer", ] diff --git a/crates/wasi-vfs-cli/Cargo.toml b/crates/wasi-vfs-cli/Cargo.toml index 7dd5b72..e2f397c 100644 --- a/crates/wasi-vfs-cli/Cargo.toml +++ b/crates/wasi-vfs-cli/Cargo.toml @@ -9,5 +9,6 @@ name = "wasi-vfs" [dependencies] anyhow = "1.0.40" structopt = "0.3.21" +wasm-encoder = "0.38.1" wasmparser = "0.106.0" wizer = { git = "https://github.com/bytecodealliance/wizer.git", rev = "v3.0.1" } diff --git a/crates/wasi-vfs-cli/src/lib.rs b/crates/wasi-vfs-cli/src/lib.rs index 97cdaea..2a8fc34 100644 --- a/crates/wasi-vfs-cli/src/lib.rs +++ b/crates/wasi-vfs-cli/src/lib.rs @@ -84,10 +84,18 @@ pub fn pack(wasm_bytes: &[u8], map_dirs: Vec<(PathBuf, PathBuf)>) -> Result bool { _ => continue, } } - false + return false; +} + +/// Copy an export entry to another name. +fn copy_export_entry(bytes: &[u8], source: &str, dest: &str) -> Result> { + let mut module = wasm_encoder::Module::new(); + + let parser = wasmparser::Parser::new(0); + + for payload in parser.parse_all(bytes) { + let payload = payload?; + match payload { + wasmparser::Payload::Version { .. } => continue, + wasmparser::Payload::ExportSection(export) => { + let mut section = wasm_encoder::ExportSection::new(); + for entry in export { + let entry = entry?; + section.export(entry.name, translate::export_kind(entry.kind), entry.index); + if entry.name == source { + section.export(dest, translate::export_kind(entry.kind), entry.index); + } + } + module.section(§ion); + } + wasmparser::Payload::End(_) => continue, + _ => { + if let Some((id, range)) = payload.as_section() { + let raw = wasm_encoder::RawSection { + id, + data: &bytes[range.start..range.end], + }; + module.section(&raw); + } + } + } + } + + Ok(module.finish()) +} + +mod translate { + pub(crate) fn export_kind(x: wasmparser::ExternalKind) -> wasm_encoder::ExportKind { + match x { + wasmparser::ExternalKind::Func => wasm_encoder::ExportKind::Func, + wasmparser::ExternalKind::Table => wasm_encoder::ExportKind::Table, + wasmparser::ExternalKind::Memory => wasm_encoder::ExportKind::Memory, + wasmparser::ExternalKind::Global => wasm_encoder::ExportKind::Global, + wasmparser::ExternalKind::Tag => wasm_encoder::ExportKind::Tag, + } + } } diff --git a/tests/run-make/pack-twice-reactor/Makefile b/tests/run-make/pack-twice-reactor/Makefile new file mode 100644 index 0000000..735fff1 --- /dev/null +++ b/tests/run-make/pack-twice-reactor/Makefile @@ -0,0 +1,18 @@ +-include ../tools.mk + +check: $(objs) + $(CC) $(LDFLAGS) main.c $(LIB_WASI_VFS) -mexec-model=reactor -o $(TMPDIR)/main.wasm + $(WASI_VFS_CLI) pack $(TMPDIR)/main.wasm --dir ./mnt0::/mnt0 -o $(TMPDIR)/main.stage0.wasm + $(NODE) --experimental-wasi-unstable-preview1 ./check.js $(TMPDIR)/main.stage0.wasm 0 + + $(WASI_VFS_CLI) pack $(TMPDIR)/main.stage0.wasm --dir ./mnt1::/mnt1 -o $(TMPDIR)/main.stage1.wasm + $(NODE) --experimental-wasi-unstable-preview1 ./check.js $(TMPDIR)/main.stage1.wasm 1 + + $(NODE) --experimental-wasi-unstable-preview1 ./check.js \ + --dir=./mnt0::/mnt0 --dir=./mnt1::/mnt1 --dir=./mnt1_1::/mnt1 \ + $(TMPDIR)/main.wasm 2 + $(WASI_VFS_CLI) pack $(TMPDIR)/main.stage1.wasm --dir ./mnt1_1::/mnt1 -o $(TMPDIR)/main.stage2.wasm + $(NODE) --experimental-wasi-unstable-preview1 ./check.js $(TMPDIR)/main.stage2.wasm 2 + +clean: + rm -rf $(TMPDIR)/* diff --git a/tests/run-make/pack-twice-reactor/check.js b/tests/run-make/pack-twice-reactor/check.js new file mode 100644 index 0000000..ce5925b --- /dev/null +++ b/tests/run-make/pack-twice-reactor/check.js @@ -0,0 +1,29 @@ +const { WASI } = require("wasi"); +const fs = require("fs"); +const process = require("process"); +const path = require("path"); + +const args = process.argv.slice(2); + +const preopens = {}; +while (args.length > 0 && args[0].startsWith("--dir=")) { + // Parse --dir=/foo::/bar + const dir = args.shift().substring("--dir=".length); + const [host, guest] = dir.split("::"); + preopens[guest] = host; +} + +const buffer = fs.readFileSync(args[0]); +const stage = Number(args[1]); + +const wasi = new WASI({ + env: { ...process.env }, + preopens +}); +const m = new WebAssembly.Module(buffer); +const i = new WebAssembly.Instance(m, { + wasi_snapshot_preview1: wasi.wasiImport, +}); + +wasi.initialize(i); +i.exports.check(stage); diff --git a/tests/run-make/pack-twice-reactor/main.c b/tests/run-make/pack-twice-reactor/main.c new file mode 100644 index 0000000..8fde674 --- /dev/null +++ b/tests/run-make/pack-twice-reactor/main.c @@ -0,0 +1,25 @@ +#include "../check.h" +#include + +#pragma clang diagnostic ignored "-Wunknown-attributes" +__attribute__((export_name("check"))) +int check(int stage) { + if (stage == 0) { + check_file_exists("/mnt0/hello.txt"); + } else if (stage == 1) { + check_file_exists("/mnt0/hello.txt"); + check_file_exists("/mnt1/goodbye.txt"); + } else if (stage == 2) { + check_file_exists("/mnt0/hello.txt"); + check_file_exists("/mnt1/x.txt"); + check_file_not_exists("/mnt1/goodbye.txt"); + } else { + fprintf(stderr, "Unknown stage: %d\n", stage); + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) { + return 1; +} diff --git a/tests/run-make/pack-twice-reactor/mnt0/hello.txt b/tests/run-make/pack-twice-reactor/mnt0/hello.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/run-make/pack-twice-reactor/mnt1/goodbye.txt b/tests/run-make/pack-twice-reactor/mnt1/goodbye.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/run-make/pack-twice-reactor/mnt1_1/x.txt b/tests/run-make/pack-twice-reactor/mnt1_1/x.txt new file mode 100644 index 0000000..e69de29