From 3fce7045cb9b4cbd892f8a5189e3849478791eea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:24:29 +0200 Subject: [PATCH 1/4] Link against lld for linking compiled object files --- compiler/rustc_codegen_ssa/src/back/link.rs | 23 +++++++++++++++++++++ compiler/rustc_llvm/build.rs | 6 ++++++ compiler/rustc_llvm/llvm-wrapper/LLD.cpp | 11 ++++++++++ config.llvm.toml | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 3 ++- 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_llvm/llvm-wrapper/LLD.cpp diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index af7f9d0f34af1..0b3c202ec48a2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -801,6 +801,29 @@ fn link_natively( // Invoke the system linker info!("{cmd:?}"); + + #[cfg(target_os = "wasi")] + if matches!(flavor, LinkerFlavor::Gnu(Cc::No, Lld::Yes) | LinkerFlavor::WasmLld(Cc::No)) { + extern "C" { + fn RustRunLld( + argc: std::ffi::c_int, + argv: *const *const std::ffi::c_char, + ) -> std::ffi::c_int; + } + + let cmd = cmd.command(); + println!("Linking using {cmd:?}"); + let mut args = cmd + .get_args() + .map(|arg| std::ffi::CString::new(arg.as_encoded_bytes()).unwrap()) + .collect::>(); + args.insert(0, std::ffi::CString::new(cmd.get_program().as_encoded_bytes()).unwrap()); + let argv = args.iter().map(|arg| arg.as_ptr()).collect::>(); + + let ret = unsafe { RustRunLld(args.len() as std::ffi::c_int, argv.as_ptr()) }; + std::process::exit(ret); + } + let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok(); let unknown_arg_regex = Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap(); diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index abc8f8bf974cc..a2829032fd554 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -221,6 +221,7 @@ fn main() { .file("llvm-wrapper/CoverageMappingWrapper.cpp") .file("llvm-wrapper/SymbolWrapper.cpp") .file("llvm-wrapper/Linker.cpp") + .file("llvm-wrapper/LLD.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("llvm-wrapper"); @@ -328,6 +329,11 @@ fn main() { println!("cargo:rustc-link-lib={kind}={name}"); } + println!("cargo:rustc-link-lib=static=LLVMOption"); + println!("cargo:rustc-link-lib=static=lldCommon"); + println!("cargo:rustc-link-lib=static=lldELF"); + println!("cargo:rustc-link-lib=static=lldWasm"); + // LLVM ldflags // // If we're a cross-compile of LLVM then unfortunately we can't trust these diff --git a/compiler/rustc_llvm/llvm-wrapper/LLD.cpp b/compiler/rustc_llvm/llvm-wrapper/LLD.cpp new file mode 100644 index 0000000000000..182ea9534b31d --- /dev/null +++ b/compiler/rustc_llvm/llvm-wrapper/LLD.cpp @@ -0,0 +1,11 @@ +#include "lld/Common/Driver.h" + +LLD_HAS_DRIVER(elf) +LLD_HAS_DRIVER(wasm) + +extern "C" int RustRunLld(int argc, char **argv) { + llvm::ArrayRef args(argv, argv + argc); + auto r = lld::lldMain(args, llvm::outs(), llvm::errs(), + {{lld::Gnu, &lld::elf::link}, {lld::Wasm, &lld::wasm::link}}); + return r.retCode; +} diff --git a/config.llvm.toml b/config.llvm.toml index 1a64513e1ed48..ababcbb76a0dc 100644 --- a/config.llvm.toml +++ b/config.llvm.toml @@ -24,7 +24,7 @@ docs = false extended = false tools = [] host = ["wasm32-wasip1-threads"] -target = ["x86_64-unknown-linux-gnu", "wasm32-wasip1-threads"] +target = ["x86_64-unknown-linux-gnu", "wasm32-wasip1"] cargo-native-static = true [install] diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 3c1acb2cf1f00..24f6cf965bf43 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -515,6 +515,8 @@ impl Step for Llvm { return res; } + cfg.define("LLVM_ENABLE_PROJECTS", "lld"); + if target.contains("wasi") { let wasi_sysroot = env::var("WASI_SYSROOT").expect("WASI_SYSROOT not set"); let wasi_sdk_path = std::path::Path::new(&wasi_sysroot) @@ -669,7 +671,6 @@ impl Step for Llvm { .define("LLVM_TOOL_XCODE_TOOLCHAIN_BUILD", "OFF") .define("LLVM_TOOL_YAML2OBJ_BUILD", "OFF") // .define("LLVM_ENABLE_PROJECTS", "clang;lld") - .define("LLVM_ENABLE_PROJECTS", "") // .define("CLANG_ENABLE_ARCMT", "OFF") // .define("CLANG_ENABLE_STATIC_ANALYZER", "OFF") // .define("CLANG_INCLUDE_TESTS", "OFF") From 27df5ca6a80e3c7478f8e2ce6a7a5a8b5df0abbc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:43:07 +0200 Subject: [PATCH 2/4] Make linking for wasm32-wasip1 work by default --- comment.txt | 7 +++---- compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs | 2 +- .../rustc_target/src/spec/targets/wasm32_wasip1_threads.rs | 2 +- config.llvm.toml | 2 -- src/bootstrap/src/core/builder.rs | 6 ++++++ 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/comment.txt b/comment.txt index 231b003b3d244..f669c73e64bd3 100644 --- a/comment.txt +++ b/comment.txt @@ -24,7 +24,7 @@ WASI_SDK_PATH=`pwd`/wasi-sdk-24.0-x86_64-linux WASI_SYSROOT=`pwd`/wasi-sdk-24.0- If you just want to run it, https://github.com/oligamiq/rust_wasm/tree/main/rustc_llvm ``` $ mkdir tmp -$ echo 'fn main() { println!("Hello World!"); }' | wasmtime run -Sthreads=y -Spreview2=n --dir tmp::/ --dir dist --env RUST_MIN_STACK=16777216 dist/bin/rustc.wasm - --sysroot dist --target wasm32-wasip1-threads -Csave-temps +$ echo 'fn main() { println!("Hello World!"); }' | wasmtime run -Sthreads=y -Spreview2=n --dir tmp::/ --dir dist --env RUST_MIN_STACK=16777216 dist/bin/rustc.wasm - --sysroot dist --target x86_64-unknown-linux-gnu -Csave-temps $ gcc -fuse-ld=lld tmp/rmeta*/lib.rmeta tmp/rust_out.*.o dist/lib/rustlib/x86_64-unknown-linux-gnu/lib/lib*.rlib -o rust_out $ ./rust_out Hello World! @@ -33,8 +33,7 @@ Hello World! to Wasi ``` $ mkdir tmp -$ echo 'fn main() { println!("Hello World!"); }' | wasmtime run -Sthreads=y -Spreview2=n --dir tmp::/ --dir dist --env RUST_MIN_STACK=16777216 dist/bin/rustc.wasm - --sysroot dist --target wasm32-wasip1-threads -Csave-temps -$ wasi-sdk-24.0-x86_64-linux/bin/wasm-ld --shared-memory --max-memory=1073741824 --import-memory --export __main_void -z stack-size=1048576 --stack-first --allow-undefined --no-demangle --import-memory --export-memory --shared-memory dist/lib/rustlib/wasm32-wasip1-threads/lib/self-contained/crt1-command.o tmp/rust_out.*.o dist/lib/rustlib/wasm32-wasip1-threads/lib/lib*.rlib -L dist/lib/rustlib/wasm32-wasip1-threads/lib/self-contained -lc -o rust_out.wasm -$ wasmtime run -Sthreads=y rust_out.wasm +$ echo 'fn main() { println!("Hello World!"); }' | wasmtime run -Sthreads=y -Spreview2=n --dir tmp::/ --dir dist --env RUST_MIN_STACK=16777216 dist/bin/rustc.wasm - --sysroot dist --target wasm32-wasip1 +$ wasmtime run tmp/rust_out.wasm Hello World! ``` diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs index 63718ed7a9f45..7728d83c2b680 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs @@ -23,7 +23,7 @@ pub(crate) fn target() -> Target { options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained(); // FIXME: Figure out cases in which WASM needs to link with a native toolchain. - options.link_self_contained = LinkSelfContainedDefault::False; + options.link_self_contained = LinkSelfContainedDefault::True; // Right now this is a bit of a workaround but we're currently saying that // the target by default has a static crt which we're taking as a signal diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 078ae9c6c9414..f6ce1c25a3a0e 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -41,7 +41,7 @@ pub(crate) fn target() -> Target { options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained(); // FIXME: Figure out cases in which WASM needs to link with a native toolchain. - options.link_self_contained = LinkSelfContainedDefault::False; + options.link_self_contained = LinkSelfContainedDefault::True; // Right now this is a bit of a workaround but we're currently saying that // the target by default has a static crt which we're taking as a signal diff --git a/config.llvm.toml b/config.llvm.toml index ababcbb76a0dc..f5a9ccfc6ccca 100644 --- a/config.llvm.toml +++ b/config.llvm.toml @@ -10,8 +10,6 @@ debug = false debuginfo-level = 0 [llvm] -cflags = "-march=native" -cxxflags = "-march=native" static-libstdcpp = true ninja = false download-ci-llvm = false diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index fe68af593aca0..b416903ff840e 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2601,6 +2601,12 @@ impl Cargo { } } + if target.contains("wasi") { + // link-self-contained needs lld to be present, but getting it to + // link for wasi is a bit difficult. + self.rustflags.arg("-Clink-self-contained=no"); + } + for arg in linker_args(builder, compiler.host, LldThreads::Yes) { self.hostflags.arg(&arg); } From a3975a321acb29e6401e6f73f047ea38cb014ea5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:43:35 +0200 Subject: [PATCH 3/4] Better path_to_c_string impl --- compiler/rustc_fs_util/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index b7f267b4bbd11..21ef09e256420 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,4 +1,3 @@ -#[cfg(any(unix, windows, target_os = "wasi"))] use std::ffi::CString; use std::path::{absolute, Path, PathBuf}; use std::{fs, io}; @@ -77,14 +76,18 @@ pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result
  • CString { use std::ffi::OsStr; + #[cfg(unix)] use std::os::unix::ffi::OsStrExt; + #[cfg(all(target_os = "wasi", target_env = "p1"))] + use std::os::wasi::ffi::OsStrExt; + let p: &OsStr = p.as_ref(); CString::new(p.as_bytes()).unwrap() } -#[cfg(any(windows, target_os = "wasi"))] +#[cfg(windows)] pub fn path_to_c_string(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } From cf327c2068549194a29160499c2ecafa9061e46e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:44:19 +0200 Subject: [PATCH 4/4] Disable rpath for lld when requested (unrelated to getting rustc to compile for wasi) --- src/bootstrap/src/core/build_steps/llvm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 24f6cf965bf43..13809b35ecd52 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1212,6 +1212,9 @@ impl Step for Lld { // `$ORIGIN` would otherwise be expanded when the `LdFlags` are passed verbatim to // cmake. ldflags.push_all("-Wl,-rpath,'$ORIGIN/../../../'"); + } else { + // CMake defaults to building executables with rpath enabled. + cfg.define("CMAKE_SKIP_RPATH", "ON"); } configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);