|
| 1 | +use std::collections::BTreeMap; |
| 2 | +use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor}; |
| 3 | + |
| 4 | +pub fn options() -> TargetOptions { |
| 5 | + let mut lld_args = Vec::new(); |
| 6 | + let mut clang_args = Vec::new(); |
| 7 | + let mut arg = |arg: &str| { |
| 8 | + lld_args.push(arg.to_string()); |
| 9 | + clang_args.push(format!("-Wl,{}", arg)); |
| 10 | + }; |
| 11 | + |
| 12 | + // There have been reports in the wild (rustwasm/wasm-bindgen#119) of |
| 13 | + // using threads causing weird hangs and bugs. Disable it entirely as |
| 14 | + // this isn't yet the bottleneck of compilation at all anyway. |
| 15 | + // |
| 16 | + // FIXME: we should file an upstream issue with LLD about this |
| 17 | + arg("--no-threads"); |
| 18 | + |
| 19 | + // By default LLD only gives us one page of stack (64k) which is a |
| 20 | + // little small. Default to a larger stack closer to other PC platforms |
| 21 | + // (1MB) and users can always inject their own link-args to override this. |
| 22 | + arg("-z"); |
| 23 | + arg("stack-size=1048576"); |
| 24 | + |
| 25 | + // By default LLD's memory layout is: |
| 26 | + // |
| 27 | + // 1. First, a blank page |
| 28 | + // 2. Next, all static data |
| 29 | + // 3. Finally, the main stack (which grows down) |
| 30 | + // |
| 31 | + // This has the unfortunate consequence that on stack overflows you |
| 32 | + // corrupt static data and can cause some exceedingly weird bugs. To |
| 33 | + // help detect this a little sooner we instead request that the stack is |
| 34 | + // placed before static data. |
| 35 | + // |
| 36 | + // This means that we'll generate slightly larger binaries as references |
| 37 | + // to static data will take more bytes in the ULEB128 encoding, but |
| 38 | + // stack overflow will be guaranteed to trap as it underflows instead of |
| 39 | + // corrupting static data. |
| 40 | + arg("--stack-first"); |
| 41 | + |
| 42 | + // FIXME we probably shouldn't pass this but instead pass an explicit |
| 43 | + // whitelist of symbols we'll allow to be undefined. We don't currently have |
| 44 | + // a mechanism of knowing, however, which symbols are intended to be |
| 45 | + // imported from the environment and which are intended to be imported from |
| 46 | + // other objects linked elsewhere. This is a coarse approximation but is |
| 47 | + // sure to hide some bugs and frustrate someone at some point, so we should |
| 48 | + // ideally work towards a world where we can explicitly list symbols that |
| 49 | + // are supposed to be imported and have all other symbols generate errors if |
| 50 | + // they remain undefined. |
| 51 | + arg("--allow-undefined"); |
| 52 | + |
| 53 | + // Rust code should never have warnings, and warnings are often |
| 54 | + // indicative of bugs, let's prevent them. |
| 55 | + arg("--fatal-warnings"); |
| 56 | + |
| 57 | + // LLD only implements C++-like demangling, which doesn't match our own |
| 58 | + // mangling scheme. Tell LLD to not demangle anything and leave it up to |
| 59 | + // us to demangle these symbols later. Currently rustc does not perform |
| 60 | + // further demangling, but tools like twiggy and wasm-bindgen are intended |
| 61 | + // to do so. |
| 62 | + arg("--no-demangle"); |
| 63 | + |
| 64 | + // The symbol visibility story is a bit in flux right now with LLD. |
| 65 | + // It's... not entirely clear to me what's going on, but this looks to |
| 66 | + // make everything work when `export_symbols` isn't otherwise called for |
| 67 | + // things like executables. |
| 68 | + // |
| 69 | + // This is really only here to get things working. If it can be removed and |
| 70 | + // basic tests still work, then sounds like it should be removed! |
| 71 | + arg("--export-dynamic"); |
| 72 | + |
| 73 | + let mut pre_link_args = BTreeMap::new(); |
| 74 | + pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args); |
| 75 | + pre_link_args.insert(LinkerFlavor::Gcc, clang_args); |
| 76 | + |
| 77 | + TargetOptions { |
| 78 | + // we allow dynamic linking, but only cdylibs. Basically we allow a |
| 79 | + // final library artifact that exports some symbols (a wasm module) but |
| 80 | + // we don't allow intermediate `dylib` crate types |
| 81 | + dynamic_linking: true, |
| 82 | + only_cdylib: true, |
| 83 | + |
| 84 | + // This means we'll just embed a `start` function in the wasm module |
| 85 | + executables: true, |
| 86 | + |
| 87 | + // relatively self-explanatory! |
| 88 | + exe_suffix: ".wasm".to_string(), |
| 89 | + dll_prefix: String::new(), |
| 90 | + dll_suffix: ".wasm".to_string(), |
| 91 | + linker_is_gnu: false, |
| 92 | + |
| 93 | + max_atomic_width: Some(64), |
| 94 | + |
| 95 | + // Unwinding doesn't work right now, so the whole target unconditionally |
| 96 | + // defaults to panic=abort. Note that this is guaranteed to change in |
| 97 | + // the future once unwinding is implemented. Don't rely on this as we're |
| 98 | + // basically guaranteed to change it once WebAssembly supports |
| 99 | + // exceptions. |
| 100 | + panic_strategy: PanicStrategy::Abort, |
| 101 | + |
| 102 | + // Wasm doesn't have atomics yet, so tell LLVM that we're in a single |
| 103 | + // threaded model which will legalize atomics to normal operations. |
| 104 | + singlethread: true, |
| 105 | + |
| 106 | + // no dynamic linking, no need for default visibility! |
| 107 | + default_hidden_visibility: true, |
| 108 | + |
| 109 | + // we use the LLD shipped with the Rust toolchain by default |
| 110 | + linker: Some("rust-lld".to_owned()), |
| 111 | + lld_flavor: LldFlavor::Wasm, |
| 112 | + |
| 113 | + // No need for indirection here, simd types can always be passed by |
| 114 | + // value as the whole module either has simd or not, which is different |
| 115 | + // from x86 (for example) where programs can have functions that don't |
| 116 | + // enable simd features. |
| 117 | + simd_types_indirect: false, |
| 118 | + |
| 119 | + pre_link_args, |
| 120 | + |
| 121 | + .. Default::default() |
| 122 | + } |
| 123 | +} |
0 commit comments