about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs77
-rw-r--r--src/librustc_target/spec/mod.rs1
-rw-r--r--src/librustc_target/spec/wasm32_base.rs123
-rw-r--r--src/librustc_target/spec/wasm32_unknown_unknown.rs80
4 files changed, 174 insertions, 107 deletions
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 244505976b6..c99fc17dd89 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -160,7 +160,16 @@ impl<'a> GccLinker<'a> {
     }
 
     fn takes_hints(&self) -> bool {
-        !self.sess.target.target.options.is_like_osx
+        // Really this function only returns true if the underlying linker
+        // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We
+        // don't really have a foolproof way to detect that, so rule out some
+        // platforms where currently this is guaranteed to *not* be the case:
+        //
+        // * On OSX they have their own linker, not binutils'
+        // * For WebAssembly the only functional linker is LLD, which doesn't
+        //   support hint flags
+        !self.sess.target.target.options.is_like_osx &&
+            self.sess.target.target.arch != "wasm32"
     }
 
     // Some platforms take hints about whether a library is static or dynamic.
@@ -375,6 +384,13 @@ impl<'a> Linker for GccLinker<'a> {
             return
         }
 
+        // Symbol visibility takes care of this for the WebAssembly.
+        // Additionally the only known linker, LLD, doesn't support the script
+        // arguments just yet
+        if self.sess.target.target.arch == "wasm32" {
+            return;
+        }
+
         let mut arg = OsString::new();
         let path = tmpdir.join("list");
 
@@ -441,13 +457,13 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn group_start(&mut self) {
-        if !self.sess.target.target.options.is_like_osx {
+        if self.takes_hints() {
             self.linker_arg("--start-group");
         }
     }
 
     fn group_end(&mut self) {
-        if !self.sess.target.target.options.is_like_osx {
+        if self.takes_hints() {
             self.linker_arg("--end-group");
         }
     }
@@ -862,59 +878,7 @@ pub struct WasmLd<'a> {
 }
 
 impl<'a> WasmLd<'a> {
-    fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
-        // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
-        // using threads causing weird hangs and bugs. Disable it entirely as
-        // this isn't yet the bottleneck of compilation at all anyway.
-        cmd.arg("--no-threads");
-
-        // By default LLD only gives us one page of stack (64k) which is a
-        // little small. Default to a larger stack closer to other PC platforms
-        // (1MB) and users can always inject their own link-args to override this.
-        cmd.arg("-z").arg("stack-size=1048576");
-
-        // By default LLD's memory layout is:
-        //
-        // 1. First, a blank page
-        // 2. Next, all static data
-        // 3. Finally, the main stack (which grows down)
-        //
-        // This has the unfortunate consequence that on stack overflows you
-        // corrupt static data and can cause some exceedingly weird bugs. To
-        // help detect this a little sooner we instead request that the stack is
-        // placed before static data.
-        //
-        // This means that we'll generate slightly larger binaries as references
-        // to static data will take more bytes in the ULEB128 encoding, but
-        // stack overflow will be guaranteed to trap as it underflows instead of
-        // corrupting static data.
-        cmd.arg("--stack-first");
-
-        // FIXME we probably shouldn't pass this but instead pass an explicit
-        // whitelist of symbols we'll allow to be undefined. Unfortunately
-        // though we can't handle symbols like `log10` that LLVM injects at a
-        // super late date without actually parsing object files. For now let's
-        // stick to this and hopefully fix it before stabilization happens.
-        cmd.arg("--allow-undefined");
-
-        // For now we just never have an entry symbol
-        cmd.arg("--no-entry");
-
-        // Rust code should never have warnings, and warnings are often
-        // indicative of bugs, let's prevent them.
-        cmd.arg("--fatal-warnings");
-
-        // The symbol visibility story is a bit in flux right now with LLD.
-        // It's... not entirely clear to me what's going on, but this looks to
-        // make everything work when `export_symbols` isn't otherwise called for
-        // things like executables.
-        cmd.arg("--export-dynamic");
-
-        // LLD only implements C++-like demangling, which doesn't match our own
-        // mangling scheme. Tell LLD to not demangle anything and leave it up to
-        // us to demangle these symbols later.
-        cmd.arg("--no-demangle");
-
+    fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
         WasmLd { cmd, sess, info }
     }
 }
@@ -1010,6 +974,7 @@ impl<'a> Linker for WasmLd<'a> {
     }
 
     fn build_dylib(&mut self, _out_filename: &Path) {
+        self.cmd.arg("--no-entry");
     }
 
     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index fdb1db645c3..401b81ee987 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -66,6 +66,7 @@ mod l4re_base;
 mod fuchsia_base;
 mod redox_base;
 mod riscv_base;
+mod wasm32_base;
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
          RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs
new file mode 100644
index 00000000000..c7e75b4fa09
--- /dev/null
+++ b/src/librustc_target/spec/wasm32_base.rs
@@ -0,0 +1,123 @@
+use std::collections::BTreeMap;
+use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor};
+
+pub fn options() -> TargetOptions {
+    let mut lld_args = Vec::new();
+    let mut clang_args = Vec::new();
+    let mut arg = |arg: &str| {
+        lld_args.push(arg.to_string());
+        clang_args.push(format!("-Wl,{}", arg));
+    };
+
+    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
+    // using threads causing weird hangs and bugs. Disable it entirely as
+    // this isn't yet the bottleneck of compilation at all anyway.
+    //
+    // FIXME: we should file an upstream issue with LLD about this
+    arg("--no-threads");
+
+    // By default LLD only gives us one page of stack (64k) which is a
+    // little small. Default to a larger stack closer to other PC platforms
+    // (1MB) and users can always inject their own link-args to override this.
+    arg("-z");
+    arg("stack-size=1048576");
+
+    // By default LLD's memory layout is:
+    //
+    // 1. First, a blank page
+    // 2. Next, all static data
+    // 3. Finally, the main stack (which grows down)
+    //
+    // This has the unfortunate consequence that on stack overflows you
+    // corrupt static data and can cause some exceedingly weird bugs. To
+    // help detect this a little sooner we instead request that the stack is
+    // placed before static data.
+    //
+    // This means that we'll generate slightly larger binaries as references
+    // to static data will take more bytes in the ULEB128 encoding, but
+    // stack overflow will be guaranteed to trap as it underflows instead of
+    // corrupting static data.
+    arg("--stack-first");
+
+    // FIXME we probably shouldn't pass this but instead pass an explicit
+    // whitelist of symbols we'll allow to be undefined. We don't currently have
+    // a mechanism of knowing, however, which symbols are intended to be
+    // imported from the environment and which are intended to be imported from
+    // other objects linked elsewhere. This is a coarse approximation but is
+    // sure to hide some bugs and frustrate someone at some point, so we should
+    // ideally work towards a world where we can explicitly list symbols that
+    // are supposed to be imported and have all other symbols generate errors if
+    // they remain undefined.
+    arg("--allow-undefined");
+
+    // Rust code should never have warnings, and warnings are often
+    // indicative of bugs, let's prevent them.
+    arg("--fatal-warnings");
+
+    // LLD only implements C++-like demangling, which doesn't match our own
+    // mangling scheme. Tell LLD to not demangle anything and leave it up to
+    // us to demangle these symbols later. Currently rustc does not perform
+    // further demangling, but tools like twiggy and wasm-bindgen are intended
+    // to do so.
+    arg("--no-demangle");
+
+    // The symbol visibility story is a bit in flux right now with LLD.
+    // It's... not entirely clear to me what's going on, but this looks to
+    // make everything work when `export_symbols` isn't otherwise called for
+    // things like executables.
+    //
+    // This is really only here to get things working. If it can be removed and
+    // basic tests still work, then sounds like it should be removed!
+    arg("--export-dynamic");
+
+    let mut pre_link_args = BTreeMap::new();
+    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
+    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);
+
+    TargetOptions {
+        // we allow dynamic linking, but only cdylibs. Basically we allow a
+        // final library artifact that exports some symbols (a wasm module) but
+        // we don't allow intermediate `dylib` crate types
+        dynamic_linking: true,
+        only_cdylib: true,
+
+        // This means we'll just embed a `start` function in the wasm module
+        executables: true,
+
+        // relatively self-explanatory!
+        exe_suffix: ".wasm".to_string(),
+        dll_prefix: String::new(),
+        dll_suffix: ".wasm".to_string(),
+        linker_is_gnu: false,
+
+        max_atomic_width: Some(64),
+
+        // Unwinding doesn't work right now, so the whole target unconditionally
+        // defaults to panic=abort. Note that this is guaranteed to change in
+        // the future once unwinding is implemented. Don't rely on this as we're
+        // basically guaranteed to change it once WebAssembly supports
+        // exceptions.
+        panic_strategy: PanicStrategy::Abort,
+
+        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
+        // threaded model which will legalize atomics to normal operations.
+        singlethread: true,
+
+        // no dynamic linking, no need for default visibility!
+        default_hidden_visibility: true,
+
+        // we use the LLD shipped with the Rust toolchain by default
+        linker: Some("rust-lld".to_owned()),
+        lld_flavor: LldFlavor::Wasm,
+
+        // No need for indirection here, simd types can always be passed by
+        // value as the whole module either has simd or not, which is different
+        // from x86 (for example) where programs can have functions that don't
+        // enable simd features.
+        simd_types_indirect: false,
+
+        pre_link_args,
+
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_target/spec/wasm32_unknown_unknown.rs b/src/librustc_target/spec/wasm32_unknown_unknown.rs
index ee2160c4720..909527d2b61 100644
--- a/src/librustc_target/spec/wasm32_unknown_unknown.rs
+++ b/src/librustc_target/spec/wasm32_unknown_unknown.rs
@@ -1,70 +1,48 @@
-// The wasm32-unknown-unknown target is currently an experimental version of a
-// wasm-based target which does *not* use the Emscripten toolchain. Instead
-// this toolchain is based purely on LLVM's own toolchain, using LLVM's native
-// WebAssembly backend as well as LLD for a native linker.
-//
-// There's some trickery below on crate types supported and various defaults
-// (aka panic=abort by default), but otherwise this is in general a relatively
-// standard target.
-
-use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy};
+//! A "bare wasm" target representing a WebAssembly output that makes zero
+//! assumptions about its environment.
+//!
+//! The `wasm32-unknown-unknown` target is intended to encapsulate use cases
+//! that do not rely on any imported functionality. The binaries generated are
+//! entirely self-contained by default when using the standard library. Although
+//! the standard library is available, most of it returns an error immediately
+//! (e.g. trying to create a TCP stream or something like that).
+//!
+//! This target is more or less managed by the Rust and WebAssembly Working
+//! Group nowadays at https://github.com/rustwasm.
+
+use super::{LldFlavor, LinkerFlavor, Target};
+use super::wasm32_base;
 
 pub fn target() -> Result<Target, String> {
-    let opts = TargetOptions {
-        // we allow dynamic linking, but only cdylibs. Basically we allow a
-        // final library artifact that exports some symbols (a wasm module) but
-        // we don't allow intermediate `dylib` crate types
-        dynamic_linking: true,
-        only_cdylib: true,
-
-        // This means we'll just embed a `start` function in the wasm module
-        executables: true,
-
-        // relatively self-explanatory!
-        exe_suffix: ".wasm".to_string(),
-        dll_prefix: String::new(),
-        dll_suffix: ".wasm".to_string(),
-        linker_is_gnu: false,
-
-        max_atomic_width: Some(64),
-
-        // Unwinding doesn't work right now, so the whole target unconditionally
-        // defaults to panic=abort. Note that this is guaranteed to change in
-        // the future once unwinding is implemented. Don't rely on this.
-        panic_strategy: PanicStrategy::Abort,
-
-        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
-        // threaded model which will legalize atomics to normal operations.
-        singlethread: true,
+    let mut options = wasm32_base::options();
+    let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
 
-        // no dynamic linking, no need for default visibility!
-        default_hidden_visibility: true,
+    // Make sure clang uses LLD as its linker and is configured appropriately
+    // otherwise
+    clang_args.push("--target=wasm32-unknown-unknown".to_string());
 
-        // we use the LLD shipped with the Rust toolchain by default
-        linker: Some("rust-lld".to_owned()),
-        lld_flavor: LldFlavor::Wasm,
+    // Disable attempting to link crt1.o since it typically isn't present and
+    // isn't needed currently.
+    clang_args.push("-nostdlib".to_string());
 
-        // No need for indirection here, simd types can always be passed by
-        // value as the whole module either has simd or not, which is different
-        // from x86 (for example) where programs can have functions that don't
-        // enable simd features.
-        simd_types_indirect: false,
+    // For now this target just never has an entry symbol no matter the output
+    // type, so unconditionally pass this.
+    clang_args.push("-Wl,--no-entry".to_string());
+    options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm))
+        .unwrap()
+        .push("--no-entry".to_string());
 
-        .. Default::default()
-    };
     Ok(Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
-        // This is basically guaranteed to change in the future, don't rely on
-        // this. Use `not(target_os = "emscripten")` for now.
         target_os: "unknown".to_string(),
         target_env: String::new(),
         target_vendor: "unknown".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
-        options: opts,
+        options,
     })
 }