Skip to content

Commit bfeac6c

Browse files
committed
Initial support for new target "wasm32-wali-linux-musl" to support the Wasm Linux
Interface This commit does not patch libc, stdarch, or cc
1 parent 0d7b2fb commit bfeac6c

File tree

10 files changed

+241
-18
lines changed

10 files changed

+241
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//! This target is a confluence of Linux and Wasm models, inheriting most
2+
//! aspects from their respective base targets
3+
4+
use crate::spec::{
5+
crt_objects, add_link_args, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy,
6+
RelocModel, TargetOptions, TlsModel,
7+
};
8+
9+
pub fn opts() -> TargetOptions {
10+
macro_rules! args {
11+
($prefix:literal) => {
12+
&[
13+
// By default LLD only gives us one page of stack (64k) which is a
14+
// little small. Default to a larger stack closer to other PC platforms
15+
// (1MB) and users can always inject their own link-args to override this.
16+
concat!($prefix, "-z"),
17+
concat!($prefix, "stack-size=1048576"),
18+
// By default LLD's memory layout is:
19+
//
20+
// 1. First, a blank page
21+
// 2. Next, all static data
22+
// 3. Finally, the main stack (which grows down)
23+
//
24+
// This has the unfortunate consequence that on stack overflows you
25+
// corrupt static data and can cause some exceedingly weird bugs. To
26+
// help detect this a little sooner we instead request that the stack is
27+
// placed before static data.
28+
//
29+
// This means that we'll generate slightly larger binaries as references
30+
// to static data will take more bytes in the ULEB128 encoding, but
31+
// stack overflow will be guaranteed to trap as it underflows instead of
32+
// corrupting static data.
33+
concat!($prefix, "--stack-first"),
34+
// FIXME we probably shouldn't pass this but instead pass an explicit list
35+
// of symbols we'll allow to be undefined. We don't currently have a
36+
// mechanism of knowing, however, which symbols are intended to be imported
37+
// from the environment and which are intended to be imported from other
38+
// objects linked elsewhere. This is a coarse approximation but is sure to
39+
// hide some bugs and frustrate someone at some point, so we should ideally
40+
// work towards a world where we can explicitly list symbols that are
41+
// supposed to be imported and have all other symbols generate errors if
42+
// they remain undefined.
43+
concat!($prefix, "--allow-undefined"),
44+
// LLD only implements C++-like demangling, which doesn't match our own
45+
// mangling scheme. Tell LLD to not demangle anything and leave it up to
46+
// us to demangle these symbols later. Currently rustc does not perform
47+
// further demangling, but tools like twiggy and wasm-bindgen are intended
48+
// to do so.
49+
concat!($prefix, "--no-demangle"),
50+
]
51+
};
52+
}
53+
54+
let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
55+
add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
56+
57+
TargetOptions {
58+
is_like_wasm: true,
59+
families: cvs!["wasm", "unix"],
60+
os: "linux".into(),
61+
env: "musl".into(),
62+
63+
// we allow dynamic linking, but only cdylibs. Basically we allow a
64+
// final library artifact that exports some symbols (a wasm module) but
65+
// we don't allow intermediate `dylib` crate types
66+
dynamic_linking: true,
67+
only_cdylib: true,
68+
69+
// relatively self-explanatory!
70+
exe_suffix: ".wasm".into(),
71+
dll_prefix: "".into(),
72+
dll_suffix: ".wasm".into(),
73+
eh_frame_header: false,
74+
75+
max_atomic_width: Some(64),
76+
77+
// Unwinding doesn't work right now, so the whole target unconditionally
78+
// defaults to panic=abort. Note that this is guaranteed to change in
79+
// the future once unwinding is implemented. Don't rely on this as we're
80+
// basically guaranteed to change it once WebAssembly supports
81+
// exceptions.
82+
panic_strategy: PanicStrategy::Abort,
83+
84+
// Symbol visibility takes care of this for the WebAssembly.
85+
// Additionally the only known linker, LLD, doesn't support the script
86+
// arguments just yet
87+
limit_rdylib_exports: false,
88+
89+
// we use the LLD shipped with the Rust toolchain by default
90+
linker: Some("rust-lld".into()),
91+
linker_flavor: LinkerFlavor::WasmLld(Cc::No),
92+
93+
pre_link_args,
94+
95+
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
96+
//
97+
// rust-lang/rust#104137: cannot blindly remove this without putting in
98+
// some other way to compensate for lack of `-nostartfiles` in linker
99+
// invocation.
100+
link_self_contained: LinkSelfContainedDefault::True,
101+
pre_link_objects_self_contained: crt_objects::pre_wasi_self_contained(),
102+
post_link_objects_self_contained: crt_objects::post_wasi_self_contained(),
103+
104+
// This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
105+
// PIC code is implemented this has quite a drastic effect if it stays
106+
// at the default, `pic`. In an effort to keep wasm binaries as minimal
107+
// as possible we're defaulting to `static` for now, but the hope is
108+
// that eventually we can ship a `pic`-compatible standard library which
109+
// works with `static` as well (or works with some method of generating
110+
// non-relative calls and such later on).
111+
relocation_model: RelocModel::Static,
112+
113+
// When the atomics feature is activated then these two keys matter,
114+
// otherwise they're basically ignored by the standard library. In this
115+
// mode, however, the `#[thread_local]` attribute works (i.e.
116+
// `has_thread_local`) and we need to get it to work by specifying
117+
// `local-exec` as that's all that's implemented in LLVM today for wasm.
118+
has_thread_local: true,
119+
tls_model: TlsModel::LocalExec,
120+
121+
// Supporting Linux requires multithreading supported by Wasm's thread
122+
// proposal
123+
singlethread: false,
124+
125+
// gdb scripts don't work on wasm blobs
126+
emit_debug_gdb_scripts: false,
127+
128+
// There's more discussion of this at
129+
// https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is
130+
// that this isn't useful for wasm and has tricky issues with
131+
// representation, so this is disabled.
132+
generate_arange_section: false,
133+
134+
// Right now this is a bit of a workaround but we're currently saying that
135+
// the target by default has a static crt which we're taking as a signal
136+
// for "use the bundled crt". If that's turned off then the system's crt
137+
// will be used, but this means that default usage of this target doesn't
138+
// need an external compiler but it's still interoperable with an external
139+
// compiler if configured correctly.
140+
crt_static_default: true,
141+
crt_static_respected: true,
142+
143+
// Allow `+crt-static` to create a "cdylib" output which is just a wasm file
144+
// without a main function.
145+
crt_static_allows_dylibs: true,
146+
147+
// Wasm start ignores arguments -- relies on API call from interface.
148+
main_needs_argc_argv: false,
149+
150+
// Wasm toolchains mangle the name of "main" to distinguish between different
151+
// signatures.
152+
entry_name: "__main_void".into(),
153+
154+
// Wasm Feature flags for supporting Linux
155+
features: "+atomics,+bulk-memory,+mutable-globals,+sign-ext".into(),
156+
157+
..Default::default()
158+
}
159+
}

compiler/rustc_target/src/spec/base/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub(crate) mod linux_gnu;
1717
pub(crate) mod linux_musl;
1818
pub(crate) mod linux_ohos;
1919
pub(crate) mod linux_uclibc;
20+
pub(crate) mod linux_wasm;
2021
pub(crate) mod msvc;
2122
pub(crate) mod netbsd;
2223
pub(crate) mod nto_qnx;

compiler/rustc_target/src/spec/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,7 @@ supported_targets! {
16741674
("wasm32-wasip1", wasm32_wasip1),
16751675
("wasm32-wasip2", wasm32_wasip2),
16761676
("wasm32-wasip1-threads", wasm32_wasip1_threads),
1677+
("wasm32-wali-linux-musl", wasm32_wali_linux_musl),
16771678
("wasm64-unknown-unknown", wasm64_unknown_unknown),
16781679

16791680
("thumbv6m-none-eabi", thumbv6m_none_eabi),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! The `wasm32-wali-linux-musl` target is a wasm32 target compliant with the
2+
//! [WebAssembly Linux Interface](https://github.com/arjunr2/WALI).
3+
4+
use crate::spec::{base, Cc, LinkerFlavor, Target};
5+
6+
pub fn target() -> Target {
7+
let mut options = base::linux_wasm::opts();
8+
9+
options.add_pre_link_args(
10+
LinkerFlavor::WasmLld(Cc::No),
11+
&["--export-memory", "--shared-memory"],
12+
);
13+
options.add_pre_link_args(
14+
LinkerFlavor::WasmLld(Cc::Yes),
15+
&[
16+
"--target=wasm32-wasi-threads",
17+
"-Wl,--export-memory,",
18+
"-Wl,--shared-memory",
19+
],
20+
);
21+
22+
Target {
23+
llvm_target: "wasm32-wasi".into(),
24+
metadata: crate::spec::TargetMetadata {
25+
description: None,
26+
tier: None,
27+
host_tools: None,
28+
std: None,
29+
},
30+
pointer_width: 32,
31+
data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
32+
arch: "wasm32".into(),
33+
options,
34+
}
35+
}

library/core/src/ffi/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,11 @@ mod c_int_definition {
157157

158158
mod c_long_definition {
159159
cfg_if! {
160-
if #[cfg(all(target_pointer_width = "64", not(windows)))] {
160+
// wasm32 for Linux uses 64-bit long as standard
161+
if #[cfg(any(
162+
all(target_pointer_width = "64", not(windows)),
163+
all(target_arch = "wasm32", target_os = "linux", target_env = "musl")
164+
))] {
161165
pub type c_long = i64;
162166
pub type c_ulong = u64;
163167
} else {

library/unwind/src/libunwind.rs

+3
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ pub const unwinder_private_data_size: usize = 35;
8181
#[cfg(target_arch = "loongarch64")]
8282
pub const unwinder_private_data_size: usize = 2;
8383

84+
#[cfg(target_arch = "wasm32")]
85+
pub const unwinder_private_data_size: usize = 2;
86+
8487
#[repr(C)]
8588
pub struct _Unwind_Exception {
8689
pub exception_class: _Unwind_Exception_Class,

src/bootstrap/configure.py

+2
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ def v(*args):
133133
"riscv64gc-unknown-linux-musl install directory")
134134
v("musl-root-loongarch64", "target.loongarch64-unknown-linux-musl.musl-root",
135135
"loongarch64-unknown-linux-musl install directory")
136+
v("musl-root-wali-wasm32", "target.wasm32-wali-linux-musl.musl-root",
137+
"wasm32-wali-linux-musl install directory")
136138
v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
137139
"rootfs in qemu testing, you probably don't want to use this")
138140
v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",

src/bootstrap/src/core/build_steps/compile.rs

+31-17
Original file line numberDiff line numberDiff line change
@@ -371,24 +371,38 @@ fn copy_self_contained_objects(
371371
let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
372372
panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
373373
});
374-
for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
375-
copy_and_stamp(
376-
builder,
377-
&libdir_self_contained,
378-
&srcdir,
379-
obj,
380-
&mut target_deps,
381-
DependencyType::TargetSelfContained,
382-
);
383-
}
384-
let crt_path = builder.ensure(llvm::CrtBeginEnd { target });
385-
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
386-
let src = crt_path.join(obj);
387-
let target = libdir_self_contained.join(obj);
388-
builder.copy_link(&src, &target);
389-
target_deps.push((target, DependencyType::TargetSelfContained));
374+
if !target.starts_with("wasm32") {
375+
for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
376+
copy_and_stamp(
377+
builder,
378+
&libdir_self_contained,
379+
&srcdir,
380+
obj,
381+
&mut target_deps,
382+
DependencyType::TargetSelfContained,
383+
);
384+
}
385+
let crt_path = builder.ensure(llvm::CrtBeginEnd { target });
386+
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
387+
let src = crt_path.join(obj);
388+
let target = libdir_self_contained.join(obj);
389+
builder.copy_link(&src, &target);
390+
target_deps.push((target, DependencyType::TargetSelfContained));
391+
}
392+
} else {
393+
// For wasm32 targets, we need to copy the libc.a and crt1-command.o files from the
394+
// musl-libdir, but we don't need the other files.
395+
for &obj in &["libc.a", "crt1-command.o"] {
396+
copy_and_stamp(
397+
builder,
398+
&libdir_self_contained,
399+
&srcdir,
400+
obj,
401+
&mut target_deps,
402+
DependencyType::TargetSelfContained,
403+
);
404+
}
390405
}
391-
392406
if !target.starts_with("s390x") {
393407
let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
394408
target_deps.push((libunwind_path, DependencyType::TargetSelfContained));

src/bootstrap/src/core/sanity.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[
3535
// just a dummy comment so the list doesn't get onelined
3636
"aarch64-apple-visionos",
3737
"aarch64-apple-visionos-sim",
38+
"wasm32-wali-linux-musl"
3839
];
3940

4041
impl Finder {

tests/assembly/targets/targets-elf.rs

+3
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@
498498
//@ revisions: wasm32_wasip1_threads
499499
//@ [wasm32_wasip1_threads] compile-flags: --target wasm32-wasip1-threads
500500
//@ [wasm32_wasip1_threads] needs-llvm-components: webassembly
501+
//@ revisions: wasm32_wali_linux_musl
502+
//@ [wasm32_wali_linux_musl] compile-flags: --target wasm32-wali-linux-musl
503+
//@ [wasm32_wali_linux_musl] needs-llvm-components: webassembly
501504
//@ revisions: wasm32_wasip2
502505
//@ [wasm32_wasip2] compile-flags: --target wasm32-wasip2
503506
//@ [wasm32_wasip2] needs-llvm-components: webassembly

0 commit comments

Comments
 (0)