Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link against lld for linking compiled object files #8

Merged
merged 4 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions comment.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand All @@ -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!
```
23 changes: 23 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Vec<_>>();
args.insert(0, std::ffi::CString::new(cmd.get_program().as_encoded_bytes()).unwrap());
let argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();

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();
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_fs_util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -77,14 +76,18 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li
}
}

#[cfg(unix)]
#[cfg(any(unix, all(target_os = "wasi", target_env = "p1")))]
pub fn path_to_c_string(p: &Path) -> 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()
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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");
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@whitequark do you know if there is a nicer way to link against lld? llvm-config doesn't list it as available component.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might be the best way sadly :/


// LLVM ldflags
//
// If we're a cross-compile of LLVM then unfortunately we can't trust these
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/LLD.cpp
Original file line number Diff line number Diff line change
@@ -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<const char *> 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;
}
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions config.llvm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,7 +22,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]
Expand Down
6 changes: 5 additions & 1 deletion src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -1211,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, &[]);
Expand Down
6 changes: 6 additions & 0 deletions src/bootstrap/src/core/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Loading