Skip to content

Commit 56a65c1

Browse files
committed
Add wasm32-wasmer-wasi-dl target, add WASIX dylib support
1 parent e3a2290 commit 56a65c1

File tree

12 files changed

+197
-56
lines changed

12 files changed

+197
-56
lines changed

build-wasix.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
cd src/llvm-project
6+
git status | grep WebAssemblyISelLowering.cpp &> /dev/null
7+
if [ $? -ne 0 ]; then
8+
git apply ../../wasix-llvm.patch
9+
fi
10+
cd ../..
11+
12+
./x.py build --target=wasm32-wasmer-wasi --stage 2
13+
./x.py build --target=wasm32-wasmer-wasi-dl --stage 2
14+
15+
rustup toolchain uninstall wasix-dev
16+
rustup toolchain link wasix-dev ./build/host/stage2
17+
18+
echo Done

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use core::iter::Iterator;
12
use std::collections::BTreeSet;
23
use std::ffi::OsString;
34
use std::fs::{File, OpenOptions, read};
@@ -1116,16 +1117,22 @@ fn link_natively(
11161117
if sess.target.is_like_osx {
11171118
let stripcmd = "rust-objcopy";
11181119
match (strip, crate_type) {
1119-
(Strip::Debuginfo, _) => {
1120-
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("--strip-debug"))
1121-
}
1120+
(Strip::Debuginfo, _) => strip_symbols_with_external_utility(
1121+
sess,
1122+
stripcmd,
1123+
out_filename,
1124+
Some("--strip-debug"),
1125+
),
11221126
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
11231127
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
11241128
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x"))
11251129
}
1126-
(Strip::Symbols, _) => {
1127-
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("--strip-all"))
1128-
}
1130+
(Strip::Symbols, _) => strip_symbols_with_external_utility(
1131+
sess,
1132+
stripcmd,
1133+
out_filename,
1134+
Some("--strip-all"),
1135+
),
11291136
(Strip::None, _) => {}
11301137
}
11311138
}
@@ -2986,6 +2993,11 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
29862993
}
29872994

29882995
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
2996+
if sess.target.is_like_wasm && lib.name.as_str() == "c" {
2997+
// For wasm targets, WasmLd decides whether to link libc based on
2998+
// the output kind, so we skip it here.
2999+
return false;
3000+
}
29893001
match lib.cfg {
29903002
Some(ref cfg) => rustc_attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
29913003
None => true,

compiler/rustc_codegen_ssa/src/back/linker.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,7 @@ impl<'a> WasmLd<'a> {
12781278
// symbols are how the TLS segments are initialized and configured.
12791279
let mut wasm_ld = WasmLd { cmd, sess };
12801280
if sess.target_features.contains(&sym::atomics) {
1281-
wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1281+
wasm_ld.link_args(&["--shared-memory", "--max-memory=4294967296", "--import-memory"]);
12821282
if sess.target.os == "unknown" || sess.target.os == "none" {
12831283
wasm_ld.link_args(&[
12841284
"--export=__wasm_init_tls",
@@ -1304,11 +1304,37 @@ impl<'a> Linker for WasmLd<'a> {
13041304
_out_filename: &Path,
13051305
) {
13061306
match output_kind {
1307-
LinkOutputKind::DynamicNoPicExe
1308-
| LinkOutputKind::DynamicPicExe
1309-
| LinkOutputKind::StaticNoPicExe
1310-
| LinkOutputKind::StaticPicExe => {}
1311-
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1307+
LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => {}
1308+
LinkOutputKind::StaticPicExe | LinkOutputKind::DynamicPicExe => {
1309+
// FIXME: The wasm32-wasmer-wasi-dl toolchain produces broken executables
1310+
// right now, because the start function isn't linked correctly. Instead of
1311+
// _start calling the rust main function, it calls __main_void from libc,
1312+
// which is broken because rustc does not generate a __main_argc_argv.
1313+
1314+
self.link_args(["-pie", "--export-all", "--no-gc-sections"]);
1315+
1316+
// We link and export all of libc, as well as all of rust's stdlib into dynamic
1317+
// executables, so that side modules can just link against the existing code at
1318+
// runtime. This has two benefits:
1319+
// * Reduced code size for side modules
1320+
// * More importantly, static and thread-local variables will exist only once.
1321+
// This is especially important for libc, which stores things such as the
1322+
// state of its memory allocator (malloc et al.) in static variables.
1323+
let whole_archive = true;
1324+
let verbatim = false; // No effect for WasmLd
1325+
self.link_staticlib_by_name("c", verbatim, whole_archive);
1326+
self.link_staticlib_by_name("resolv", verbatim, whole_archive);
1327+
self.link_staticlib_by_name("rt", verbatim, whole_archive);
1328+
self.link_staticlib_by_name("m", verbatim, whole_archive);
1329+
self.link_staticlib_by_name("pthread", verbatim, whole_archive);
1330+
self.link_staticlib_by_name("util", verbatim, whole_archive);
1331+
self.link_staticlib_by_name("wasi-emulated-mman", verbatim, whole_archive);
1332+
self.link_staticlib_by_name("common-tag-stubs", verbatim, whole_archive);
1333+
}
1334+
LinkOutputKind::DynamicDylib => {
1335+
self.link_args(["--no-entry", "-shared", "--unresolved-symbols=import-dynamic"]);
1336+
}
1337+
LinkOutputKind::StaticDylib => {
13121338
self.link_arg("--no-entry");
13131339
}
13141340
LinkOutputKind::WasiReactorExe => {
@@ -1394,7 +1420,7 @@ impl<'a> Linker for WasmLd<'a> {
13941420

13951421
fn no_default_libraries(&mut self) {}
13961422

1397-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1423+
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
13981424
for sym in symbols {
13991425
self.link_args(&["--export", sym]);
14001426
}
@@ -1403,7 +1429,23 @@ impl<'a> Linker for WasmLd<'a> {
14031429
// symbols explicitly passed via the `--export` flags above and hides all
14041430
// others. Various bits and pieces of wasm32-unknown-unknown tooling use
14051431
// this, so be sure these symbols make their way out of the linker as well.
1406-
self.link_args(&["--export=__heap_base", "--export=__data_end", "--export=__stack_pointer"]);
1432+
self.link_args(&[
1433+
"--export=__wasm_init_tls",
1434+
"--export=__tls_size",
1435+
"--export=__tls_align",
1436+
"--export=__tls_base",
1437+
"--export=__wasm_call_ctors",
1438+
"--export=__wasm_signal",
1439+
"--export-if-defined=__wasm_apply_data_relocs",
1440+
]);
1441+
1442+
if matches!(crate_type, CrateType::Executable) {
1443+
self.link_args(&[
1444+
"--export-if-defined=__stack_pointer",
1445+
"--export-if-defined=__heap_base",
1446+
"--export-if-defined=__data_end",
1447+
]);
1448+
}
14071449
}
14081450

14091451
fn subsystem(&mut self, _subsystem: &str) {}

compiler/rustc_target/src/spec/crt_objects.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ pub(super) fn pre_wasi_self_contained() -> CrtObjects {
115115
(LinkOutputKind::DynamicPicExe, &["crt1-command.o"]),
116116
(LinkOutputKind::StaticNoPicExe, &["crt1-command.o"]),
117117
(LinkOutputKind::StaticPicExe, &["crt1-command.o"]),
118+
(LinkOutputKind::DynamicDylib, &["scrt1.o"]),
119+
(LinkOutputKind::StaticDylib, &["scrt1.o"]),
118120
(LinkOutputKind::WasiReactorExe, &["crt1-reactor.o"]),
119121
])
120122
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,9 +1333,9 @@ impl StackProbeType {
13331333
.and_then(|o| o.as_array())
13341334
.ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
13351335
let mut iter = min_version.into_iter().map(|v| {
1336-
let int = v.as_u64().ok_or_else(|| {
1337-
"expected `min-llvm-version-for-inline` values to be integers"
1338-
})?;
1336+
let int = v.as_u64().ok_or_else(
1337+
|| "expected `min-llvm-version-for-inline` values to be integers",
1338+
)?;
13391339
u32::try_from(int)
13401340
.map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
13411341
});
@@ -1809,6 +1809,7 @@ supported_targets! {
18091809
("wasm32-wasip2", wasm32_wasip2),
18101810
("wasm32-wasip1-threads", wasm32_wasip1_threads),
18111811
("wasm32-wasmer-wasi", wasm32_wasmer_wasi),
1812+
("wasm32-wasmer-wasi-dl", wasm32_wasmer_wasi_dl),
18121813
("wasm64-unknown-emscripten", wasm64_unknown_emscripten),
18131814
("wasm64-unknown-unknown", wasm64_unknown_unknown),
18141815
("wasm64-wasmer-wasi", wasm64_wasmer_wasi),
@@ -3462,10 +3463,10 @@ impl Target {
34623463

34633464
// Each field should have been read using `Json::remove` so any keys remaining are unused.
34643465
let remaining_keys = obj.keys();
3465-
Ok((base, TargetWarnings {
3466-
unused_fields: remaining_keys.cloned().collect(),
3467-
incorrect_type,
3468-
}))
3466+
Ok((
3467+
base,
3468+
TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
3469+
))
34693470
}
34703471

34713472
/// Load a built-in target

compiler/rustc_target/src/spec/targets/wasm32_wasmer_wasi.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,31 @@
7171
//! best we can with this target. Don't start relying on too much here unless
7272
//! you know what you're getting in to!
7373
74-
use crate::spec::{base, crt_objects, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
74+
use crate::spec::{Cc, LinkSelfContainedDefault, LinkerFlavor, Target, base, crt_objects};
7575

7676
pub(crate) fn target() -> Target {
77+
macro_rules! args {
78+
($prefix:literal) => {
79+
&[
80+
// We need shared memory for multithreading
81+
concat!($prefix, "--shared-memory"),
82+
concat!($prefix, "--import-memory"),
83+
concat!($prefix, "--export-dynamic"),
84+
concat!($prefix, "--no-check-features"),
85+
concat!($prefix, "-mllvm"),
86+
concat!($prefix, "--wasm-enable-sjlj"),
87+
]
88+
};
89+
}
90+
7791
let mut options = base::wasm::options();
7892

7993
options.os = "wasi".into();
8094
options.vendor = "wasmer".into();
81-
options.add_pre_link_args(
82-
LinkerFlavor::WasmLld(Cc::Yes),
83-
&[
84-
"--target=wasm32-wasi",
85-
// We need shared memory for multithreading
86-
"--shared-memory",
87-
"--no-check-features",
88-
],
89-
);
95+
options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), &["--target=wasm32-wasi"]);
96+
97+
options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,"));
98+
options.add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), args!(""));
9099

91100
options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
92101
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! `wasm32-wasmer-wasi` with support for dynamic linking.
2+
3+
use crate::spec::{RelocModel, Target, TlsModel};
4+
5+
pub(crate) fn target() -> Target {
6+
let mut target = super::wasm32_wasmer_wasi::target();
7+
8+
target.env = "dl".into();
9+
10+
target.options.dll_prefix = "lib".into();
11+
target.options.dll_suffix = ".so".into();
12+
13+
target.options.relocation_model = RelocModel::Pic;
14+
target.options.tls_model = TlsModel::GeneralDynamic;
15+
target.options.crt_static_default = false;
16+
target.options.position_independent_executables = true;
17+
18+
target
19+
}

config.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
change-id = 125535
22

33
[build]
4-
target = ["wasm32-wasmer-wasi", "wasm64-wasmer-wasi"]
4+
target = ["wasm32-wasmer-wasi", "wasm32-wasmer-wasi-dl"]
55
extended = true
6-
tools = [ "clippy", "rustfmt" ]
6+
tools = ["cargo", "clippy", "rustfmt"]
77
configure-args = []
88

99
[rust]
@@ -14,7 +14,7 @@ llvm-tools = true
1414
download-ci-llvm = false
1515

1616
[target.wasm32-wasmer-wasi]
17-
wasi-root = "../wasix-libc/sysroot32"
17+
wasi-root = "../wasix-libc/sysroot32-eh"
1818

19-
[target.wasm64-wasmer-wasi]
20-
wasi-root = "../wasix-libc/sysroot64"
19+
[target.wasm32-wasmer-wasi-dl]
20+
wasi-root = "../wasix-libc/sysroot32-ehpic"

library/std/Cargo.toml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
3434
addr2line = { version = "0.22.0", optional = true, default-features = false }
3535

3636
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
37-
libc = { git = "https://github.com/wasix-org/libc.git", branch = "wasix-0.2.164", version = "0.2.164", default-features = false, features = ['rustc-dep-of-std'], public = true }
37+
libc = { git = "https://github.com/wasix-org/libc.git", branch = "wasix-0.2.164", version = "0.2.164", default-features = false, features = [
38+
'rustc-dep-of-std',
39+
], public = true }
3840

3941
[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
4042
object = { version = "0.36.0", default-features = false, optional = true, features = [
@@ -80,10 +82,19 @@ wasi = { version = "0.11.0", features = [
8082
], default-features = false }
8183

8284
[target.wasm32-wasmer-wasi.dependencies]
83-
wasi = { package = "wasix", version = "0.13.0", features = ['rustc-dep-of-std'], default-features = false, public = true }
85+
wasi = { package = "wasix", version = "0.13.0", features = [
86+
'rustc-dep-of-std',
87+
], default-features = false, public = true }
88+
89+
[target.wasm32-wasmer-wasi-dl.dependencies]
90+
wasi = { package = "wasix", version = "0.13.0", features = [
91+
'rustc-dep-of-std',
92+
], default-features = false, public = true }
8493

8594
[target.wasm64-wasmer-wasi.dependencies]
86-
wasi = { package = "wasix", version = "0.13.0", features = ['rustc-dep-of-std'], default-features = false, public = true }
95+
wasi = { package = "wasix", version = "0.13.0", features = [
96+
'rustc-dep-of-std',
97+
], default-features = false, public = true }
8798

8899
[target.'cfg(target_os = "uefi")'.dependencies]
89100
r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
@@ -145,6 +156,7 @@ check-cfg = [
145156
'cfg(bootstrap)',
146157
'cfg(target_arch, values("xtensa"))',
147158
'cfg(target_vendor, values("wasmer"))',
159+
'cfg(target_env, values("dl"))',
148160
# std use #[path] imports to portable-simd `std_float` crate
149161
# and to the `backtrace` crate which messes-up with Cargo list
150162
# of declared features, we therefor expect any feature cfg

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,28 @@ fn copy_self_contained_objects(
392392
target.triple
393393
)
394394
});
395-
for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
395+
let mut files = vec!["libc.a", "crt1-command.o", "crt1-reactor.o"];
396+
if target.contains("-dl") {
397+
files.extend([
398+
// Needed for DL side modules.
399+
"scrt1.o",
400+
// Need to bring these over for DL main module builds, so we can embed them.
401+
"libcommon-tag-stubs.a",
402+
"libcrypt.a",
403+
"libwasi-emulated-mman.a",
404+
"libresolv.a",
405+
"librt.a",
406+
"libm.a",
407+
"libpthread.a",
408+
"libutil.a",
409+
// We don't link c++ libs in, but we bring them over anyway so that, when
410+
// a rust program needs to load C++-based dylibs, the user can link these
411+
// in manually via linker flags.
412+
"libc++.a",
413+
"libc++abi.a",
414+
]);
415+
}
416+
for obj in files {
396417
copy_and_stamp(
397418
builder,
398419
&libdir_self_contained,

0 commit comments

Comments
 (0)