Skip to content

Commit 092ffea

Browse files
committed
Restore support for the wasm32-wasip2 target
This adjusts find_mir_or_eval_fn to respect #[wasm_import_module] on wasm. To avoid having to thread through the import module everywhere, I opted to merge it with the item name with a $$$ as separator. This is unlikely to occur in a real import module name or item name. This reverts commit c38128b and makes a few minor adjustments.
1 parent 3ab6735 commit 092ffea

File tree

9 files changed

+152
-2
lines changed

9 files changed

+152
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ degree documented below):
220220
- `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
221221
- `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite.
222222
- `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
223+
- `wasi`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
223224
- For targets on other operating systems, Miri might fail before even reaching the `main` function.
224225

225226
However, even for targets that we do support, the degree of support for accessing platform APIs

ci/ci.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ case $HOST_TARGET in
153153
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
154154
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
155155
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd
156+
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC hello wasm
156157
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
157158
TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
158159
;;

src/machine.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,23 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
12431243
// foreign function
12441244
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
12451245
let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
1246-
let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
1246+
1247+
let link_name = if ecx.tcx.sess.target.is_like_wasm
1248+
&& let Some(module) =
1249+
ecx.tcx.wasm_import_module_map(instance.def_id().krate).get(&instance.def_id())
1250+
{
1251+
// Adapted from https://github.com/rust-lang/rust/blob/90b65889799733f21ebdf59d96411aa531c5900a/compiler/rustc_codegen_llvm/src/attributes.rs#L549-L562
1252+
let codegen_fn_attrs = ecx.tcx.codegen_instance_attrs(instance.def);
1253+
let name = codegen_fn_attrs
1254+
.symbol_name
1255+
.unwrap_or_else(|| ecx.tcx.item_name(instance.def_id()));
1256+
// $$$ is unlikely to occur in either the import module name or item name, so use it
1257+
// as a separator here. It will be split again in emulate_foreign_item_inner for wasi.
1258+
Symbol::intern(&format!("{}$$${}", module, name))
1259+
} else {
1260+
Symbol::intern(ecx.tcx.symbol_name(instance).name)
1261+
};
1262+
12471263
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
12481264
}
12491265

src/shims/env.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<'tcx> EnvVars<'tcx> {
5151
} else if ecx.tcx.sess.target.os == "windows" {
5252
EnvVars::Windows(WindowsEnvVars::new(ecx, env_vars)?)
5353
} else {
54-
// For "none" targets (i.e., without an OS).
54+
// Used e.g. for wasi
5555
EnvVars::Uninit
5656
};
5757
ecx.machine.env_vars = env_vars;

src/shims/foreign_items.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
102102
let this = self.eval_context_ref();
103103
match this.tcx.sess.target.os.as_ref() {
104104
os if this.target_os_is_unix() => shims::unix::foreign_items::is_dyn_sym(name, os),
105+
"wasi" => shims::wasi::foreign_items::is_dyn_sym(name),
105106
"windows" => shims::windows::foreign_items::is_dyn_sym(name),
106107
_ => false,
107108
}
@@ -845,6 +846,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
845846
shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
846847
this, link_name, abi, args, dest,
847848
),
849+
"wasi" =>
850+
shims::wasi::foreign_items::EvalContextExt::emulate_foreign_item_inner(
851+
this, link_name, abi, args, dest,
852+
),
848853
"windows" =>
849854
shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
850855
this, link_name, abi, args, dest,

src/shims/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod math;
88
#[cfg(all(unix, feature = "native-lib"))]
99
mod native_lib;
1010
mod unix;
11+
mod wasi;
1112
mod windows;
1213
mod x86;
1314

src/shims/tls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ impl<'tcx> TlsDtorsState<'tcx> {
253253
}
254254
_ => {
255255
// No TLS dtor support.
256+
// FIXME: should we do something on wasi?
256257
break 'new_state Done;
257258
}
258259
}

src/shims/wasi/foreign_items.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use rustc_abi::CanonAbi;
2+
use rustc_middle::ty::Ty;
3+
use rustc_span::Symbol;
4+
use rustc_target::callconv::FnAbi;
5+
6+
use crate::shims::alloc::EvalContextExt as _;
7+
use crate::*;
8+
9+
pub fn is_dyn_sym(_name: &str) -> bool {
10+
false
11+
}
12+
13+
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
14+
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
15+
fn emulate_foreign_item_inner(
16+
&mut self,
17+
link_name: Symbol,
18+
abi: &FnAbi<'tcx, Ty<'tcx>>,
19+
args: &[OpTy<'tcx>],
20+
dest: &MPlaceTy<'tcx>,
21+
) -> InterpResult<'tcx, EmulateItemResult> {
22+
let this = self.eval_context_mut();
23+
24+
let (interface, name) = if let Some((module, name)) = link_name.as_str().split_once("$$$") {
25+
// According to the component model, the version should be matched as semver, but for
26+
// simplicity we strip the version entirely for now. Once we support wasm-wasip3 it may
27+
// become actually important to match on the version, but for now it shouldn't matter.
28+
let (module, _version) = module
29+
.split_once('@')
30+
.ok_or_else(|| err_unsup_format!("module name {module} must contain a version"))?;
31+
(Some(module), name)
32+
} else {
33+
// This item is provided by wasi-libc, not imported from the wasi runtime
34+
(None, link_name.as_str())
35+
};
36+
37+
match (interface, name) {
38+
// Allocation
39+
(None, "posix_memalign") => {
40+
let [memptr, align, size] =
41+
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
42+
let result = this.posix_memalign(memptr, align, size)?;
43+
this.write_scalar(result, dest)?;
44+
}
45+
(None, "aligned_alloc") => {
46+
let [align, size] =
47+
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
48+
let res = this.aligned_alloc(align, size)?;
49+
this.write_pointer(res, dest)?;
50+
}
51+
52+
// Standard input/output
53+
// FIXME: These shims are hacks that just get basic stdout/stderr working. We can't
54+
// constrain them to "std" since std itself uses the wasi crate for this.
55+
(Some("wasi:cli/stdout"), "get-stdout") => {
56+
let [] =
57+
this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?;
58+
this.write_scalar(Scalar::from_i32(1), dest)?; // POSIX FD number for stdout
59+
}
60+
(Some("wasi:cli/stderr"), "get-stderr") => {
61+
let [] =
62+
this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?;
63+
this.write_scalar(Scalar::from_i32(2), dest)?; // POSIX FD number for stderr
64+
}
65+
(Some("wasi:io/streams"), "[resource-drop]output-stream") => {
66+
let [handle] =
67+
this.check_shim_sig(shim_sig!(extern "C" fn(i32) -> ()), link_name, abi, args)?;
68+
let handle = this.read_scalar(handle)?.to_i32()?;
69+
70+
if !(handle == 1 || handle == 2) {
71+
throw_unsup_format!("wasm output-stream: unsupported handle");
72+
}
73+
// We don't actually close these FDs, so this is a NOP.
74+
}
75+
(Some("wasi:io/streams"), "[method]output-stream.blocking-write-and-flush") => {
76+
let [handle, buf, len, ret_area] = this.check_shim_sig(
77+
shim_sig!(extern "C" fn(i32, *mut _, usize, *mut _) -> ()),
78+
link_name,
79+
abi,
80+
args,
81+
)?;
82+
let handle = this.read_scalar(handle)?.to_i32()?;
83+
let buf = this.read_pointer(buf)?;
84+
let len = this.read_target_usize(len)?;
85+
let ret_area = this.read_pointer(ret_area)?;
86+
87+
if len > 4096 {
88+
throw_unsup_format!(
89+
"wasm output-stream.blocking-write-and-flush: buffer too big"
90+
);
91+
}
92+
let len = usize::try_from(len).unwrap();
93+
let Some(fd) = this.machine.fds.get(handle) else {
94+
throw_unsup_format!(
95+
"wasm output-stream.blocking-write-and-flush: unsupported handle"
96+
);
97+
};
98+
fd.write(
99+
this.machine.communicate(),
100+
buf,
101+
len,
102+
this,
103+
callback!(
104+
@capture<'tcx> {
105+
len: usize,
106+
ret_area: Pointer,
107+
}
108+
|this, result: Result<usize, IoError>| {
109+
if !matches!(result, Ok(l) if l == len) {
110+
throw_unsup_format!("wasm output-stream.blocking-write-and-flush: returning errors is not supported");
111+
}
112+
// 0 in the first byte of the ret_area indicates success.
113+
let ret = this.ptr_to_mplace(ret_area, this.machine.layouts.u8);
114+
this.write_null(&ret)?;
115+
interp_ok(())
116+
}),
117+
)?;
118+
}
119+
120+
_ => return interp_ok(EmulateItemResult::NotSupported),
121+
}
122+
interp_ok(EmulateItemResult::NeedsReturn)
123+
}
124+
}

src/shims/wasi/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod foreign_items;

0 commit comments

Comments
 (0)