diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-07-29 02:10:52 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-07-29 02:10:52 +0200 |
| commit | 778b631ff06c463fad290ea8ff8f2817ab62a5fd (patch) | |
| tree | 45b3e2a9c745e5c6956b9556c011c899285a6bdc /src/librustc_codegen_ssa | |
| parent | c7312fe4ff85ada30103cea58db25d83e0bec4b0 (diff) | |
| parent | dc50a633f3260a3aeb79a4ca9800587be7f732e7 (diff) | |
| download | rust-778b631ff06c463fad290ea8ff8f2817ab62a5fd.tar.gz rust-778b631ff06c463fad290ea8ff8f2817ab62a5fd.zip | |
Rollup merge of #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.
Diffstat (limited to 'src/librustc_codegen_ssa')
| -rw-r--r-- | src/librustc_codegen_ssa/back/link.rs | 8 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/back/linker.rs | 47 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/back/mod.rs | 1 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/back/wasm.rs | 191 |
4 files changed, 46 insertions, 201 deletions
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 707b7cae16c..3f6a1a72ea6 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -678,14 +678,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, sess.fatal(&format!("failed to run dsymutil: {}", e)) } } - - if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { - super::wasm::add_producer_section( - &out_filename, - &sess.edition().to_string(), - option_env!("CFG_VERSION").unwrap_or("unknown"), - ); - } } /// Returns a boolean indicating whether the specified crate should be ignored diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index cb8870d0be9..26091005f25 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -901,7 +901,45 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { + fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { + // If the atomics feature is enabled for wasm then we need a whole bunch + // of flags: + // + // * `--shared-memory` - the link won't even succeed without this, flags + // the one linear memory as `shared` + // + // * `--max-memory=1G` - when specifying a shared memory this must also + // be specified. We conservatively choose 1GB but users should be able + // to override this with `-C link-arg`. + // + // * `--import-memory` - it doesn't make much sense for memory to be + // exported in a threaded module because typically you're + // sharing memory and instantiating the module multiple times. As a + // result if it were exported then we'd just have no sharing. + // + // * `--passive-segments` - all memory segments should be passive to + // prevent each module instantiation from reinitializing memory. + // + // * `--export=__wasm_init_memory` - when using `--passive-segments` the + // linker will synthesize this function, and so we need to make sure + // that our usage of `--export` below won't accidentally cause this + // function to get deleted. + // + // * `--export=*tls*` - when `#[thread_local]` symbols are used these + // symbols are how the TLS segments are initialized and configured. + let atomics = sess.opts.cg.target_feature.contains("+atomics") || + sess.target.target.options.features.contains("+atomics"); + if atomics { + cmd.arg("--shared-memory"); + cmd.arg("--max-memory=1073741824"); + cmd.arg("--import-memory"); + cmd.arg("--passive-segments"); + cmd.arg("--export=__wasm_init_memory"); + cmd.arg("--export=__wasm_init_tls"); + cmd.arg("--export=__tls_size"); + cmd.arg("--export=__tls_align"); + cmd.arg("--export=__tls_base"); + } WasmLd { cmd, sess, info } } } @@ -1004,6 +1042,13 @@ impl<'a> Linker for WasmLd<'a> { for sym in self.info.exports[&crate_type].iter() { self.cmd.arg("--export").arg(&sym); } + + // LLD will hide these otherwise-internal symbols since our `--export` + // list above is a whitelist of what to export. Various bits and pieces + // of tooling use this, so be sure these symbols make their way out of + // the linker as well. + self.cmd.arg("--export=__heap_base"); + self.cmd.arg("--export=__data_end"); } fn subsystem(&mut self, _subsystem: &str) { diff --git a/src/librustc_codegen_ssa/back/mod.rs b/src/librustc_codegen_ssa/back/mod.rs index a16d099ee3e..901891d85a4 100644 --- a/src/librustc_codegen_ssa/back/mod.rs +++ b/src/librustc_codegen_ssa/back/mod.rs @@ -6,4 +6,3 @@ pub mod command; pub mod symbol_export; pub mod archive; pub mod rpath; -pub mod wasm; diff --git a/src/librustc_codegen_ssa/back/wasm.rs b/src/librustc_codegen_ssa/back/wasm.rs deleted file mode 100644 index 2a9e81a788e..00000000000 --- a/src/librustc_codegen_ssa/back/wasm.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::fs; -use std::path::Path; -use std::str; - -use rustc_serialize::leb128; - -// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec -const WASM_CUSTOM_SECTION_ID: u8 = 0; - -/// Adds or augment the existing `producers` section to encode information about -/// the Rust compiler used to produce the wasm file. -pub fn add_producer_section( - path: &Path, - rust_version: &str, - rustc_version: &str, -) { - struct Field<'a> { - name: &'a str, - values: Vec<FieldValue<'a>>, - } - - #[derive(Copy, Clone)] - struct FieldValue<'a> { - name: &'a str, - version: &'a str, - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - let mut ret = WasmEncoder::new(); - ret.data.extend(&wasm[..8]); - - // skip the 8 byte wasm/version header - let rustc_value = FieldValue { - name: "rustc", - version: rustc_version, - }; - let rust_value = FieldValue { - name: "Rust", - version: rust_version, - }; - let mut fields = Vec::new(); - let mut wrote_rustc = false; - let mut wrote_rust = false; - - // Move all sections from the original wasm file to our output, skipping - // everything except the producers section - for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) { - if id != WASM_CUSTOM_SECTION_ID { - ret.byte(id); - ret.bytes(raw); - continue - } - let mut decoder = WasmDecoder::new(raw); - if decoder.str() != "producers" { - ret.byte(id); - ret.bytes(raw); - continue - } - - // Read off the producers section into our fields outside the loop, - // we'll re-encode the producers section when we're done (to handle an - // entirely missing producers section as well). - info!("rewriting existing producers section"); - - for _ in 0..decoder.u32() { - let name = decoder.str(); - let mut values = Vec::new(); - for _ in 0..decoder.u32() { - let name = decoder.str(); - let version = decoder.str(); - values.push(FieldValue { name, version }); - } - - if name == "language" { - values.push(rust_value); - wrote_rust = true; - } else if name == "processed-by" { - values.push(rustc_value); - wrote_rustc = true; - } - fields.push(Field { name, values }); - } - } - - if !wrote_rust { - fields.push(Field { - name: "language", - values: vec![rust_value], - }); - } - if !wrote_rustc { - fields.push(Field { - name: "processed-by", - values: vec![rustc_value], - }); - } - - // Append the producers section to the end of the wasm file. - let mut section = WasmEncoder::new(); - section.str("producers"); - section.u32(fields.len() as u32); - for field in fields { - section.str(field.name); - section.u32(field.values.len() as u32); - for value in field.values { - section.str(value.name); - section.str(value.version); - } - } - ret.byte(WASM_CUSTOM_SECTION_ID); - ret.bytes(§ion.data); - - fs::write(path, &ret.data).expect("failed to write wasm output"); -} - -struct WasmSections<'a>(WasmDecoder<'a>); - -impl<'a> Iterator for WasmSections<'a> { - type Item = (u8, &'a [u8]); - - fn next(&mut self) -> Option<(u8, &'a [u8])> { - if self.0.data.is_empty() { - return None - } - - // see https://webassembly.github.io/spec/core/binary/modules.html#sections - let id = self.0.byte(); - let section_len = self.0.u32(); - info!("new section {} / {} bytes", id, section_len); - let section = self.0.skip(section_len as usize); - Some((id, section)) - } -} - -struct WasmDecoder<'a> { - data: &'a [u8], -} - -impl<'a> WasmDecoder<'a> { - fn new(data: &'a [u8]) -> WasmDecoder<'a> { - WasmDecoder { data } - } - - fn byte(&mut self) -> u8 { - self.skip(1)[0] - } - - fn u32(&mut self) -> u32 { - let (n, l1) = leb128::read_u32_leb128(self.data); - self.data = &self.data[l1..]; - return n - } - - fn skip(&mut self, amt: usize) -> &'a [u8] { - let (data, rest) = self.data.split_at(amt); - self.data = rest; - data - } - - fn str(&mut self) -> &'a str { - let len = self.u32(); - str::from_utf8(self.skip(len as usize)).unwrap() - } -} - -struct WasmEncoder { - data: Vec<u8>, -} - -impl WasmEncoder { - fn new() -> WasmEncoder { - WasmEncoder { data: Vec::new() } - } - - fn u32(&mut self, val: u32) { - leb128::write_u32_leb128(&mut self.data, val); - } - - fn byte(&mut self, val: u8) { - self.data.push(val); - } - - fn bytes(&mut self, val: &[u8]) { - self.u32(val.len() as u32); - self.data.extend_from_slice(val); - } - - fn str(&mut self, val: &str) { - self.bytes(val.as_bytes()) - } -} |
