Skip to content

Commit 778b631

Browse files
authored
Rollup merge of rust-lang#62809 - alexcrichton:wasm-llvm-9, r=nikic
rustc: Update wasm32 support for LLVM 9 This commit brings in a number of minor updates for rustc's support for the wasm target which has changed in the LLVM 9 update. Notable updates include: * The compiler now no longer manually inserts the `producers` section, instead relying on LLVM to do so. LLVM uses the `llvm.ident` metadata for the `processed-by` directive (which is now emitted on the wasm target in this PR) and it uses debuginfo to figure out what `language` to put in the `producers` section. * Threaded WebAssembly code now requires different flags to be passed with LLD. In LLD we now pass: * `--shared-memory` - required since objects are compiled with atomics. This also means that the generated memory will be marked as `shared`. * `--max-memory=1GB` - required with the `--shared-memory` argument since shared memories in WebAssembly must have a maximum size. The 1GB number is intended to be a conservative estimate for rustc, but it should be overridable with `-C link-arg` if necessary. * `--passive-segments` - this has become the default for multithreaded memory, but when compiling a threaded module all data segments need to be marked as passive to ensure they don't re-initialize memory for each thread. This will also cause LLD to emit a synthetic function to initialize memory which users will have to arrange to call. * The `__heap_base` and `__data_end` globals are explicitly exported since they're now hidden by default due to the `--export` flags we pass to LLD.
2 parents c7312fe + dc50a63 commit 778b631

File tree

14 files changed

+131
-338
lines changed

14 files changed

+131
-338
lines changed

src/librustc_codegen_llvm/debuginfo/metadata.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -913,9 +913,12 @@ pub fn compile_unit_metadata(
913913
}
914914

915915
debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
916+
let rustc_producer = format!(
917+
"rustc version {}",
918+
option_env!("CFG_VERSION").expect("CFG_VERSION"),
919+
);
916920
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
917-
let producer = format!("clang LLVM (rustc version {})",
918-
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
921+
let producer = format!("clang LLVM ({})", rustc_producer);
919922

920923
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
921924
let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
@@ -980,6 +983,21 @@ pub fn compile_unit_metadata(
980983
gcov_metadata);
981984
}
982985

986+
// Insert `llvm.ident` metadata on the wasm32 targets since that will
987+
// get hooked up to the "producer" sections `processed-by` information.
988+
if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
989+
let name_metadata = llvm::LLVMMDStringInContext(
990+
debug_context.llcontext,
991+
rustc_producer.as_ptr() as *const _,
992+
rustc_producer.as_bytes().len() as c_uint,
993+
);
994+
llvm::LLVMAddNamedMetadataOperand(
995+
debug_context.llmod,
996+
const_cstr!("llvm.ident").as_ptr(),
997+
llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
998+
);
999+
}
1000+
9831001
return unit_metadata;
9841002
};
9851003

src/librustc_codegen_ssa/back/link.rs

-8
Original file line numberDiff line numberDiff line change
@@ -678,14 +678,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
678678
sess.fatal(&format!("failed to run dsymutil: {}", e))
679679
}
680680
}
681-
682-
if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" {
683-
super::wasm::add_producer_section(
684-
&out_filename,
685-
&sess.edition().to_string(),
686-
option_env!("CFG_VERSION").unwrap_or("unknown"),
687-
);
688-
}
689681
}
690682

691683
/// Returns a boolean indicating whether the specified crate should be ignored

src/librustc_codegen_ssa/back/linker.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,45 @@ pub struct WasmLd<'a> {
901901
}
902902

903903
impl<'a> WasmLd<'a> {
904-
fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
904+
fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
905+
// If the atomics feature is enabled for wasm then we need a whole bunch
906+
// of flags:
907+
//
908+
// * `--shared-memory` - the link won't even succeed without this, flags
909+
// the one linear memory as `shared`
910+
//
911+
// * `--max-memory=1G` - when specifying a shared memory this must also
912+
// be specified. We conservatively choose 1GB but users should be able
913+
// to override this with `-C link-arg`.
914+
//
915+
// * `--import-memory` - it doesn't make much sense for memory to be
916+
// exported in a threaded module because typically you're
917+
// sharing memory and instantiating the module multiple times. As a
918+
// result if it were exported then we'd just have no sharing.
919+
//
920+
// * `--passive-segments` - all memory segments should be passive to
921+
// prevent each module instantiation from reinitializing memory.
922+
//
923+
// * `--export=__wasm_init_memory` - when using `--passive-segments` the
924+
// linker will synthesize this function, and so we need to make sure
925+
// that our usage of `--export` below won't accidentally cause this
926+
// function to get deleted.
927+
//
928+
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
929+
// symbols are how the TLS segments are initialized and configured.
930+
let atomics = sess.opts.cg.target_feature.contains("+atomics") ||
931+
sess.target.target.options.features.contains("+atomics");
932+
if atomics {
933+
cmd.arg("--shared-memory");
934+
cmd.arg("--max-memory=1073741824");
935+
cmd.arg("--import-memory");
936+
cmd.arg("--passive-segments");
937+
cmd.arg("--export=__wasm_init_memory");
938+
cmd.arg("--export=__wasm_init_tls");
939+
cmd.arg("--export=__tls_size");
940+
cmd.arg("--export=__tls_align");
941+
cmd.arg("--export=__tls_base");
942+
}
905943
WasmLd { cmd, sess, info }
906944
}
907945
}
@@ -1004,6 +1042,13 @@ impl<'a> Linker for WasmLd<'a> {
10041042
for sym in self.info.exports[&crate_type].iter() {
10051043
self.cmd.arg("--export").arg(&sym);
10061044
}
1045+
1046+
// LLD will hide these otherwise-internal symbols since our `--export`
1047+
// list above is a whitelist of what to export. Various bits and pieces
1048+
// of tooling use this, so be sure these symbols make their way out of
1049+
// the linker as well.
1050+
self.cmd.arg("--export=__heap_base");
1051+
self.cmd.arg("--export=__data_end");
10071052
}
10081053

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

src/librustc_codegen_ssa/back/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@ pub mod command;
66
pub mod symbol_export;
77
pub mod archive;
88
pub mod rpath;
9-
pub mod wasm;

src/librustc_codegen_ssa/back/wasm.rs

-191
This file was deleted.

src/librustc_target/spec/wasm32_base.rs

+8
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ pub fn options() -> TargetOptions {
132132
// non-relative calls and such later on).
133133
relocation_model: "static".to_string(),
134134

135+
// When the atomics feature is activated then these two keys matter,
136+
// otherwise they're basically ignored by the standard library. In this
137+
// mode, however, the `#[thread_local]` attribute works (i.e.
138+
// `has_elf_tls`) and we need to get it to work by specifying
139+
// `local-exec` as that's all that's implemented in LLVM today for wasm.
140+
has_elf_tls: true,
141+
tls_model: "local-exec".to_string(),
142+
135143
.. Default::default()
136144
}
137145
}

src/libstd/Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ panic_immediate_abort = ["core/panic_immediate_abort"]
7575
# requires rebuilding the standard library to use it.
7676
wasm_syscall = []
7777

78-
# An off-by-default features to enable libstd to assume that wasm-bindgen is in
79-
# the environment for hooking up some thread-related information like the
80-
# current thread id and accessing/getting the current thread's TCB
81-
wasm-bindgen-threads = []
82-
8378
# Enable std_detect default features for stdarch/crates/std_detect:
8479
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
8580
std_detect_file_io = []

src/libstd/sys/wasi/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub mod stdio;
4747
pub mod thread;
4848
#[path = "../wasm/thread_local.rs"]
4949
pub mod thread_local;
50+
#[path = "../wasm/fast_thread_local.rs"]
51+
pub mod fast_thread_local;
5052
pub mod time;
5153
pub mod ext;
5254

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![unstable(feature = "thread_local_internals", issue = "0")]
2+
3+
pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) {
4+
// FIXME: right now there is no concept of "thread exit", but this is likely
5+
// going to show up at some point in the form of an exported symbol that the
6+
// wasm runtime is oging to be expected to call. For now we basically just
7+
// ignore the arguments, but if such a function starts to exist it will
8+
// likely look like the OSX implementation in `unix/fast_thread_local.rs`
9+
}

src/libstd/sys/wasm/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub mod stack_overflow;
3737
pub mod thread;
3838
pub mod time;
3939
pub mod stdio;
40+
pub mod thread_local;
41+
pub mod fast_thread_local;
4042

4143
pub use crate::sys_common::os_str_bytes as os_str;
4244

@@ -48,13 +50,10 @@ cfg_if::cfg_if! {
4850
pub mod mutex;
4951
#[path = "rwlock_atomics.rs"]
5052
pub mod rwlock;
51-
#[path = "thread_local_atomics.rs"]
52-
pub mod thread_local;
5353
} else {
5454
pub mod condvar;
5555
pub mod mutex;
5656
pub mod rwlock;
57-
pub mod thread_local;
5857
}
5958
}
6059

0 commit comments

Comments
 (0)