From 3000a3f63d9bb96614a1d8ee9dc4d3005af0489e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 10 Aug 2019 16:50:23 +0200 Subject: [PATCH 1/6] [WIP] Implement dylib loading for the JIT --- Cargo.lock | 11 +++++++++ Cargo.toml | 1 + config.sh | 3 +++ example/mini_core.rs | 7 ------ src/driver.rs | 59 ++++++++++++++++++++++++++++++++++++++++++-- test.sh | 9 ++++--- 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1311e02f78f6..c642747e6f01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,6 +396,15 @@ name = "libc" version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libloading" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -606,6 +615,7 @@ dependencies = [ "gimli 0.19.0 (git+https://github.com/gimli-rs/gimli.git)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.12.0 (git+https://github.com/gimli-rs/object.git)", "target-lexicon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -884,6 +894,7 @@ dependencies = [ "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +"checksum libloading 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5692f82b51823e27c4118b3e5c0d98aee9be90633ebc71ad12afef380b50219" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" diff --git a/Cargo.toml b/Cargo.toml index 414423d72b97..ec0350687aac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ tempfile = "3.0.7" gimli = { git = "https://github.com/gimli-rs/gimli.git" } indexmap = "1.0.2" object = "0.12.0" +libloading = "0.5.1" [patch."https://github.com/CraneStation/cranelift.git"] cranelift = { git = "https://github.com/bjorn3/cretonne.git", branch = "do_not_remove_cg_clif_i128" } diff --git a/config.sh b/config.sh index a6868f792dec..1d5c78c8e729 100644 --- a/config.sh +++ b/config.sh @@ -15,3 +15,6 @@ TARGET_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") export RUSTFLAGS='-Zalways-encode-mir -Cpanic=abort -Cdebuginfo=2 -Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot' RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out" export RUSTC_LOG=warn # display metadata load errors + +export LD_LIBRARY_PATH=$(pwd)/target/out +export DYLD_LIBRARY_PATH=$(pwd)/target/out diff --git a/example/mini_core.rs b/example/mini_core.rs index f57f1ff635d7..84664eb41392 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -369,9 +369,6 @@ pub trait FnMut: FnOnce { } #[lang = "panic"] -// Make it available to jited mini_core_hello_world -// FIXME remove next line when jit supports linking rlibs -#[inline(always)] pub fn panic(&(_msg, _file, _line, _col): &(&'static str, &'static str, u32, u32)) -> ! { unsafe { libc::puts("Panicking\0" as *const str as *const u8); @@ -419,15 +416,11 @@ impl Deref for Box { } #[lang = "exchange_malloc"] -// Make it available to jited mini_core_hello_world -// FIXME remove next line when jit supports linking rlibs -#[inline(always)] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { libc::malloc(size) } #[lang = "box_free"] -#[inline(always)] unsafe fn box_free(ptr: *mut T) { libc::free(ptr as *mut u8); } diff --git a/src/driver.rs b/src/driver.rs index 413f9f4e0484..e3bf4a0d5693 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -48,9 +48,64 @@ pub fn codegen_crate( fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; - let mut jit_module: Module = Module::new(SimpleJITBuilder::new( + let mut dylib_paths = Vec::new(); + + { + use rustc::middle::dependency_format::Linkage; + + let crate_info = CrateInfo::new(tcx); + let formats = tcx.sess.dependency_formats.borrow(); + let data = formats.get(&CrateType::Executable).unwrap(); + for &(cnum, _) in &crate_info.used_crates_dynamic { + let src = &crate_info.used_crate_source[&cnum]; + match data[cnum.as_usize() - 1] { + _ if crate_info.profiler_runtime == Some(cnum) => unimplemented!(), + _ if crate_info.sanitizer_runtime == Some(cnum) => unimplemented!(), + + // compiler-builtins are always placed last to ensure that they're + // linked correctly. + _ if crate_info.compiler_builtins == Some(cnum) => { + unimplemented!(); + } + Linkage::NotLinked | + Linkage::IncludedFromDylib => {} + Linkage::Static => { + let name = tcx.crate_name(cnum); + let mut err = tcx.sess.struct_fatal(&format!("Can't load static lib {}", name.as_str())); + err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); + err.emit(); + } + Linkage::Dynamic => { + dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); + } + } + } + } + + let mut imported_symbols = Vec::new(); + for path in dylib_paths { + use object::Object; + let lib = libloading::Library::new(&path).unwrap(); + let obj = std::fs::read(path).unwrap(); + let obj = object::File::parse(&obj).unwrap(); + imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { + let name = symbol.name().unwrap().to_string(); + if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { + return None; + } + println!("name: {:?}", name); + let symbol: libloading::Symbol<*const u8> = + unsafe { lib.get(name.as_bytes()) }.unwrap(); + Some((name, *symbol)) + })); + std::mem::forget(lib) + } + + let mut jit_builder = SimpleJITBuilder::new( cranelift_module::default_libcall_names(), - )); + ); + jit_builder.symbols(imported_symbols); + let mut jit_module: Module = Module::new(jit_builder); assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); let sig = Signature { diff --git a/test.sh b/test.sh index aa5b18365278..71c3ba50f7e1 100755 --- a/test.sh +++ b/test.sh @@ -33,13 +33,16 @@ $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitr ./target/out/arbitrary_self_types_pointers_and_wrappers echo "[BUILD] sysroot" -time ./build_sysroot/build_sysroot.sh +#time ./build_sysroot/build_sysroot.sh -echo "[BUILD+RUN] alloc_example" +echo "[AOT] alloc_example" $RUSTC example/alloc_example.rs --crate-type bin ./target/out/alloc_example -echo "[BUILD+RUN] std_example" +echo "[JIT] std_example" +SHOULD_RUN=1 $RUSTC example/std_example.rs --crate-type bin -Cprefer-dynamic + +echo "[AOT] std_example" $RUSTC example/std_example.rs --crate-type bin ./target/out/std_example From 1538f7488e370f380aa5832f2d23f7010c1809f2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 10 Aug 2019 16:56:19 +0200 Subject: [PATCH 2/6] Add libstd.so to sysroot --- build_sysroot/build_sysroot.sh | 4 ++-- test.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index 4e58858f133d..c37dd5104a85 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -28,7 +28,7 @@ fi # Copy files to sysroot mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ -cp target/$TARGET_TRIPLE/$sysroot_channel/deps/*.rlib sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +cp target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ if [[ "$1" == "--release" ]]; then channel='release' @@ -39,4 +39,4 @@ else fi # Copy files to sysroot -cp sysroot_src/src/libtest/target/$TARGET_TRIPLE/$sysroot_channel/deps/*.rlib sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +cp sysroot_src/src/libtest/target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ diff --git a/test.sh b/test.sh index 71c3ba50f7e1..cd2b9fe44839 100755 --- a/test.sh +++ b/test.sh @@ -33,7 +33,7 @@ $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitr ./target/out/arbitrary_self_types_pointers_and_wrappers echo "[BUILD] sysroot" -#time ./build_sysroot/build_sysroot.sh +time ./build_sysroot/build_sysroot.sh echo "[AOT] alloc_example" $RUSTC example/alloc_example.rs --crate-type bin From 9041db962decfe6fa719d3f801b3f985f8027110 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 11 Aug 2019 17:06:18 +0200 Subject: [PATCH 3/6] Fix it --- src/driver.rs | 18 +++++------------- src/lib.rs | 10 +++++++--- src/pretty_clif.rs | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index e3bf4a0d5693..fc1049684b94 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -59,16 +59,7 @@ fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { for &(cnum, _) in &crate_info.used_crates_dynamic { let src = &crate_info.used_crate_source[&cnum]; match data[cnum.as_usize() - 1] { - _ if crate_info.profiler_runtime == Some(cnum) => unimplemented!(), - _ if crate_info.sanitizer_runtime == Some(cnum) => unimplemented!(), - - // compiler-builtins are always placed last to ensure that they're - // linked correctly. - _ if crate_info.compiler_builtins == Some(cnum) => { - unimplemented!(); - } - Linkage::NotLinked | - Linkage::IncludedFromDylib => {} + Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { let name = tcx.crate_name(cnum); let mut err = tcx.sess.struct_fatal(&format!("Can't load static lib {}", name.as_str())); @@ -101,7 +92,8 @@ fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { std::mem::forget(lib) } - let mut jit_builder = SimpleJITBuilder::new( + let mut jit_builder = SimpleJITBuilder::with_isa( + crate::build_isa(tcx.sess, false), cranelift_module::default_libcall_names(), ); jit_builder.symbols(imported_symbols); @@ -159,7 +151,7 @@ fn run_aot( let new_module = |name: String| { let module: Module = Module::new( FaerieBuilder::new( - crate::build_isa(tcx.sess), + crate::build_isa(tcx.sess, true), name + ".o", FaerieTrapCollection::Disabled, cranelift_module::default_libcall_names(), @@ -231,7 +223,7 @@ fn run_aot( .to_string(); let mut metadata_artifact = - faerie::Artifact::new(crate::build_isa(tcx.sess).triple().clone(), metadata_cgu_name.clone()); + faerie::Artifact::new(crate::build_isa(tcx.sess, true).triple().clone(), metadata_cgu_name.clone()); crate::metadata::write_metadata(tcx, &mut metadata_artifact); let tmp_file = tcx diff --git a/src/lib.rs b/src/lib.rs index 22beefd16235..e0cd46eea3c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,10 +239,14 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple { target.parse().unwrap() } -fn build_isa(sess: &Session) -> Box { +fn build_isa(sess: &Session, enable_pic: bool) -> Box { let mut flags_builder = settings::builder(); - flags_builder.enable("is_pic").unwrap(); - flags_builder.set("probestack_enabled", "false").unwrap(); // ___cranelift_probestack is not provided + if enable_pic { + flags_builder.enable("is_pic").unwrap(); + } else { + flags_builder.set("is_pic", "false").unwrap(); + } + flags_builder.set("probestack_enabled", "false").unwrap(); // __cranelift_probestack is not provided flags_builder.set("enable_verifier", if cfg!(debug_assertions) { "true" } else { diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 57fcebe79c26..4d05659a060e 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -218,7 +218,7 @@ pub fn write_clif_file<'tcx>( &mut clif, &func, &DisplayFunctionAnnotations { - isa: Some(&*crate::build_isa(tcx.sess)), + isa: Some(&*crate::build_isa(tcx.sess, true /* PIC doesn't matter here */)), value_ranges, }, ) From 05b7312db23eb9551f966e2b725bb62fae9dcd75 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 11 Aug 2019 17:33:52 +0200 Subject: [PATCH 4/6] Misc changes --- config.sh | 4 ++-- src/driver.rs | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/config.sh b/config.sh index 1d5c78c8e729..9bfff744a66f 100644 --- a/config.sh +++ b/config.sh @@ -16,5 +16,5 @@ export RUSTFLAGS='-Zalways-encode-mir -Cpanic=abort -Cdebuginfo=2 -Zcodegen-back RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out" export RUSTC_LOG=warn # display metadata load errors -export LD_LIBRARY_PATH=$(pwd)/target/out -export DYLD_LIBRARY_PATH=$(pwd)/target/out +export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib" +export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH diff --git a/src/driver.rs b/src/driver.rs index fc1049684b94..a8be65b03813 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -18,13 +18,6 @@ pub fn codegen_crate( metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box { - if !tcx.sess.crate_types.get().contains(&CrateType::Executable) - && std::env::var("SHOULD_RUN").is_ok() - { - tcx.sess - .err("Can't JIT run non executable (SHOULD_RUN env var is set)"); - } - tcx.sess.abort_if_errors(); let mut log = if cfg!(debug_assertions) { @@ -33,7 +26,9 @@ pub fn codegen_crate( None }; - if std::env::var("SHOULD_RUN").is_ok() { + if std::env::var("SHOULD_RUN").is_ok() + && tcx.sess.crate_types.get().contains(&CrateType::Executable) + { #[cfg(not(target_arch = "wasm32"))] let _: ! = run_jit(tcx, &mut log); From bd19af37f48844838ad1d07c0c9eb214e43bd83c Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 11 Aug 2019 18:12:49 +0200 Subject: [PATCH 5/6] Remove debugging println --- src/driver.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index a8be65b03813..65f81680bbc6 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -79,7 +79,6 @@ fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { return None; } - println!("name: {:?}", name); let symbol: libloading::Symbol<*const u8> = unsafe { lib.get(name.as_bytes()) }.unwrap(); Some((name, *symbol)) From 57bc9d8daf268fa7dc28d89665f4e8ee394ae726 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 11 Aug 2019 18:17:51 +0200 Subject: [PATCH 6/6] Extract jit imported symbols loading functionAlso make the staticlib load error non fatal --- src/driver.rs | 90 +++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 65f81680bbc6..3c4ce99d9828 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -43,48 +43,7 @@ pub fn codegen_crate( fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; - let mut dylib_paths = Vec::new(); - - { - use rustc::middle::dependency_format::Linkage; - - let crate_info = CrateInfo::new(tcx); - let formats = tcx.sess.dependency_formats.borrow(); - let data = formats.get(&CrateType::Executable).unwrap(); - for &(cnum, _) in &crate_info.used_crates_dynamic { - let src = &crate_info.used_crate_source[&cnum]; - match data[cnum.as_usize() - 1] { - Linkage::NotLinked | Linkage::IncludedFromDylib => {} - Linkage::Static => { - let name = tcx.crate_name(cnum); - let mut err = tcx.sess.struct_fatal(&format!("Can't load static lib {}", name.as_str())); - err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); - err.emit(); - } - Linkage::Dynamic => { - dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); - } - } - } - } - - let mut imported_symbols = Vec::new(); - for path in dylib_paths { - use object::Object; - let lib = libloading::Library::new(&path).unwrap(); - let obj = std::fs::read(path).unwrap(); - let obj = object::File::parse(&obj).unwrap(); - imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { - let name = symbol.name().unwrap().to_string(); - if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { - return None; - } - let symbol: libloading::Symbol<*const u8> = - unsafe { lib.get(name.as_bytes()) }.unwrap(); - Some((name, *symbol)) - })); - std::mem::forget(lib) - } + let imported_symbols = load_imported_symbols_for_jit(tcx); let mut jit_builder = SimpleJITBuilder::with_isa( crate::build_isa(tcx.sess, false), @@ -136,6 +95,53 @@ fn run_jit(tcx: TyCtxt<'_>, log: &mut Option) -> ! { std::process::exit(ret); } +fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { + use rustc::middle::dependency_format::Linkage; + + let mut dylib_paths = Vec::new(); + + let crate_info = CrateInfo::new(tcx); + let formats = tcx.sess.dependency_formats.borrow(); + let data = formats.get(&CrateType::Executable).unwrap(); + for &(cnum, _) in &crate_info.used_crates_dynamic { + let src = &crate_info.used_crate_source[&cnum]; + match data[cnum.as_usize() - 1] { + Linkage::NotLinked | Linkage::IncludedFromDylib => {} + Linkage::Static => { + let name = tcx.crate_name(cnum); + let mut err = tcx.sess.struct_err(&format!("Can't load static lib {}", name.as_str())); + err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); + err.emit(); + } + Linkage::Dynamic => { + dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); + } + } + } + + let mut imported_symbols = Vec::new(); + for path in dylib_paths { + use object::Object; + let lib = libloading::Library::new(&path).unwrap(); + let obj = std::fs::read(path).unwrap(); + let obj = object::File::parse(&obj).unwrap(); + imported_symbols.extend(obj.dynamic_symbols().filter_map(|(_idx, symbol)| { + let name = symbol.name().unwrap().to_string(); + if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { + return None; + } + let symbol: libloading::Symbol<*const u8> = + unsafe { lib.get(name.as_bytes()) }.unwrap(); + Some((name, *symbol)) + })); + std::mem::forget(lib) + } + + tcx.sess.abort_if_errors(); + + imported_symbols +} + fn run_aot( tcx: TyCtxt<'_>, metadata: EncodedMetadata,