diff -Nru rustc-1.26.0+dfsg0+llvm/debian/changelog rustc-1.26.1+dfsg0+llvm/debian/changelog --- rustc-1.26.0+dfsg0+llvm/debian/changelog 2018-06-01 14:40:50.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/debian/changelog 2018-06-01 15:10:34.000000000 +0000 @@ -1,3 +1,12 @@ +rustc (1.26.1+dfsg0+llvm-0ubuntu1) cosmic; urgency=medium + + * Update to 1.26.1 + * Exclude src/tools/lld from the tarball + - update debian/copyright + - update debian/rules + + -- Chris Coulson Fri, 01 Jun 2018 16:10:34 +0100 + rustc (1.26.0+dfsg0+llvm-0ubuntu3) cosmic; urgency=medium * Backport 'Fix "fp" feature for AArch64', as the console warnings appear diff -Nru rustc-1.26.0+dfsg0+llvm/debian/copyright rustc-1.26.1+dfsg0+llvm/debian/copyright --- rustc-1.26.0+dfsg0+llvm/debian/copyright 2018-06-01 14:40:50.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/debian/copyright 2018-06-01 15:10:34.000000000 +0000 @@ -17,6 +17,7 @@ # cargo's own test suite (in its own package) also called cargotest. # NB: don't exclude rust-installer, it's needed for "install" functionality src/tools/cargo + src/tools/lld src/tools/rls src/tools/rustfmt src/tools/miri @@ -36,7 +37,6 @@ src/vendor/bitflags-0.7.0 src/vendor/bufstream src/vendor/cargo_metadata-0.2.3 - src/vendor/clippy_lints src/vendor/commoncrypto src/vendor/commoncrypto-sys src/vendor/core-foundation diff -Nru rustc-1.26.0+dfsg0+llvm/debian/rules rustc-1.26.1+dfsg0+llvm/debian/rules --- rustc-1.26.0+dfsg0+llvm/debian/rules 2018-06-01 14:40:50.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/debian/rules 2018-06-01 15:10:34.000000000 +0000 @@ -284,8 +284,6 @@ $(RM) -rf $(SRC_CLEAN:%=debian/rust-src/usr/src/rustc-$(RUST_LONG_VERSION)/%) # Get rid of src/llvm $(RM) -rf debian/rust-src/usr/src/rustc-$(RUST_LONG_VERSION)/src/llvm - # XXX(chrisccoulson): Drop this when we have an updated source tarball with it removed - $(RM) -rf debian/rust-src/usr/src/rustc-$(RUST_LONG_VERSION)/src/tools/lld # Get rid of lintian warnings find debian/rust-src/usr/src/rustc-$(RUST_LONG_VERSION) \ \( -name .gitignore \ diff -Nru rustc-1.26.0+dfsg0+llvm/git-commit-hash rustc-1.26.1+dfsg0+llvm/git-commit-hash --- rustc-1.26.0+dfsg0+llvm/git-commit-hash 2018-05-07 18:44:36.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/git-commit-hash 2018-05-25 20:03:09.000000000 +0000 @@ -1 +1 @@ -a7756804103447ea4e68a71ccf071e7ad8f7a03e \ No newline at end of file +827013a31b88e536e85b8e6ceb5b9988042ec335 \ No newline at end of file diff -Nru rustc-1.26.0+dfsg0+llvm/RELEASES.md rustc-1.26.1+dfsg0+llvm/RELEASES.md --- rustc-1.26.0+dfsg0+llvm/RELEASES.md 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/RELEASES.md 2018-05-25 18:31:50.000000000 +0000 @@ -1,3 +1,233 @@ +Version 1.26.1 (2018-05-29) +========================== + +Tools +----- + +- [RLS now works on Windows][50646] +- [Rustfmt stopped badly formatting text in some cases][rustfmt/2695] + +Compatibility Notes +-------- + +- [`fn main() -> impl Trait` no longer works for non-Termination + trait][50656] + This reverts an accidental stabilization. +- [`NaN > NaN` no longer returns true in const-fn contexts][50812] +- [Prohibit using turbofish for `impl Trait` in method arguments][50950] + +[50646]: https://github.com/rust-lang/rust/issues/50646 +[50656]: https://github.com/rust-lang/rust/pull/50656 +[50812]: https://github.com/rust-lang/rust/pull/50812 +[50950]: https://github.com/rust-lang/rust/issues/50950 +[rustfmt/2695]: https://github.com/rust-lang-nursery/rustfmt/issues/2695 + +Version 1.26.0 (2018-05-10) +========================== + +Language +-------- +- [Closures now implement `Copy` and/or `Clone` if all captured variables + implement either or both traits.][49299] +- [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813] +- [Stablise `'_`. The underscore lifetime can be used anywhere where a + lifetime can be elided.][49458] +- [`impl Trait` is now stable allowing you to have abstract types in returns + or in function parameters.][49255] e.g. `fn foo() -> impl Iterator` or + `fn open(path: impl AsRef)`. +- [Pattern matching will now automatically apply dereferences.][49394] +- [128-bit integers in the form of `u128` and `i128` are now stable.][49101] +- [`main` can now return `Result<(), E: Debug>`][49162] in addition to `()`. +- [A lot of operations are now available in a const context.][46882] E.g. You + can now index into constant arrays, reference and dereference into constants, + and use Tuple struct constructors. +- [Fixed entry slice patterns are now stable.][48516] e.g. + ```rust + let points = [1, 2, 3, 4]; + match points { + [1, 2, 3, 4] => println!("All points were sequential."), + _ => println!("Not all points were sequential."), + } + ``` + + +Compiler +-------- +- [LLD is now used as the default linker for `wasm32-unknown-unknown`.][48125] +- [Fixed exponential projection complexity on nested types.][48296] + This can provide up to a ~12% reduction in compile times for certain crates. +- [Added the `--remap-path-prefix` option to rustc.][48359] Allowing you + to remap path prefixes outputted by the compiler. +- [Added `powerpc-unknown-netbsd` target.][48281] + +Libraries +--------- +- [Implemented `From for usize` & `From<{u8, i16}> for isize`.][49305] +- [Added hexadecimal formatting for integers with fmt::Debug][48978] + e.g. `assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]")` +- [Implemented `Default, Hash` for `cmp::Reverse`.][48628] +- [Optimized `str::repeat` being 8x faster in large cases.][48657] +- [`ascii::escape_default` is now available in libcore.][48735] +- [Trailing commas are now supported in std and core macros.][48056] +- [Implemented `Copy, Clone` for `cmp::Reverse`][47379] +- [Implemented `Clone` for `char::{ToLowercase, ToUppercase}`.][48629] + +Stabilized APIs +--------------- +- [`*const T::add`] +- [`*const T::copy_to_nonoverlapping`] +- [`*const T::copy_to`] +- [`*const T::read_unaligned`] +- [`*const T::read_volatile`] +- [`*const T::read`] +- [`*const T::sub`] +- [`*const T::wrapping_add`] +- [`*const T::wrapping_sub`] +- [`*mut T::add`] +- [`*mut T::copy_to_nonoverlapping`] +- [`*mut T::copy_to`] +- [`*mut T::read_unaligned`] +- [`*mut T::read_volatile`] +- [`*mut T::read`] +- [`*mut T::replace`] +- [`*mut T::sub`] +- [`*mut T::swap`] +- [`*mut T::wrapping_add`] +- [`*mut T::wrapping_sub`] +- [`*mut T::write_bytes`] +- [`*mut T::write_unaligned`] +- [`*mut T::write_volatile`] +- [`*mut T::write`] +- [`Box::leak`] +- [`FromUtf8Error::as_bytes`] +- [`LocalKey::try_with`] +- [`Option::cloned`] +- [`btree_map::Entry::and_modify`] +- [`fs::read_to_string`] +- [`fs::read`] +- [`fs::write`] +- [`hash_map::Entry::and_modify`] +- [`iter::FusedIterator`] +- [`ops::RangeInclusive`] +- [`ops::RangeToInclusive`] +- [`process::id`] +- [`slice::rotate_left`] +- [`slice::rotate_right`] +- [`String::retain`] + + +Cargo +----- +- [Cargo will now output path to custom commands when `-v` is + passed with `--list`][cargo/5041] +- [The Cargo binary version is now the same as the Rust version][cargo/5083] +- [`Cargo.lock` files are now included in published crates.][cargo/5093] + +Misc +---- +- [The second edition of "The Rust Programming Language" book is now recommended + over the first.][48404] + +Compatibility Notes +------------------- + +- [aliasing a `Fn` trait as `dyn` no longer works.][48481] E.g. the following + syntax is now invalid. + ``` + use std::ops::Fn as dyn; + fn g(_: Box) {} + ``` +- [The result of dereferences are no longer promoted to `'static`.][47408] + e.g. + ```rust + fn main() { + const PAIR: &(i32, i32) = &(0, 1); + let _reversed_pair: &'static _ = &(PAIR.1, PAIR.0); // Doesn't work + } + ``` +- [Deprecate `AsciiExt` trait in favor of inherent methods.][49109] +- [`".e0"` will now no longer parse as `0.0` and will instead cause + an error.][48235] +- [Removed hoedown from rustdoc.][48274] +- [Bounds on higher-kinded lifetimes a hard error.][48326] + +[46882]: https://github.com/rust-lang/rust/pull/46882 +[47379]: https://github.com/rust-lang/rust/pull/47379 +[47408]: https://github.com/rust-lang/rust/pull/47408 +[47813]: https://github.com/rust-lang/rust/pull/47813 +[48056]: https://github.com/rust-lang/rust/pull/48056 +[48125]: https://github.com/rust-lang/rust/pull/48125 +[48166]: https://github.com/rust-lang/rust/pull/48166 +[48235]: https://github.com/rust-lang/rust/pull/48235 +[48274]: https://github.com/rust-lang/rust/pull/48274 +[48281]: https://github.com/rust-lang/rust/pull/48281 +[48296]: https://github.com/rust-lang/rust/pull/48296 +[48326]: https://github.com/rust-lang/rust/pull/48326 +[48359]: https://github.com/rust-lang/rust/pull/48359 +[48404]: https://github.com/rust-lang/rust/pull/48404 +[48481]: https://github.com/rust-lang/rust/pull/48481 +[48516]: https://github.com/rust-lang/rust/pull/48516 +[48628]: https://github.com/rust-lang/rust/pull/48628 +[48629]: https://github.com/rust-lang/rust/pull/48629 +[48657]: https://github.com/rust-lang/rust/pull/48657 +[48735]: https://github.com/rust-lang/rust/pull/48735 +[48978]: https://github.com/rust-lang/rust/pull/48978 +[49101]: https://github.com/rust-lang/rust/pull/49101 +[49109]: https://github.com/rust-lang/rust/pull/49109 +[49121]: https://github.com/rust-lang/rust/pull/49121 +[49162]: https://github.com/rust-lang/rust/pull/49162 +[49184]: https://github.com/rust-lang/rust/pull/49184 +[49234]: https://github.com/rust-lang/rust/pull/49234 +[49255]: https://github.com/rust-lang/rust/pull/49255 +[49299]: https://github.com/rust-lang/rust/pull/49299 +[49305]: https://github.com/rust-lang/rust/pull/49305 +[49394]: https://github.com/rust-lang/rust/pull/49394 +[49458]: https://github.com/rust-lang/rust/pull/49458 +[`*const T::add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add +[`*const T::copy_to_nonoverlapping`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to_nonoverlapping +[`*const T::copy_to`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to +[`*const T::read_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned +[`*const T::read_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile +[`*const T::read`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read +[`*const T::sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.sub +[`*const T::wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add +[`*const T::wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub +[`*mut T::add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add-1 +[`*mut T::copy_to_nonoverlapping`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to_nonoverlapping-1 +[`*mut T::copy_to`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to-1 +[`*mut T::read_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned-1 +[`*mut T::read_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile-1 +[`*mut T::read`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read-1 +[`*mut T::replace`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.replace +[`*mut T::sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.sub-1 +[`*mut T::swap`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.swap +[`*mut T::wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add-1 +[`*mut T::wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub-1 +[`*mut T::write_bytes`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_bytes +[`*mut T::write_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_unaligned +[`*mut T::write_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_volatile +[`*mut T::write`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write +[`Box::leak`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak +[`FromUtf8Error::as_bytes`]: https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html#method.as_bytes +[`LocalKey::try_with`]: https://doc.rust-lang.org/std/thread/struct.LocalKey.html#method.try_with +[`Option::cloned`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.cloned +[`btree_map::Entry::and_modify`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.and_modify +[`fs::read_to_string`]: https://doc.rust-lang.org/std/fs/fn.read_to_string.html +[`fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html +[`fs::write`]: https://doc.rust-lang.org/std/fs/fn.write.html +[`hash_map::Entry::and_modify`]: https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.and_modify +[`iter::FusedIterator`]: https://doc.rust-lang.org/std/iter/trait.FusedIterator.html +[`ops::RangeInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html +[`ops::RangeToInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html +[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html +[`slice::rotate_left`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_left +[`slice::rotate_right`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_right +[`String::retain`]: https://doc.rust-lang.org/std/string/struct.String.html#method.retain +[cargo/5041]: https://github.com/rust-lang/cargo/pull/5041 +[cargo/5083]: https://github.com/rust-lang/cargo/pull/5083 +[cargo/5093]: https://github.com/rust-lang/cargo/pull/5093 + + Version 1.25.0 (2018-03-29) ========================== diff -Nru rustc-1.26.0+dfsg0+llvm/src/bootstrap/channel.rs rustc-1.26.1+dfsg0+llvm/src/bootstrap/channel.rs --- rustc-1.26.0+dfsg0+llvm/src/bootstrap/channel.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/bootstrap/channel.rs 2018-05-25 18:31:50.000000000 +0000 @@ -24,7 +24,7 @@ use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.26.0"; +pub const CFG_RELEASE_NUM: &str = "1.26.1"; pub struct GitInfo { inner: Option, diff -Nru rustc-1.26.0+dfsg0+llvm/src/Cargo.lock rustc-1.26.1+dfsg0+llvm/src/Cargo.lock --- rustc-1.26.0+dfsg0+llvm/src/Cargo.lock 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/Cargo.lock 2018-05-25 18:31:50.000000000 +0000 @@ -198,7 +198,7 @@ "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -287,26 +287,6 @@ [[package]] name = "clippy_lints" -version = "0.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clippy_lints" version = "0.0.191" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -896,7 +876,7 @@ [[package]] name = "languageserver-types" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1415,12 +1395,12 @@ dependencies = [ "cargo 0.27.0", "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.191", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1432,7 +1412,7 @@ "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.4.1", + "rustfmt-nightly 0.4.2", "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1528,7 +1508,7 @@ [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1537,7 +1517,7 @@ [[package]] name = "rustc-ap-rustc_data_structures" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1545,20 +1525,20 @@ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1566,32 +1546,32 @@ [[package]] name = "rustc-ap-serialize" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "73.0.0" +version = "94.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2012,7 +1992,7 @@ [[package]] name = "rustfmt-nightly" -version = "0.4.1" +version = "0.4.2" dependencies = [ "cargo_metadata 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2024,7 +2004,7 @@ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2319,7 +2299,7 @@ [[package]] name = "tempfile" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2646,7 +2626,6 @@ "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum clippy_lints 0.0.189 (registry+https://github.com/rust-lang/crates.io-index)" = "fef652630bbf8c5e89601220abd000f5057e8fa9db608484b5ebaad98e9bce53" "checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" @@ -2699,7 +2678,7 @@ "checksum json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)" = "39ebf0fac977ee3a4a3242b6446004ff64514889e3e2730bbd4f764a67a2e483" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d25086d59f44b80253d5ff96c66a692fb69de8485cf7a25b28677e89126de0d" +"checksum languageserver-types 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e264ab825353617bbc80844717555be6e9e1d403474b1d0a3b8e190440b13e" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -2757,12 +2736,12 @@ "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" -"checksum rustc-ap-rustc_cratesio_shim 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "421262e22426c06306e46057a75048f883dbc43886f78dbe1e750397a9c9b8e6" -"checksum rustc-ap-rustc_data_structures 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8460c1207f9abb48a9720aee8be418bcfac018b6eee7b740b98a410e7799d24a" -"checksum rustc-ap-rustc_errors 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad2077469162e52fcd84543334e18632088b9e342fe54e3b78c37d7077d09714" -"checksum rustc-ap-serialize 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69943901ae255dca5f63faeae2ff08b402d34a56d1eb50d34fbff6e83e6ace60" -"checksum rustc-ap-syntax 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a44363359a43df753e26a4d4fef72720af183de635ebae8699686cb5d5de813" -"checksum rustc-ap-syntax_pos 73.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "413f464657e8d5f3864de308dba1867526f21a44809b6f338b34e8c0caf88fb0" +"checksum rustc-ap-rustc_cratesio_shim 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02ab246f7da18804a51d3676c2229a9e74951ed4362687647609fefd6e4f55fa" +"checksum rustc-ap-rustc_data_structures 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b652047d793132b5f38b7eb010192d9aec72a8e52a1685822d3097ff5e04834a" +"checksum rustc-ap-rustc_errors 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc91190fa312cdf88d1ed63b8574ef57ea6b4260eb123e1979ca2d1848a7afa7" +"checksum rustc-ap-serialize 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06e78f89811eaddebb2b8c51a52cf21b5fcfaf8da6fabe9091a19927e57cd520" +"checksum rustc-ap-syntax 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fb9d06911de80e4ba6bef14f348c948485d18a20601dd23698c349e0f8d3fbb" +"checksum rustc-ap-syntax_pos 94.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba449d1d913b9ec98294968828576514b5adef0239cb39d2c42c62b8f38aa14f" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" @@ -2791,7 +2770,7 @@ "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" "checksum tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1605d3388ceb50252952ffebab4b5dc43017ead7e4481b175961c283bb951195" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99" +"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_const_math/float.rs rustc-1.26.1+dfsg0+llvm/src/librustc_const_math/float.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_const_math/float.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_const_math/float.rs 2018-05-25 18:31:50.000000000 +0000 @@ -38,19 +38,18 @@ } /// Compares the values if they are of the same type - pub fn try_cmp(self, rhs: Self) -> Result { + pub fn try_cmp(self, rhs: Self) -> Result, ConstMathErr> { match (self.ty, rhs.ty) { (ast::FloatTy::F64, ast::FloatTy::F64) => { let a = Double::from_bits(self.bits); let b = Double::from_bits(rhs.bits); - // This is pretty bad but it is the existing behavior. - Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater)) + Ok(a.partial_cmp(&b)) } (ast::FloatTy::F32, ast::FloatTy::F32) => { let a = Single::from_bits(self.bits); let b = Single::from_bits(rhs.bits); - Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater)) + Ok(a.partial_cmp(&b)) } _ => Err(CmpBetweenUnequalTypes), diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_mir/hair/pattern/mod.rs rustc-1.26.1+dfsg0+llvm/src/librustc_mir/hair/pattern/mod.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_mir/hair/pattern/mod.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_mir/hair/pattern/mod.rs 2018-05-25 18:31:50.000000000 +0000 @@ -1115,7 +1115,12 @@ ty, }; // FIXME(oli-obk): report cmp errors? - l.try_cmp(r).ok() + // FIXME: Just returning Ordering::Greater here is the previous behavior but may + // not be what we want. It means that NaN > NaN is true, which if false. + match l.try_cmp(r) { + Ok(opt) => Some(opt.unwrap_or(Ordering::Greater)), + _ => None, + } }, ty::TyInt(_) => { let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_mir/interpret/operator.rs rustc-1.26.1+dfsg0+llvm/src/librustc_mir/interpret/operator.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_mir/interpret/operator.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_mir/interpret/operator.rs 2018-05-25 18:31:50.000000000 +0000 @@ -1,8 +1,9 @@ +use std::cmp::Ordering; + use rustc::mir; use rustc::ty::{self, Ty}; use rustc_const_math::ConstFloat; use syntax::ast::FloatTy; -use std::cmp::Ordering; use rustc::ty::layout::LayoutOf; use super::{EvalContext, Place, Machine, ValTy}; @@ -134,13 +135,24 @@ bits: r, ty, }; + let cmp = |l: ConstFloat, r: ConstFloat| -> Option { + l.try_cmp(r).unwrap_or(None) + }; match op { - Eq => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Equal), - Ne => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Equal), - Lt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Less), - Le => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Greater), - Gt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Greater), - Ge => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Less), + Eq => PrimVal::from_bool(cmp(l, r) == Some(Ordering::Equal)), + Ne => PrimVal::from_bool(cmp(l, r) != Some(Ordering::Equal)), + Lt => PrimVal::from_bool(cmp(l, r) == Some(Ordering::Less)), + Gt => PrimVal::from_bool(cmp(l, r) == Some(Ordering::Greater)), + Le => PrimVal::from_bool(match cmp(l, r) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => true, + _ => false, + }), + Ge => PrimVal::from_bool(match cmp(l, r) { + Some(Ordering::Greater) => true, + Some(Ordering::Equal) => true, + _ => false, + }), Add => PrimVal::Bytes((l + r).unwrap().bits), Sub => PrimVal::Bytes((l - r).unwrap().bits), Mul => PrimVal::Bytes((l * r).unwrap().bits), diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_privacy/lib.rs rustc-1.26.1+dfsg0+llvm/src/librustc_privacy/lib.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_privacy/lib.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_privacy/lib.rs 2018-05-25 18:31:50.000000000 +0000 @@ -31,6 +31,7 @@ use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::maps::Providers; +use rustc::ty::subst::UnpackedKind; use rustc::util::nodemap::NodeSet; use syntax::ast::{self, CRATE_NODE_ID, Ident}; use syntax::symbol::keywords; @@ -39,6 +40,7 @@ use std::cmp; use std::mem::replace; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; mod diagnostics; @@ -624,6 +626,7 @@ in_body: bool, span: Span, empty_tables: &'a ty::TypeckTables<'tcx>, + visited_anon_tys: FxHashSet } impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { @@ -943,8 +946,15 @@ self.tcx.sess.span_err(self.span, &msg); return true; } - // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion - for subst in trait_ref.substs.iter().skip(1) { + for subst in trait_ref.substs.iter() { + // Skip repeated `TyAnon`s to avoid infinite recursion. + if let UnpackedKind::Type(ty) = subst.unpack() { + if let ty::TyAnon(def_id, ..) = ty.sty { + if !self.visited_anon_tys.insert(def_id) { + continue; + } + } + } if subst.visit_with(self) { return true; } @@ -1677,6 +1687,7 @@ in_body: false, span: krate.span, empty_tables: &empty_tables, + visited_anon_tys: FxHashSet() }; intravisit::walk_crate(&mut visitor, krate); diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/method/confirm.rs rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/method/confirm.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/method/confirm.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/method/confirm.rs 2018-05-25 18:31:50.000000000 +0000 @@ -45,18 +45,21 @@ } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn confirm_method(&self, - span: Span, - self_expr: &'gcx hir::Expr, - call_expr: &'gcx hir::Expr, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - segment: &hir::PathSegment) - -> ConfirmResult<'tcx> { - debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", - unadjusted_self_ty, - pick, - segment.parameters); + pub fn confirm_method( + &self, + span: Span, + self_expr: &'gcx hir::Expr, + call_expr: &'gcx hir::Expr, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + segment: &hir::PathSegment, + ) -> ConfirmResult<'tcx> { + debug!( + "confirm(unadjusted_self_ty={:?}, pick={:?}, generic_args={:?})", + unadjusted_self_ty, + pick, + segment.parameters, + ); let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, segment) @@ -77,11 +80,12 @@ } } - fn confirm(&mut self, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - segment: &hir::PathSegment) - -> ConfirmResult<'tcx> { + fn confirm( + &mut self, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + segment: &hir::PathSegment, + ) -> ConfirmResult<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); @@ -299,16 +303,18 @@ }) } - fn instantiate_method_substs(&mut self, - pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment, - parent_substs: &Substs<'tcx>) - -> &'tcx Substs<'tcx> { + fn instantiate_method_substs( + &mut self, + pick: &probe::Pick<'tcx>, + segment: &hir::PathSegment, + parent_substs: &Substs<'tcx>, + ) -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. let method_generics = self.tcx.generics_of(pick.item.def_id); let mut fn_segment = Some((segment, method_generics)); + self.fcx.check_impl_trait(self.span, fn_segment); self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true); // Create subst for early-bound lifetime parameters, combining diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/method/mod.rs rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/method/mod.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/method/mod.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/method/mod.rs 2018-05-25 18:31:50.000000000 +0000 @@ -173,12 +173,14 @@ self.tcx.check_stability(pick.item.def_id, Some(call_expr.id), span); - let result = self.confirm_method(span, - self_expr, - call_expr, - self_ty, - pick.clone(), - segment); + let result = self.confirm_method( + span, + self_expr, + call_expr, + self_ty, + pick.clone(), + segment, + ); if result.illegal_sized_bound { // We probe again, taking all traits into account (not only those in scope). diff -Nru rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/mod.rs rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/mod.rs --- rustc-1.26.0+dfsg0+llvm/src/librustc_typeck/check/mod.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/librustc_typeck/check/mod.rs 2018-05-25 18:31:50.000000000 +0000 @@ -1035,13 +1035,13 @@ let mut fcx = FnCtxt::new(inherited, param_env, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); - let ret_ty = fn_sig.output(); - fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType); - let ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &ret_ty); - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty))); + let declared_ret_ty = fn_sig.output(); + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + let revealed_ret_ty = fcx.instantiate_anon_types_from_return_value(fn_id, &declared_ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), - ret_ty, + revealed_ret_ty, fn_sig.variadic, fn_sig.unsafety, fn_sig.abi @@ -1123,7 +1123,7 @@ actual_return_ty = fcx.next_diverging_ty_var( TypeVariableOrigin::DivergingFn(span)); } - fcx.demand_suptype(span, ret_ty, actual_return_ty); + fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); // Check that the main return type implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { @@ -1131,7 +1131,7 @@ if id == fn_id { match fcx.sess().entry_type.get() { Some(config::EntryMain) => { - let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); + let substs = fcx.tcx.mk_substs(iter::once(Kind::from(declared_ret_ty))); let trait_ref = ty::TraitRef::new(term_id, substs); let return_ty_span = decl.output.span(); let cause = traits::ObligationCause::new( @@ -4806,7 +4806,7 @@ // a problem. self.check_path_parameter_count(span, &mut type_segment, false); self.check_path_parameter_count(span, &mut fn_segment, false); - self.check_impl_trait(span, &mut fn_segment); + self.check_impl_trait(span, fn_segment); let (fn_start, has_self) = match (type_segment, fn_segment) { (_, Some((_, generics))) => { @@ -5066,7 +5066,7 @@ /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait(&self, span: Span, - segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { + segment: Option<(&hir::PathSegment, &ty::Generics)>) { use hir::SyntheticTyParamKind::*; segment.map(|(path_segment, generics)| { diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/run-pass/impl-trait/issue-49376.rs rustc-1.26.1+dfsg0+llvm/src/test/run-pass/impl-trait/issue-49376.rs --- rustc-1.26.0+dfsg0+llvm/src/test/run-pass/impl-trait/issue-49376.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/run-pass/impl-trait/issue-49376.rs 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests for nested self-reference which caused a stack overflow. + +use std::fmt::Debug; +use std::ops::*; + +fn gen() -> impl PartialOrd + PartialEq + Debug { } + +struct Bar {} +trait Foo {} +impl Foo for Bar {} + +fn foo() -> impl Foo { + Bar {} +} + +fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 } +fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 1 } + +fn main() {} diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/run-pass/issue-50811.rs rustc-1.26.1+dfsg0+llvm/src/test/run-pass/issue-50811.rs --- rustc-1.26.0+dfsg0+llvm/src/test/run-pass/issue-50811.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/run-pass/issue-50811.rs 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,65 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; + +use std::f64::{NAN, NEG_INFINITY, INFINITY, MAX}; +use std::mem::size_of; +use test::black_box; + +// Ensure the const-eval result and runtime result of float comparison are equivalent. + +macro_rules! compare { + ($op:tt) => { + compare!( + [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN], + $op + ); + }; + ([$($lhs:expr),+], $op:tt) => { + $(compare!( + $lhs, + $op, + [NEG_INFINITY, -MAX, -1.0, -0.0, 0.0, 1.0, MAX, INFINITY, NAN] + );)+ + }; + ($lhs:expr, $op:tt, [$($rhs:expr),+]) => { + $({ + // Wrap the check in its own function to reduce time needed to borrowck. + fn check() { + static CONST_EVAL: bool = $lhs $op $rhs; + let runtime_eval = black_box($lhs) $op black_box($rhs); + assert_eq!(CONST_EVAL, runtime_eval, stringify!($lhs $op $rhs)); + assert_eq!( + size_of::<[u8; ($lhs $op $rhs) as usize]>(), + runtime_eval as usize, + stringify!($lhs $op $rhs (forced const eval)) + ); + } + check(); + })+ + }; +} + +fn main() { + assert_eq!(0.0/0.0 < 0.0/0.0, false); + assert_eq!(0.0/0.0 > 0.0/0.0, false); + assert_eq!(NAN < NAN, false); + assert_eq!(NAN > NAN, false); + + compare!(==); + compare!(!=); + compare!(<); + compare!(<=); + compare!(>); + compare!(>=); +} diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs rustc-1.26.1+dfsg0+llvm/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs --- rustc-1.26.0+dfsg0+llvm/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-impl-termination.rs 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait_lib)] + +fn main() -> impl std::process::Termination { } diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs rustc-1.26.1+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs --- rustc-1.26.0+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.rs 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::any::Any; +pub struct EventHandler { +} + +impl EventHandler +{ + pub fn handle_event(&mut self, _efunc: impl FnMut(T)) {} +} + +struct TestEvent(i32); + +fn main() { + let mut evt = EventHandler {}; + evt.handle_event::(|_evt| { + //~^ ERROR cannot provide explicit type parameters + }); +} diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr rustc-1.26.1+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr --- rustc-1.26.0+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/ui/impl-trait/universal-turbofish-in-method-issue-50950.stderr 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,9 @@ +error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position. + --> $DIR/universal-turbofish-in-method-issue-50950.rs:24:9 + | +LL | evt.handle_event::(|_evt| { + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0632`. diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs rustc-1.26.1+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs --- rustc-1.26.0+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,13 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that an `impl Trait` that is not `impl Termination` will not work. +fn main() -> impl Copy { } +//~^ ERROR `main` has invalid return type `impl std::marker::Copy` diff -Nru rustc-1.26.0+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr rustc-1.26.1+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr --- rustc-1.26.0+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr 2018-05-25 18:31:50.000000000 +0000 @@ -0,0 +1,11 @@ +error[E0277]: `main` has invalid return type `impl std::marker::Copy` + --> $DIR/termination-trait-impl-trait.rs:12:14 + | +LL | fn main() -> impl Copy { } + | ^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | + = help: consider using `()`, or a `Result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/build-manifest/src/main.rs rustc-1.26.1+dfsg0+llvm/src/tools/build-manifest/src/main.rs --- rustc-1.26.0+dfsg0+llvm/src/tools/build-manifest/src/main.rs 2018-05-07 17:31:28.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/build-manifest/src/main.rs 2018-05-25 18:31:50.000000000 +0000 @@ -356,6 +356,28 @@ target: "*".to_string(), }); + // If the components/extensions don't actually exist for this + // particular host/target combination then nix it entirely from our + // lists. + { + let has_component = |c: &Component| { + if c.target == "*" { + return true + } + let pkg = match manifest.pkg.get(&c.pkg) { + Some(p) => p, + None => return false, + }; + let target = match pkg.target.get(&c.target) { + Some(t) => t, + None => return false, + }; + target.available + }; + extensions.retain(&has_component); + components.retain(&has_component); + } + pkg.target.insert(host.to_string(), Target { available: true, url: Some(self.url(&filename)), diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/.arcconfig rustc-1.26.1+dfsg0+llvm/src/tools/lld/.arcconfig --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/.arcconfig 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/.arcconfig 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -{ - "repository.callsign" : "LLD", - "conduit_uri" : "https://reviews.llvm.org/" -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/.clang-format rustc-1.26.1+dfsg0+llvm/src/tools/lld/.clang-format --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/.clang-format 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/.clang-format 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -BasedOnStyle: LLVM diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/cmake/modules/AddLLD.cmake rustc-1.26.1+dfsg0+llvm/src/tools/lld/cmake/modules/AddLLD.cmake --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/cmake/modules/AddLLD.cmake 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/cmake/modules/AddLLD.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -macro(add_lld_library name) - cmake_parse_arguments(ARG - "SHARED" - "" - "" - ${ARGN}) - if(ARG_SHARED) - set(ARG_ENABLE_SHARED SHARED) - endif() - llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS}) - set_target_properties(${name} PROPERTIES FOLDER "lld libraries") - - if (LLD_BUILD_TOOLS) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_lldtargets EXPORT lldTargets) - set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True) - endif() - - install(TARGETS ${name} - COMPONENT ${name} - ${export_to_lldtargets} - LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} - ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} - RUNTIME DESTINATION bin) - - if (${ARG_SHARED} AND NOT CMAKE_CONFIGURATION_TYPES) - add_llvm_install_targets(install-${name} - DEPENDS ${name} - COMPONENT ${name}) - endif() - set_property(GLOBAL APPEND PROPERTY LLD_EXPORTS ${name}) - endif() -endmacro(add_lld_library) - -macro(add_lld_executable name) - add_llvm_executable(${name} ${ARGN}) - set_target_properties(${name} PROPERTIES FOLDER "lld executables") -endmacro(add_lld_executable) - -macro(add_lld_tool name) - if (NOT LLD_BUILD_TOOLS) - set(EXCLUDE_FROM_ALL ON) - endif() - - add_lld_executable(${name} ${ARGN}) - - if (LLD_BUILD_TOOLS) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_lldtargets EXPORT lldTargets) - set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True) - endif() - - install(TARGETS ${name} - ${export_to_lldtargets} - RUNTIME DESTINATION bin - COMPONENT ${name}) - - if(NOT CMAKE_CONFIGURATION_TYPES) - add_llvm_install_targets(install-${name} - DEPENDS ${name} - COMPONENT ${name}) - endif() - set_property(GLOBAL APPEND PROPERTY LLD_EXPORTS ${name}) - endif() -endmacro() - -macro(add_lld_symlink name dest) - add_llvm_tool_symlink(${name} ${dest} ALWAYS_GENERATE) - # Always generate install targets - llvm_install_symlink(${name} ${dest} ALWAYS_GENERATE) -endmacro() diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/cmake/modules/FindVTune.cmake rustc-1.26.1+dfsg0+llvm/src/tools/lld/cmake/modules/FindVTune.cmake --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/cmake/modules/FindVTune.cmake 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/cmake/modules/FindVTune.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# - Find VTune ittnotify. -# Defines: -# VTune_FOUND -# VTune_INCLUDE_DIRS -# VTune_LIBRARIES - -set(dirs - "$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/" - "C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/" - "$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/" - "C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/" - ) - -find_path(VTune_INCLUDE_DIRS ittnotify.h - PATHS ${dirs} - PATH_SUFFIXES include) - -if (CMAKE_SIZEOF_VOID_P MATCHES "8") - set(vtune_lib_dir lib64) -else() - set(vtune_lib_dir lib32) -endif() - -find_library(VTune_LIBRARIES libittnotify - HINTS "${VTune_INCLUDE_DIRS}/.." - PATHS ${dirs} - PATH_SUFFIXES ${vtune_lib_dir}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/CMakeLists.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/CMakeLists.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/CMakeLists.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,239 +0,0 @@ -# Check if lld is built as a standalone project. -if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - project(lld) - cmake_minimum_required(VERSION 3.4.3) - - set(CMAKE_INCLUDE_CURRENT_DIR ON) - set(LLD_BUILT_STANDALONE TRUE) - - find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary") - if(NOT LLVM_CONFIG_PATH) - message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH") - endif() - - execute_process(COMMAND "${LLVM_CONFIG_PATH}" - "--obj-root" - "--includedir" - "--cmakedir" - "--src-root" - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(HAD_ERROR) - message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") - endif() - - string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}") - - list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT) - list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR) - list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH) - list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR) - - set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree") - set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include") - set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") - - file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR) - - if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake") - message(FATAL_ERROR "LLVMConfig.cmake not found") - endif() - include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake") - - list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") - - set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}") - include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS}) - link_directories(${LLVM_LIBRARY_DIRS}) - - set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) - set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) - find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) - - include(AddLLVM) - include(TableGen) - include(HandleLLVMOptions) - - if(LLVM_INCLUDE_TESTS) - set(Python_ADDITIONAL_VERSIONS 2.7) - include(FindPythonInterp) - if(NOT PYTHONINTERP_FOUND) - message(FATAL_ERROR -"Unable to find Python interpreter, required for testing. - -Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") - endif() - - if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7) - message(FATAL_ERROR "Python 2.7 or newer is required") - endif() - - # Check prebuilt llvm/utils. - if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX} - AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX}) - set(LLVM_UTILS_PROVIDED ON) - endif() - - if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - # Note: path not really used, except for checking if lit was found - set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) - if(NOT LLVM_UTILS_PROVIDED) - add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck) - add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not) - set(LLVM_UTILS_PROVIDED ON) - set(LLD_TEST_DEPS FileCheck not) - endif() - set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest) - if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h - AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX} - AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt) - add_subdirectory(${UNITTEST_DIR} utils/unittest) - endif() - else() - # Seek installed Lit. - find_program(LLVM_LIT - NAMES llvm-lit lit.py lit - PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit" - DOC "Path to lit.py") - endif() - - if(LLVM_LIT) - # Define the default arguments to use with 'lit', and an option for the user - # to override. - set(LIT_ARGS_DEFAULT "-sv") - if (MSVC OR XCODE) - set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") - endif() - set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") - - # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. - if(WIN32 AND NOT CYGWIN) - set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") - endif() - else() - set(LLVM_INCLUDE_TESTS OFF) - endif() - endif() -endif() - -set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include ) -set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) - -# Compute the LLD version from the LLVM version. -string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION - ${PACKAGE_VERSION}) -message(STATUS "LLD version: ${LLD_VERSION}") - -string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR - ${LLD_VERSION}) -string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR - ${LLD_VERSION}) - -# Determine LLD revision and repository. -# TODO: Figure out a way to get the revision and the repository on windows. -if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" ) - execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR} - OUTPUT_VARIABLE LLD_REVISION) - - execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR} - OUTPUT_VARIABLE LLD_REPOSITORY) - if ( LLD_REPOSITORY ) - # Replace newline characters with spaces - string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY}) - # Remove leading spaces - STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" ) - # Remove trailing spaces - string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY}) - endif() - - if ( LLD_REVISION ) - # Replace newline characters with spaces - string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION}) - # Remove leading spaces - STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" ) - # Remove trailing spaces - string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION}) - endif() -endif () - -# Configure the Version.inc file. -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Common/Version.inc.in - ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Common/Version.inc) - - -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) - message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite " -"the makefiles distributed with LLVM. Please create a directory and run cmake " -"from there, passing the path to this source directory as the last argument. " -"This process created the file `CMakeCache.txt' and the directory " -"`CMakeFiles'. Please delete them.") -endif() - -list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules") - -include(AddLLD) - -option(LLD_USE_VTUNE - "Enable VTune user task tracking." - OFF) -if (LLD_USE_VTUNE) - find_package(VTune) - if (VTUNE_FOUND) - include_directories(${VTune_INCLUDE_DIRS}) - list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES}) - add_definitions(-DLLD_HAS_VTUNE) - endif() -endif() - -option(LLD_BUILD_TOOLS - "Build the lld tools. If OFF, just generate build targets." ON) - -if (MSVC) - add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.' - add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header. -endif() - -include_directories(BEFORE - ${CMAKE_CURRENT_BINARY_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/include - ) - -if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - install(DIRECTORY include/ - DESTINATION include - FILES_MATCHING - PATTERN "*.h" - PATTERN ".svn" EXCLUDE - ) -endif() - -if (MSVC) - FOREACH(flag - CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO - CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_DEBUG_INIT - CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG_INIT) - if (MSVC) - STRING(REPLACE "/MD" "/MT" "${flag}" "${${flag}}") - SET("${flag}" "${${flag}}") - endif (MSVC) - ENDFOREACH() -endif() - -add_subdirectory(Common) -add_subdirectory(lib) -add_subdirectory(tools/lld) - -if (LLVM_INCLUDE_TESTS) - add_subdirectory(test) - add_subdirectory(unittests) -endif() - -add_subdirectory(docs) -add_subdirectory(COFF) -add_subdirectory(ELF) -add_subdirectory(MinGW) -add_subdirectory(wasm) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/CODE_OWNERS.TXT rustc-1.26.1+dfsg0+llvm/src/tools/lld/CODE_OWNERS.TXT --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/CODE_OWNERS.TXT 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/CODE_OWNERS.TXT 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -This file is a list of the people responsible for ensuring that patches for a -particular part of LLD are reviewed, either by themself or by someone else. -They are also the gatekeepers for their part of LLD, with the final word on -what goes in or not. - -The list is sorted by surname and formatted to allow easy grepping and -beautification by scripts. The fields are: name (N), email (E), web-address -(W), PGP key ID and fingerprint (P), description (D), and snail-mail address -(S). Each entry should contain at least the (N), (E) and (D) fields. - - -N: Rui Ueyama -E: ruiu@google.com -D: COFF, ELF backends (COFF/* ELF/*) - -N: Lang Hames, Nick Kledzik -E: lhames@gmail.com, kledzik@apple.com -D: Mach-O backend - -N: Sam Clegg -E: sbc@chromium.org -D: WebAssembly backend (wasm/*) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Chunks.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Chunks.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Chunks.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Chunks.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,535 +0,0 @@ -//===- Chunks.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Chunks.h" -#include "InputFiles.h" -#include "Symbols.h" -#include "Writer.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::COFF; -using llvm::support::ulittle32_t; - -namespace lld { -namespace coff { - -SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) - : Chunk(SectionKind), Repl(this), Header(H), File(F), - Relocs(File->getCOFFObj()->getRelocations(Header)), - NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { - // Initialize SectionName. - File->getCOFFObj()->getSectionName(Header, SectionName); - - Alignment = Header->getAlignment(); - - // If linker GC is disabled, every chunk starts out alive. If linker GC is - // enabled, treat non-comdat sections as roots. Generally optimized object - // files will be built with -ffunction-sections or /Gy, so most things worth - // stripping will be in a comdat. - Live = !Config->DoGC || !isCOMDAT(); -} - -static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } -static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } -static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } -static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } -static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } - -static void applySecRel(const SectionChunk *Sec, uint8_t *Off, - OutputSection *OS, uint64_t S) { - if (!OS) { - if (Sec->isCodeView()) - return; - fatal("SECREL relocation cannot be applied to absolute symbols"); - } - uint64_t SecRel = S - OS->getRVA(); - if (SecRel > UINT32_MAX) { - error("overflow in SECREL relocation in section: " + Sec->getSectionName()); - return; - } - add32(Off, SecRel); -} - -static void applySecIdx(uint8_t *Off, OutputSection *OS) { - // If we have no output section, this must be an absolute symbol. Use the - // sentinel absolute symbol section index. - uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex; - add16(Off, SecIdx); -} - -void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, - uint64_t S, uint64_t P) const { - switch (Type) { - case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; - case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; - case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; - case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; - case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; - case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; - case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; - default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); - } -} - -void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, - uint64_t S, uint64_t P) const { - switch (Type) { - case IMAGE_REL_I386_ABSOLUTE: break; - case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; - case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; - case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; - default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); - } -} - -static void applyMOV(uint8_t *Off, uint16_t V) { - write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); - write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); -} - -static uint16_t readMOV(uint8_t *Off) { - uint16_t Opcode1 = read16le(Off); - uint16_t Opcode2 = read16le(Off + 2); - uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); - Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); - return Imm; -} - -void applyMOV32T(uint8_t *Off, uint32_t V) { - uint16_t ImmW = readMOV(Off); // read MOVW operand - uint16_t ImmT = readMOV(Off + 4); // read MOVT operand - uint32_t Imm = ImmW | (ImmT << 16); - V += Imm; // add the immediate offset - applyMOV(Off, V); // set MOVW operand - applyMOV(Off + 4, V >> 16); // set MOVT operand -} - -static void applyBranch20T(uint8_t *Off, int32_t V) { - if (!isInt<21>(V)) - fatal("relocation out of range"); - uint32_t S = V < 0 ? 1 : 0; - uint32_t J1 = (V >> 19) & 1; - uint32_t J2 = (V >> 18) & 1; - or16(Off, (S << 10) | ((V >> 12) & 0x3f)); - or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); -} - -void applyBranch24T(uint8_t *Off, int32_t V) { - if (!isInt<25>(V)) - fatal("relocation out of range"); - uint32_t S = V < 0 ? 1 : 0; - uint32_t J1 = ((~V >> 23) & 1) ^ S; - uint32_t J2 = ((~V >> 22) & 1) ^ S; - or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); - // Clear out the J1 and J2 bits which may be set. - write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); -} - -void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, - uint64_t S, uint64_t P) const { - // Pointer to thumb code must have the LSB set. - uint64_t SX = S; - if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) - SX |= 1; - switch (Type) { - case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; - case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; - case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; - case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; - case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; - case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; - default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); - } -} - -// Interpret the existing immediate value as a byte offset to the -// target symbol, then update the instruction with the immediate as -// the page offset from the current instruction to the target. -static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) { - uint32_t Orig = read32le(Off); - uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); - S += Imm; - Imm = (S >> 12) - (P >> 12); - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; - uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi); -} - -// Update the immediate field in a AARCH64 ldr, str, and add instruction. -// Optionally limit the range of the written immediate by one or more bits -// (RangeLimit). -static void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { - uint32_t Orig = read32le(Off); - Imm += (Orig >> 10) & 0xFFF; - Orig &= ~(0xFFF << 10); - write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10)); -} - -// Add the 12 bit page offset to the existing immediate. -// Ldr/str instructions store the opcode immediate scaled -// by the load/store size (giving a larger range for larger -// loads/stores). The immediate is always (both before and after -// fixing up the relocation) stored scaled similarly. -// Even if larger loads/stores have a larger range, limit the -// effective offset to 12 bit, since it is intended to be a -// page offset. -static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { - uint32_t Orig = read32le(Off); - uint32_t Size = Orig >> 30; - // 0x04000000 indicates SIMD/FP registers - // 0x00800000 indicates 128 bit - if ((Orig & 0x4800000) == 0x4800000) - Size += 4; - if ((Imm & ((1 << Size) - 1)) != 0) - fatal("misaligned ldr/str offset"); - applyArm64Imm(Off, Imm >> Size, Size); -} - -void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, - uint64_t S, uint64_t P) const { - switch (Type) { - case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; - case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; - case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; - case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; - case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; - case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; - default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); - } -} - -void SectionChunk::writeTo(uint8_t *Buf) const { - if (!hasData()) - return; - // Copy section contents from source object file to output file. - ArrayRef A = getContents(); - memcpy(Buf + OutputSectionOff, A.data(), A.size()); - - // Apply relocations. - size_t InputSize = getSize(); - for (const coff_relocation &Rel : Relocs) { - // Check for an invalid relocation offset. This check isn't perfect, because - // we don't have the relocation size, which is only known after checking the - // machine and relocation type. As a result, a relocation may overwrite the - // beginning of the following input section. - if (Rel.VirtualAddress >= InputSize) - fatal("relocation points beyond the end of its parent section"); - - uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; - - // Get the output section of the symbol for this relocation. The output - // section is needed to compute SECREL and SECTION relocations used in debug - // info. - auto *Sym = - dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); - if (!Sym) { - if (isCodeView() || isDWARF()) - continue; - // Symbols in early discarded sections are represented using null pointers, - // so we need to retrieve the name from the object file. - COFFSymbolRef Sym = - check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); - StringRef Name; - File->getCOFFObj()->getSymbolName(Sym, Name); - fatal("relocation against symbol in discarded section: " + Name); - } - Chunk *C = Sym->getChunk(); - OutputSection *OS = C ? C->getOutputSection() : nullptr; - - // Only absolute and __ImageBase symbols lack an output section. For any - // other symbol, this indicates that the chunk was discarded. Normally - // relocations against discarded sections are an error. However, debug info - // sections are not GC roots and can end up with these kinds of relocations. - // Skip these relocations. - if (!OS && !isa(Sym) && !isa(Sym)) { - if (isCodeView() || isDWARF()) - continue; - fatal("relocation against symbol in discarded section: " + - Sym->getName()); - } - uint64_t S = Sym->getRVA(); - - // Compute the RVA of the relocation for relative relocations. - uint64_t P = RVA + Rel.VirtualAddress; - switch (Config->Machine) { - case AMD64: - applyRelX64(Off, Rel.Type, OS, S, P); - break; - case I386: - applyRelX86(Off, Rel.Type, OS, S, P); - break; - case ARMNT: - applyRelARM(Off, Rel.Type, OS, S, P); - break; - case ARM64: - applyRelARM64(Off, Rel.Type, OS, S, P); - break; - default: - llvm_unreachable("unknown machine type"); - } - } -} - -void SectionChunk::addAssociative(SectionChunk *Child) { - AssocChildren.push_back(Child); -} - -static uint8_t getBaserelType(const coff_relocation &Rel) { - switch (Config->Machine) { - case AMD64: - if (Rel.Type == IMAGE_REL_AMD64_ADDR64) - return IMAGE_REL_BASED_DIR64; - return IMAGE_REL_BASED_ABSOLUTE; - case I386: - if (Rel.Type == IMAGE_REL_I386_DIR32) - return IMAGE_REL_BASED_HIGHLOW; - return IMAGE_REL_BASED_ABSOLUTE; - case ARMNT: - if (Rel.Type == IMAGE_REL_ARM_ADDR32) - return IMAGE_REL_BASED_HIGHLOW; - if (Rel.Type == IMAGE_REL_ARM_MOV32T) - return IMAGE_REL_BASED_ARM_MOV32T; - return IMAGE_REL_BASED_ABSOLUTE; - case ARM64: - if (Rel.Type == IMAGE_REL_ARM64_ADDR64) - return IMAGE_REL_BASED_DIR64; - return IMAGE_REL_BASED_ABSOLUTE; - default: - llvm_unreachable("unknown machine type"); - } -} - -// Windows-specific. -// Collect all locations that contain absolute addresses, which need to be -// fixed by the loader if load-time relocation is needed. -// Only called when base relocation is enabled. -void SectionChunk::getBaserels(std::vector *Res) { - for (const coff_relocation &Rel : Relocs) { - uint8_t Ty = getBaserelType(Rel); - if (Ty == IMAGE_REL_BASED_ABSOLUTE) - continue; - Symbol *Target = File->getSymbol(Rel.SymbolTableIndex); - if (!Target || isa(Target)) - continue; - Res->emplace_back(RVA + Rel.VirtualAddress, Ty); - } -} - -bool SectionChunk::hasData() const { - return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); -} - -uint32_t SectionChunk::getPermissions() const { - return Header->Characteristics & PermMask; -} - -bool SectionChunk::isCOMDAT() const { - return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; -} - -void SectionChunk::printDiscardedMessage() const { - // Removed by dead-stripping. If it's removed by ICF, ICF already - // printed out the name, so don't repeat that here. - if (Sym && this == Repl) - message("Discarded " + Sym->getName()); -} - -StringRef SectionChunk::getDebugName() { - if (Sym) - return Sym->getName(); - return ""; -} - -ArrayRef SectionChunk::getContents() const { - ArrayRef A; - File->getCOFFObj()->getSectionContents(Header, A); - return A; -} - -void SectionChunk::replace(SectionChunk *Other) { - Other->Repl = Repl; - Other->Live = false; -} - -CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { - // Common symbols are aligned on natural boundaries up to 32 bytes. - // This is what MSVC link.exe does. - Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); -} - -uint32_t CommonChunk::getPermissions() const { - return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | - IMAGE_SCN_MEM_WRITE; -} - -void StringChunk::writeTo(uint8_t *Buf) const { - memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); -} - -ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { - // Intel Optimization Manual says that all branch targets - // should be 16-byte aligned. MSVC linker does this too. - Alignment = 16; -} - -void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { - memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); - // The first two bytes is a JMP instruction. Fill its operand. - write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); -} - -void ImportThunkChunkX86::getBaserels(std::vector *Res) { - Res->emplace_back(getRVA() + 2); -} - -void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { - memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); - // The first two bytes is a JMP instruction. Fill its operand. - write32le(Buf + OutputSectionOff + 2, - ImpSymbol->getRVA() + Config->ImageBase); -} - -void ImportThunkChunkARM::getBaserels(std::vector *Res) { - Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); -} - -void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { - memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); - // Fix mov.w and mov.t operands. - applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); -} - -void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { - int64_t Off = ImpSymbol->getRVA() & 0xfff; - memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); - applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA); - applyArm64Ldr(Buf + OutputSectionOff + 4, Off); -} - -void LocalImportChunk::getBaserels(std::vector *Res) { - Res->emplace_back(getRVA()); -} - -size_t LocalImportChunk::getSize() const { - return Config->is64() ? 8 : 4; -} - -void LocalImportChunk::writeTo(uint8_t *Buf) const { - if (Config->is64()) { - write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); - } else { - write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); - } -} - -void SEHTableChunk::writeTo(uint8_t *Buf) const { - ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); - size_t Cnt = 0; - for (Defined *D : Syms) - Begin[Cnt++] = D->getRVA(); - std::sort(Begin, Begin + Cnt); -} - -// Windows-specific. This class represents a block in .reloc section. -// The format is described here. -// -// On Windows, each DLL is linked against a fixed base address and -// usually loaded to that address. However, if there's already another -// DLL that overlaps, the loader has to relocate it. To do that, DLLs -// contain .reloc sections which contain offsets that need to be fixed -// up at runtime. If the loader finds that a DLL cannot be loaded to its -// desired base address, it loads it to somewhere else, and add - to each offset that is -// specified by the .reloc section. In ELF terms, .reloc sections -// contain relative relocations in REL format (as opposed to RELA.) -// -// This already significantly reduces the size of relocations compared -// to ELF .rel.dyn, but Windows does more to reduce it (probably because -// it was invented for PCs in the late '80s or early '90s.) Offsets in -// .reloc are grouped by page where the page size is 12 bits, and -// offsets sharing the same page address are stored consecutively to -// represent them with less space. This is very similar to the page -// table which is grouped by (multiple stages of) pages. -// -// For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00, -// 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4 -// bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they -// are represented like this: -// -// 0x00000 -- page address (4 bytes) -// 16 -- size of this block (4 bytes) -// 0xA030 -- entries (2 bytes each) -// 0xA500 -// 0xA700 -// 0xAA00 -// 0x20000 -- page address (4 bytes) -// 12 -- size of this block (4 bytes) -// 0xA004 -- entries (2 bytes each) -// 0xA008 -// -// Usually we have a lot of relocations for each page, so the number of -// bytes for one .reloc entry is close to 2 bytes on average. -BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { - // Block header consists of 4 byte page RVA and 4 byte block size. - // Each entry is 2 byte. Last entry may be padding. - Data.resize(alignTo((End - Begin) * 2 + 8, 4)); - uint8_t *P = Data.data(); - write32le(P, Page); - write32le(P + 4, Data.size()); - P += 8; - for (Baserel *I = Begin; I != End; ++I) { - write16le(P, (I->Type << 12) | (I->RVA - Page)); - P += 2; - } -} - -void BaserelChunk::writeTo(uint8_t *Buf) const { - memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); -} - -uint8_t Baserel::getDefaultType() { - switch (Config->Machine) { - case AMD64: - case ARM64: - return IMAGE_REL_BASED_DIR64; - case I386: - case ARMNT: - return IMAGE_REL_BASED_HIGHLOW; - default: - llvm_unreachable("unknown machine type"); - } -} - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Chunks.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Chunks.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Chunks.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Chunks.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,365 +0,0 @@ -//===- Chunks.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_CHUNKS_H -#define LLD_COFF_CHUNKS_H - -#include "Config.h" -#include "InputFiles.h" -#include "lld/Common/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Object/COFF.h" -#include -#include - -namespace lld { -namespace coff { - -using llvm::COFF::ImportDirectoryTableEntry; -using llvm::object::COFFSymbolRef; -using llvm::object::SectionRef; -using llvm::object::coff_relocation; -using llvm::object::coff_section; - -class Baserel; -class Defined; -class DefinedImportData; -class DefinedRegular; -class ObjFile; -class OutputSection; -class Symbol; - -// Mask for section types (code, data, bss, disacardable, etc.) -// and permissions (writable, readable or executable). -const uint32_t PermMask = 0xFF0000F0; - -// A Chunk represents a chunk of data that will occupy space in the -// output (if the resolver chose that). It may or may not be backed by -// a section of an input file. It could be linker-created data, or -// doesn't even have actual data (if common or bss). -class Chunk { -public: - enum Kind { SectionKind, OtherKind }; - Kind kind() const { return ChunkKind; } - virtual ~Chunk() = default; - - // Returns the size of this chunk (even if this is a common or BSS.) - virtual size_t getSize() const = 0; - - // Write this chunk to a mmap'ed file, assuming Buf is pointing to - // beginning of the file. Because this function may use RVA values - // of other chunks for relocations, you need to set them properly - // before calling this function. - virtual void writeTo(uint8_t *Buf) const {} - - // The writer sets and uses the addresses. - uint64_t getRVA() const { return RVA; } - void setRVA(uint64_t V) { RVA = V; } - - // Returns true if this has non-zero data. BSS chunks return - // false. If false is returned, the space occupied by this chunk - // will be filled with zeros. - virtual bool hasData() const { return true; } - - // Returns readable/writable/executable bits. - virtual uint32_t getPermissions() const { return 0; } - - // Returns the section name if this is a section chunk. - // It is illegal to call this function on non-section chunks. - virtual StringRef getSectionName() const { - llvm_unreachable("unimplemented getSectionName"); - } - - // An output section has pointers to chunks in the section, and each - // chunk has a back pointer to an output section. - void setOutputSection(OutputSection *O) { Out = O; } - OutputSection *getOutputSection() const { return Out; } - - // Windows-specific. - // Collect all locations that contain absolute addresses for base relocations. - virtual void getBaserels(std::vector *Res) {} - - // Returns a human-readable name of this chunk. Chunks are unnamed chunks of - // bytes, so this is used only for logging or debugging. - virtual StringRef getDebugName() { return ""; } - - // The alignment of this chunk. The writer uses the value. - uint32_t Alignment = 1; - -protected: - Chunk(Kind K = OtherKind) : ChunkKind(K) {} - const Kind ChunkKind; - - // The RVA of this chunk in the output. The writer sets a value. - uint64_t RVA = 0; - - // The output section for this chunk. - OutputSection *Out = nullptr; - -public: - // The offset from beginning of the output section. The writer sets a value. - uint64_t OutputSectionOff = 0; -}; - -// A chunk corresponding a section of an input file. -class SectionChunk final : public Chunk { - // Identical COMDAT Folding feature accesses section internal data. - friend class ICF; - -public: - class symbol_iterator : public llvm::iterator_adaptor_base< - symbol_iterator, const coff_relocation *, - std::random_access_iterator_tag, Symbol *> { - friend SectionChunk; - - ObjFile *File; - - symbol_iterator(ObjFile *File, const coff_relocation *I) - : symbol_iterator::iterator_adaptor_base(I), File(File) {} - - public: - symbol_iterator() = default; - - Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); } - }; - - SectionChunk(ObjFile *File, const coff_section *Header); - static bool classof(const Chunk *C) { return C->kind() == SectionKind; } - size_t getSize() const override { return Header->SizeOfRawData; } - ArrayRef getContents() const; - void writeTo(uint8_t *Buf) const override; - bool hasData() const override; - uint32_t getPermissions() const override; - StringRef getSectionName() const override { return SectionName; } - void getBaserels(std::vector *Res) override; - bool isCOMDAT() const; - void applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, - uint64_t P) const; - void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, - uint64_t P) const; - void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, - uint64_t P) const; - void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, - uint64_t P) const; - - // Called if the garbage collector decides to not include this chunk - // in a final output. It's supposed to print out a log message to stdout. - void printDiscardedMessage() const; - - // Adds COMDAT associative sections to this COMDAT section. A chunk - // and its children are treated as a group by the garbage collector. - void addAssociative(SectionChunk *Child); - - StringRef getDebugName() override; - - // Returns true if the chunk was not dropped by GC. - bool isLive() { return Live; } - - // Used by the garbage collector. - void markLive() { - assert(Config->DoGC && "should only mark things live from GC"); - assert(!isLive() && "Cannot mark an already live section!"); - Live = true; - } - - // True if this is a codeview debug info chunk. These will not be laid out in - // the image. Instead they will end up in the PDB, if one is requested. - bool isCodeView() const { - return SectionName == ".debug" || SectionName.startswith(".debug$"); - } - - // True if this is a DWARF debug info or exception handling chunk. - bool isDWARF() const { - return SectionName.startswith(".debug_") || SectionName == ".eh_frame"; - } - - // Allow iteration over the bodies of this chunk's relocated symbols. - llvm::iterator_range symbols() const { - return llvm::make_range(symbol_iterator(File, Relocs.begin()), - symbol_iterator(File, Relocs.end())); - } - - // Allow iteration over the associated child chunks for this section. - ArrayRef children() const { return AssocChildren; } - - // A pointer pointing to a replacement for this chunk. - // Initially it points to "this" object. If this chunk is merged - // with other chunk by ICF, it points to another chunk, - // and this chunk is considrered as dead. - SectionChunk *Repl; - - // The CRC of the contents as described in the COFF spec 4.5.5. - // Auxiliary Format 5: Section Definitions. Used for ICF. - uint32_t Checksum = 0; - - const coff_section *Header; - - // The file that this chunk was created from. - ObjFile *File; - - // The COMDAT leader symbol if this is a COMDAT chunk. - DefinedRegular *Sym = nullptr; - -private: - StringRef SectionName; - std::vector AssocChildren; - llvm::iterator_range Relocs; - size_t NumRelocs; - - // Used by the garbage collector. - bool Live; - - // Used for ICF (Identical COMDAT Folding) - void replace(SectionChunk *Other); - uint32_t Class[2] = {0, 0}; -}; - -// A chunk for common symbols. Common chunks don't have actual data. -class CommonChunk : public Chunk { -public: - CommonChunk(const COFFSymbolRef Sym); - size_t getSize() const override { return Sym.getValue(); } - bool hasData() const override { return false; } - uint32_t getPermissions() const override; - StringRef getSectionName() const override { return ".bss"; } - -private: - const COFFSymbolRef Sym; -}; - -// A chunk for linker-created strings. -class StringChunk : public Chunk { -public: - explicit StringChunk(StringRef S) : Str(S) {} - size_t getSize() const override { return Str.size() + 1; } - void writeTo(uint8_t *Buf) const override; - -private: - StringRef Str; -}; - -static const uint8_t ImportThunkX86[] = { - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 -}; - -static const uint8_t ImportThunkARM[] = { - 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 - 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 - 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] -}; - -static const uint8_t ImportThunkARM64[] = { - 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 - 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] - 0x00, 0x02, 0x1f, 0xd6, // br x16 -}; - -// Windows-specific. -// A chunk for DLL import jump table entry. In a final output, it's -// contents will be a JMP instruction to some __imp_ symbol. -class ImportThunkChunkX64 : public Chunk { -public: - explicit ImportThunkChunkX64(Defined *S); - size_t getSize() const override { return sizeof(ImportThunkX86); } - void writeTo(uint8_t *Buf) const override; - -private: - Defined *ImpSymbol; -}; - -class ImportThunkChunkX86 : public Chunk { -public: - explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} - size_t getSize() const override { return sizeof(ImportThunkX86); } - void getBaserels(std::vector *Res) override; - void writeTo(uint8_t *Buf) const override; - -private: - Defined *ImpSymbol; -}; - -class ImportThunkChunkARM : public Chunk { -public: - explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} - size_t getSize() const override { return sizeof(ImportThunkARM); } - void getBaserels(std::vector *Res) override; - void writeTo(uint8_t *Buf) const override; - -private: - Defined *ImpSymbol; -}; - -class ImportThunkChunkARM64 : public Chunk { -public: - explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} - size_t getSize() const override { return sizeof(ImportThunkARM64); } - void writeTo(uint8_t *Buf) const override; - -private: - Defined *ImpSymbol; -}; - -// Windows-specific. -// See comments for DefinedLocalImport class. -class LocalImportChunk : public Chunk { -public: - explicit LocalImportChunk(Defined *S) : Sym(S) {} - size_t getSize() const override; - void getBaserels(std::vector *Res) override; - void writeTo(uint8_t *Buf) const override; - -private: - Defined *Sym; -}; - -// Windows-specific. -// A chunk for SEH table which contains RVAs of safe exception handler -// functions. x86-only. -class SEHTableChunk : public Chunk { -public: - explicit SEHTableChunk(std::set S) : Syms(std::move(S)) {} - size_t getSize() const override { return Syms.size() * 4; } - void writeTo(uint8_t *Buf) const override; - -private: - std::set Syms; -}; - -// Windows-specific. -// This class represents a block in .reloc section. -// See the PE/COFF spec 5.6 for details. -class BaserelChunk : public Chunk { -public: - BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); - size_t getSize() const override { return Data.size(); } - void writeTo(uint8_t *Buf) const override; - -private: - std::vector Data; -}; - -class Baserel { -public: - Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} - explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} - uint8_t getDefaultType(); - - uint32_t RVA; - uint8_t Type; -}; - -void applyMOV32T(uint8_t *Off, uint32_t V); -void applyBranch24T(uint8_t *Off, int32_t V); - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/CMakeLists.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/CMakeLists.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/CMakeLists.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS Options.td) -tablegen(LLVM Options.inc -gen-opt-parser-defs) -add_public_tablegen_target(COFFOptionsTableGen) - -if(NOT LLD_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - -add_lld_library(lldCOFF - Chunks.cpp - DLL.cpp - Driver.cpp - DriverUtils.cpp - ICF.cpp - InputFiles.cpp - LTO.cpp - MapFile.cpp - MarkLive.cpp - MinGW.cpp - PDB.cpp - Strings.cpp - SymbolTable.cpp - Symbols.cpp - Writer.cpp - - LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} - BinaryFormat - Core - DebugInfoCodeView - DebugInfoMSF - DebugInfoPDB - LibDriver - LTO - MC - Object - Option - Support - WindowsManifest - - LINK_LIBS - lldCommon - ${LLVM_PTHREAD_LIB} - - DEPENDS - COFFOptionsTableGen - ${tablegen_deps} - ) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Config.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Config.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Config.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Config.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -//===- Config.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_CONFIG_H -#define LLD_COFF_CONFIG_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/CachePruning.h" -#include -#include -#include -#include - -namespace lld { -namespace coff { - -using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; -using llvm::COFF::WindowsSubsystem; -using llvm::StringRef; -class DefinedAbsolute; -class DefinedRelative; -class StringChunk; -class Symbol; - -// Short aliases. -static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; -static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64; -static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; -static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; - -// Represents an /export option. -struct Export { - StringRef Name; // N in /export:N or /export:E=N - StringRef ExtName; // E in /export:E=N - Symbol *Sym = nullptr; - uint16_t Ordinal = 0; - bool Noname = false; - bool Data = false; - bool Private = false; - bool Constant = false; - - // If an export is a form of /export:foo=dllname.bar, that means - // that foo should be exported as an alias to bar in the DLL. - // ForwardTo is set to "dllname.bar" part. Usually empty. - StringRef ForwardTo; - StringChunk *ForwardChunk = nullptr; - - // True if this /export option was in .drectves section. - bool Directives = false; - StringRef SymbolName; - StringRef ExportName; // Name in DLL - - bool operator==(const Export &E) { - return (Name == E.Name && ExtName == E.ExtName && - Ordinal == E.Ordinal && Noname == E.Noname && - Data == E.Data && Private == E.Private); - } -}; - -enum class DebugType { - None = 0x0, - CV = 0x1, /// CodeView - PData = 0x2, /// Procedure Data - Fixup = 0x4, /// Relocation Table -}; - -// Global configuration. -struct Configuration { - enum ManifestKind { SideBySide, Embed, No }; - bool is64() { return Machine == AMD64 || Machine == ARM64; } - - llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; - bool Verbose = false; - WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; - Symbol *Entry = nullptr; - bool NoEntry = false; - std::string OutputFile; - std::string ImportName; - bool DoGC = true; - bool DoICF = true; - bool Relocatable = true; - bool Force = false; - bool Debug = false; - bool DebugDwarf = false; - bool DebugGHashes = false; - unsigned DebugTypes = static_cast(DebugType::None); - llvm::SmallString<128> PDBPath; - std::vector Argv; - - // Symbols in this set are considered as live by the garbage collector. - std::vector GCRoot; - - std::set NoDefaultLibs; - bool NoDefaultLibAll = false; - - // True if we are creating a DLL. - bool DLL = false; - StringRef Implib; - std::vector Exports; - std::set DelayLoads; - std::map DLLOrder; - Symbol *DelayLoadHelper = nullptr; - - bool SaveTemps = false; - - // Used for SafeSEH. - Symbol *SEHTable = nullptr; - Symbol *SEHCount = nullptr; - - // Used for /opt:lldlto=N - unsigned LTOOptLevel = 2; - - // Used for /opt:lldltojobs=N - unsigned LTOJobs = 0; - // Used for /opt:lldltopartitions=N - unsigned LTOPartitions = 1; - - // Used for /opt:lldltocache=path - StringRef LTOCache; - // Used for /opt:lldltocachepolicy=policy - llvm::CachePruningPolicy LTOCachePolicy; - - // Used for /merge:from=to (e.g. /merge:.rdata=.text) - std::map Merge; - - // Used for /section=.name,{DEKPRSW} to set section attributes. - std::map Section; - - // Options for manifest files. - ManifestKind Manifest = No; - int ManifestID = 1; - StringRef ManifestDependency; - bool ManifestUAC = true; - std::vector ManifestInput; - StringRef ManifestLevel = "'asInvoker'"; - StringRef ManifestUIAccess = "'false'"; - StringRef ManifestFile; - - // Used for /aligncomm. - std::map AlignComm; - - // Used for /failifmismatch. - std::map MustMatch; - - // Used for /alternatename. - std::map AlternateNames; - - // Used for /lldmap. - std::string MapFile; - - uint64_t ImageBase = -1; - uint64_t StackReserve = 1024 * 1024; - uint64_t StackCommit = 4096; - uint64_t HeapReserve = 1024 * 1024; - uint64_t HeapCommit = 4096; - uint32_t MajorImageVersion = 0; - uint32_t MinorImageVersion = 0; - uint32_t MajorOSVersion = 6; - uint32_t MinorOSVersion = 0; - bool CanExitEarly = false; - bool DynamicBase = true; - bool AllowBind = true; - bool NxCompat = true; - bool AllowIsolation = true; - bool TerminalServerAware = true; - bool LargeAddressAware = false; - bool HighEntropyVA = false; - bool AppContainer = false; - bool MinGW = false; - bool WarnLocallyDefinedImported = true; -}; - -extern Configuration *Config; - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DLL.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DLL.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DLL.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DLL.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,597 +0,0 @@ -//===- DLL.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines various types of chunks for the DLL import or export -// descriptor tables. They are inherently Windows-specific. -// You need to read Microsoft PE/COFF spec to understand details -// about the data structures. -// -// If you are not particularly interested in linking against Windows -// DLL, you can skip this file, and you should still be able to -// understand the rest of the linker. -// -//===----------------------------------------------------------------------===// - -#include "Chunks.h" -#include "DLL.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Path.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::COFF; - -namespace lld { -namespace coff { -namespace { - -// Import table - -static int ptrSize() { return Config->is64() ? 8 : 4; } - -// A chunk for the import descriptor table. -class HintNameChunk : public Chunk { -public: - HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} - - size_t getSize() const override { - // Starts with 2 byte Hint field, followed by a null-terminated string, - // ends with 0 or 1 byte padding. - return alignTo(Name.size() + 3, 2); - } - - void writeTo(uint8_t *Buf) const override { - write16le(Buf + OutputSectionOff, Hint); - memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); - } - -private: - StringRef Name; - uint16_t Hint; -}; - -// A chunk for the import descriptor table. -class LookupChunk : public Chunk { -public: - explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = ptrSize(); } - size_t getSize() const override { return ptrSize(); } - - void writeTo(uint8_t *Buf) const override { - write32le(Buf + OutputSectionOff, HintName->getRVA()); - } - - Chunk *HintName; -}; - -// A chunk for the import descriptor table. -// This chunk represent import-by-ordinal symbols. -// See Microsoft PE/COFF spec 7.1. Import Header for details. -class OrdinalOnlyChunk : public Chunk { -public: - explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { Alignment = ptrSize(); } - size_t getSize() const override { return ptrSize(); } - - void writeTo(uint8_t *Buf) const override { - // An import-by-ordinal slot has MSB 1 to indicate that - // this is import-by-ordinal (and not import-by-name). - if (Config->is64()) { - write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); - } else { - write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); - } - } - - uint16_t Ordinal; -}; - -// A chunk for the import descriptor table. -class ImportDirectoryChunk : public Chunk { -public: - explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} - size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } - - void writeTo(uint8_t *Buf) const override { - auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); - E->ImportLookupTableRVA = LookupTab->getRVA(); - E->NameRVA = DLLName->getRVA(); - E->ImportAddressTableRVA = AddressTab->getRVA(); - } - - Chunk *DLLName; - Chunk *LookupTab; - Chunk *AddressTab; -}; - -// A chunk representing null terminator in the import table. -// Contents of this chunk is always null bytes. -class NullChunk : public Chunk { -public: - explicit NullChunk(size_t N) : Size(N) {} - bool hasData() const override { return false; } - size_t getSize() const override { return Size; } - -private: - size_t Size; -}; - -static std::vector> -binImports(const std::vector &Imports) { - // Group DLL-imported symbols by DLL name because that's how - // symbols are layed out in the import descriptor table. - auto Less = [](const std::string &A, const std::string &B) { - return Config->DLLOrder[A] < Config->DLLOrder[B]; - }; - std::map, - bool(*)(const std::string &, const std::string &)> M(Less); - for (DefinedImportData *Sym : Imports) - M[Sym->getDLLName().lower()].push_back(Sym); - - std::vector> V; - for (auto &KV : M) { - // Sort symbols by name for each group. - std::vector &Syms = KV.second; - std::sort(Syms.begin(), Syms.end(), - [](DefinedImportData *A, DefinedImportData *B) { - return A->getName() < B->getName(); - }); - V.push_back(std::move(Syms)); - } - return V; -} - -// Export table -// See Microsoft PE/COFF spec 4.3 for details. - -// A chunk for the delay import descriptor table etnry. -class DelayDirectoryChunk : public Chunk { -public: - explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} - - size_t getSize() const override { - return sizeof(delay_import_directory_table_entry); - } - - void writeTo(uint8_t *Buf) const override { - auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); - E->Attributes = 1; - E->Name = DLLName->getRVA(); - E->ModuleHandle = ModuleHandle->getRVA(); - E->DelayImportAddressTable = AddressTab->getRVA(); - E->DelayImportNameTable = NameTab->getRVA(); - } - - Chunk *DLLName; - Chunk *ModuleHandle; - Chunk *AddressTab; - Chunk *NameTab; -}; - -// Initial contents for delay-loaded functions. -// This code calls __delayLoadHelper2 function to resolve a symbol -// and then overwrites its jump table slot with the result -// for subsequent function calls. -static const uint8_t ThunkX64[] = { - 0x51, // push rcx - 0x52, // push rdx - 0x41, 0x50, // push r8 - 0x41, 0x51, // push r9 - 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h - 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 - 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 - 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 - 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 - 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] - 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] - 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 - 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] - 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] - 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] - 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] - 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h - 0x41, 0x59, // pop r9 - 0x41, 0x58, // pop r8 - 0x5A, // pop rdx - 0x59, // pop rcx - 0xFF, 0xE0, // jmp rax -}; - -static const uint8_t ThunkX86[] = { - 0x51, // push ecx - 0x52, // push edx - 0x68, 0, 0, 0, 0, // push offset ___imp__ - 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll - 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 - 0x5A, // pop edx - 0x59, // pop ecx - 0xFF, 0xE0, // jmp eax -}; - -static const uint8_t ThunkARM[] = { - 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_ - 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_ - 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} - 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 - 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} - 0x61, 0x46, // mov r1, ip - 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR - 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR - 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2 - 0x84, 0x46, // mov ip, r0 - 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7} - 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr} - 0x60, 0x47, // bx ip -}; - -// A chunk for the delay import thunk. -class ThunkChunkX64 : public Chunk { -public: - ThunkChunkX64(Defined *I, Chunk *D, Defined *H) - : Imp(I), Desc(D), Helper(H) {} - - size_t getSize() const override { return sizeof(ThunkX64); } - - void writeTo(uint8_t *Buf) const override { - memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); - write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); - write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); - write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); - } - - Defined *Imp = nullptr; - Chunk *Desc = nullptr; - Defined *Helper = nullptr; -}; - -class ThunkChunkX86 : public Chunk { -public: - ThunkChunkX86(Defined *I, Chunk *D, Defined *H) - : Imp(I), Desc(D), Helper(H) {} - - size_t getSize() const override { return sizeof(ThunkX86); } - - void writeTo(uint8_t *Buf) const override { - memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); - write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); - write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); - write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); - } - - void getBaserels(std::vector *Res) override { - Res->emplace_back(RVA + 3); - Res->emplace_back(RVA + 8); - } - - Defined *Imp = nullptr; - Chunk *Desc = nullptr; - Defined *Helper = nullptr; -}; - -class ThunkChunkARM : public Chunk { -public: - ThunkChunkARM(Defined *I, Chunk *D, Defined *H) - : Imp(I), Desc(D), Helper(H) {} - - size_t getSize() const override { return sizeof(ThunkARM); } - - void writeTo(uint8_t *Buf) const override { - memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM)); - applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase); - applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase); - applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34); - } - - void getBaserels(std::vector *Res) override { - Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); - Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); - } - - Defined *Imp = nullptr; - Chunk *Desc = nullptr; - Defined *Helper = nullptr; -}; - -// A chunk for the import descriptor table. -class DelayAddressChunk : public Chunk { -public: - explicit DelayAddressChunk(Chunk *C) : Thunk(C) { Alignment = ptrSize(); } - size_t getSize() const override { return ptrSize(); } - - void writeTo(uint8_t *Buf) const override { - if (Config->is64()) { - write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); - } else { - uint32_t Bit = 0; - // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT) - Bit = 1; - write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit); - } - } - - void getBaserels(std::vector *Res) override { - Res->emplace_back(RVA); - } - - Chunk *Thunk; -}; - -// Export table -// Read Microsoft PE/COFF spec 5.3 for details. - -// A chunk for the export descriptor table. -class ExportDirectoryChunk : public Chunk { -public: - ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) - : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), - OrdinalTab(O) {} - - size_t getSize() const override { - return sizeof(export_directory_table_entry); - } - - void writeTo(uint8_t *Buf) const override { - auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); - E->NameRVA = DLLName->getRVA(); - E->OrdinalBase = 0; - E->AddressTableEntries = MaxOrdinal + 1; - E->NumberOfNamePointers = NameTabSize; - E->ExportAddressTableRVA = AddressTab->getRVA(); - E->NamePointerRVA = NameTab->getRVA(); - E->OrdinalTableRVA = OrdinalTab->getRVA(); - } - - uint16_t MaxOrdinal; - uint16_t NameTabSize; - Chunk *DLLName; - Chunk *AddressTab; - Chunk *NameTab; - Chunk *OrdinalTab; -}; - -class AddressTableChunk : public Chunk { -public: - explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} - size_t getSize() const override { return Size * 4; } - - void writeTo(uint8_t *Buf) const override { - for (const Export &E : Config->Exports) { - uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; - uint32_t Bit = 0; - // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT && !E.Data) - Bit = 1; - if (E.ForwardChunk) { - write32le(P, E.ForwardChunk->getRVA() | Bit); - } else { - write32le(P, cast(E.Sym)->getRVA() | Bit); - } - } - } - -private: - size_t Size; -}; - -class NamePointersChunk : public Chunk { -public: - explicit NamePointersChunk(std::vector &V) : Chunks(V) {} - size_t getSize() const override { return Chunks.size() * 4; } - - void writeTo(uint8_t *Buf) const override { - uint8_t *P = Buf + OutputSectionOff; - for (Chunk *C : Chunks) { - write32le(P, C->getRVA()); - P += 4; - } - } - -private: - std::vector Chunks; -}; - -class ExportOrdinalChunk : public Chunk { -public: - explicit ExportOrdinalChunk(size_t I) : Size(I) {} - size_t getSize() const override { return Size * 2; } - - void writeTo(uint8_t *Buf) const override { - uint8_t *P = Buf + OutputSectionOff; - for (Export &E : Config->Exports) { - if (E.Noname) - continue; - write16le(P, E.Ordinal); - P += 2; - } - } - -private: - size_t Size; -}; - -} // anonymous namespace - -uint64_t IdataContents::getDirSize() { - return Dirs.size() * sizeof(ImportDirectoryTableEntry); -} - -uint64_t IdataContents::getIATSize() { - return Addresses.size() * ptrSize(); -} - -// Returns a list of .idata contents. -// See Microsoft PE/COFF spec 5.4 for details. -std::vector IdataContents::getChunks() { - create(); - - // The loader assumes a specific order of data. - // Add each type in the correct order. - std::vector V; - V.insert(V.end(), Dirs.begin(), Dirs.end()); - V.insert(V.end(), Lookups.begin(), Lookups.end()); - V.insert(V.end(), Addresses.begin(), Addresses.end()); - V.insert(V.end(), Hints.begin(), Hints.end()); - V.insert(V.end(), DLLNames.begin(), DLLNames.end()); - return V; -} - -void IdataContents::create() { - std::vector> V = binImports(Imports); - - // Create .idata contents for each DLL. - for (std::vector &Syms : V) { - // Create lookup and address tables. If they have external names, - // we need to create HintName chunks to store the names. - // If they don't (if they are import-by-ordinals), we store only - // ordinal values to the table. - size_t Base = Lookups.size(); - for (DefinedImportData *S : Syms) { - uint16_t Ord = S->getOrdinal(); - if (S->getExternalName().empty()) { - Lookups.push_back(make(Ord)); - Addresses.push_back(make(Ord)); - continue; - } - auto *C = make(S->getExternalName(), Ord); - Lookups.push_back(make(C)); - Addresses.push_back(make(C)); - Hints.push_back(C); - } - // Terminate with null values. - Lookups.push_back(make(ptrSize())); - Addresses.push_back(make(ptrSize())); - - for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I]); - - // Create the import table header. - DLLNames.push_back(make(Syms[0]->getDLLName())); - auto *Dir = make(DLLNames.back()); - Dir->LookupTab = Lookups[Base]; - Dir->AddressTab = Addresses[Base]; - Dirs.push_back(Dir); - } - // Add null terminator. - Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); -} - -std::vector DelayLoadContents::getChunks() { - std::vector V; - V.insert(V.end(), Dirs.begin(), Dirs.end()); - V.insert(V.end(), Names.begin(), Names.end()); - V.insert(V.end(), HintNames.begin(), HintNames.end()); - V.insert(V.end(), DLLNames.begin(), DLLNames.end()); - return V; -} - -std::vector DelayLoadContents::getDataChunks() { - std::vector V; - V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); - V.insert(V.end(), Addresses.begin(), Addresses.end()); - return V; -} - -uint64_t DelayLoadContents::getDirSize() { - return Dirs.size() * sizeof(delay_import_directory_table_entry); -} - -void DelayLoadContents::create(Defined *H) { - Helper = H; - std::vector> V = binImports(Imports); - - // Create .didat contents for each DLL. - for (std::vector &Syms : V) { - // Create the delay import table header. - DLLNames.push_back(make(Syms[0]->getDLLName())); - auto *Dir = make(DLLNames.back()); - - size_t Base = Addresses.size(); - for (DefinedImportData *S : Syms) { - Chunk *T = newThunkChunk(S, Dir); - auto *A = make(T); - Addresses.push_back(A); - Thunks.push_back(T); - StringRef ExtName = S->getExternalName(); - if (ExtName.empty()) { - Names.push_back(make(S->getOrdinal())); - } else { - auto *C = make(ExtName, 0); - Names.push_back(make(C)); - HintNames.push_back(C); - } - } - // Terminate with null values. - Addresses.push_back(make(8)); - Names.push_back(make(8)); - - for (int I = 0, E = Syms.size(); I < E; ++I) - Syms[I]->setLocation(Addresses[Base + I]); - auto *MH = make(8); - MH->Alignment = 8; - ModuleHandles.push_back(MH); - - // Fill the delay import table header fields. - Dir->ModuleHandle = MH; - Dir->AddressTab = Addresses[Base]; - Dir->NameTab = Names[Base]; - Dirs.push_back(Dir); - } - // Add null terminator. - Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); -} - -Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { - switch (Config->Machine) { - case AMD64: - return make(S, Dir, Helper); - case I386: - return make(S, Dir, Helper); - case ARMNT: - return make(S, Dir, Helper); - default: - llvm_unreachable("unsupported machine type"); - } -} - -EdataContents::EdataContents() { - uint16_t MaxOrdinal = 0; - for (Export &E : Config->Exports) - MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); - - auto *DLLName = make(sys::path::filename(Config->OutputFile)); - auto *AddressTab = make(MaxOrdinal); - std::vector Names; - for (Export &E : Config->Exports) - if (!E.Noname) - Names.push_back(make(E.ExportName)); - - std::vector Forwards; - for (Export &E : Config->Exports) { - if (E.ForwardTo.empty()) - continue; - E.ForwardChunk = make(E.ForwardTo); - Forwards.push_back(E.ForwardChunk); - } - - auto *NameTab = make(Names); - auto *OrdinalTab = make(Names.size()); - auto *Dir = make(MaxOrdinal, Names.size(), DLLName, - AddressTab, NameTab, OrdinalTab); - Chunks.push_back(Dir); - Chunks.push_back(DLLName); - Chunks.push_back(AddressTab); - Chunks.push_back(NameTab); - Chunks.push_back(OrdinalTab); - Chunks.insert(Chunks.end(), Names.begin(), Names.end()); - Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); -} - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DLL.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DLL.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DLL.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DLL.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -//===- DLL.h ----------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_DLL_H -#define LLD_COFF_DLL_H - -#include "Chunks.h" -#include "Symbols.h" - -namespace lld { -namespace coff { - -// Windows-specific. -// IdataContents creates all chunks for the DLL import table. -// You are supposed to call add() to add symbols and then -// call getChunks() to get a list of chunks. -class IdataContents { -public: - void add(DefinedImportData *Sym) { Imports.push_back(Sym); } - bool empty() { return Imports.empty(); } - std::vector getChunks(); - - uint64_t getDirRVA() { return Dirs[0]->getRVA(); } - uint64_t getDirSize(); - uint64_t getIATRVA() { return Addresses[0]->getRVA(); } - uint64_t getIATSize(); - -private: - void create(); - - std::vector Imports; - std::vector Dirs; - std::vector Lookups; - std::vector Addresses; - std::vector Hints; - std::vector DLLNames; -}; - -// Windows-specific. -// DelayLoadContents creates all chunks for the delay-load DLL import table. -class DelayLoadContents { -public: - void add(DefinedImportData *Sym) { Imports.push_back(Sym); } - bool empty() { return Imports.empty(); } - void create(Defined *Helper); - std::vector getChunks(); - std::vector getDataChunks(); - ArrayRef getCodeChunks() { return Thunks; } - - uint64_t getDirRVA() { return Dirs[0]->getRVA(); } - uint64_t getDirSize(); - -private: - Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); - - Defined *Helper; - std::vector Imports; - std::vector Dirs; - std::vector ModuleHandles; - std::vector Addresses; - std::vector Names; - std::vector HintNames; - std::vector Thunks; - std::vector DLLNames; -}; - -// Windows-specific. -// EdataContents creates all chunks for the DLL export table. -class EdataContents { -public: - EdataContents(); - std::vector Chunks; -}; - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Driver.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Driver.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Driver.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Driver.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1335 +0,0 @@ -//===- Driver.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Driver.h" -#include "Config.h" -#include "InputFiles.h" -#include "MinGW.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "Writer.h" -#include "lld/Common/Driver.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "lld/Common/Version.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/BinaryFormat/Magic.h" -#include "llvm/Object/ArchiveWriter.h" -#include "llvm/Object/COFFImportFile.h" -#include "llvm/Object/COFFModuleDefinition.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/TarWriter.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ToolDrivers/llvm-lib/LibDriver.h" -#include -#include - -#include - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::COFF; -using llvm::sys::Process; - -namespace lld { -namespace coff { - -Configuration *Config; -LinkerDriver *Driver; - -bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { - errorHandler().LogName = Args[0]; - errorHandler().ErrorOS = &Diag; - errorHandler().ColorDiagnostics = Diag.has_colors(); - errorHandler().ErrorLimitExceededMsg = - "too many errors emitted, stopping now" - " (use /ERRORLIMIT:0 to see all errors)"; - errorHandler().ExitEarly = CanExitEarly; - Config = make(); - Config->Argv = {Args.begin(), Args.end()}; - Config->CanExitEarly = CanExitEarly; - - Symtab = make(); - - Driver = make(); - Driver->link(Args); - - // Call exit() if we can to avoid calling destructors. - if (CanExitEarly) - exitLld(errorCount() ? 1 : 0); - - freeArena(); - return !errorCount(); -} - -// Drop directory components and replace extension with ".exe" or ".dll". -static std::string getOutputPath(StringRef Path) { - auto P = Path.find_last_of("\\/"); - StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); - const char* E = Config->DLL ? ".dll" : ".exe"; - return (S.substr(0, S.rfind('.')) + E).str(); -} - -// ErrorOr is not default constructible, so it cannot be used as the type -// parameter of a future. -// FIXME: We could open the file in createFutureForFile and avoid needing to -// return an error here, but for the moment that would cost us a file descriptor -// (a limited resource on Windows) for the duration that the future is pending. -typedef std::pair, std::error_code> MBErrPair; - -// Create a std::future that opens and maps a file using the best strategy for -// the host platform. -static std::future createFutureForFile(std::string Path) { -#if LLVM_ON_WIN32 - // On Windows, file I/O is relatively slow so it is best to do this - // asynchronously. - auto Strategy = std::launch::async; -#else - auto Strategy = std::launch::deferred; -#endif - return std::async(Strategy, [=]() { - auto MBOrErr = MemoryBuffer::getFile(Path); - if (!MBOrErr) - return MBErrPair{nullptr, MBOrErr.getError()}; - return MBErrPair{std::move(*MBOrErr), std::error_code()}; - }); -} - -MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { - MemoryBufferRef MBRef = *MB; - make>(std::move(MB)); // take ownership - - if (Driver->Tar) - Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), - MBRef.getBuffer()); - return MBRef; -} - -void LinkerDriver::addBuffer(std::unique_ptr MB, - bool WholeArchive) { - MemoryBufferRef MBRef = takeBuffer(std::move(MB)); - FilePaths.push_back(MBRef.getBufferIdentifier()); - - // File type is detected by contents, not by file extension. - switch (identify_magic(MBRef.getBuffer())) { - case file_magic::windows_resource: - Resources.push_back(MBRef); - break; - - case file_magic::archive: - if (WholeArchive) { - std::unique_ptr File = - CHECK(Archive::create(MBRef), - MBRef.getBufferIdentifier() + ": failed to parse archive"); - - for (MemoryBufferRef M : getArchiveMembers(File.get())) - addArchiveBuffer(M, "", MBRef.getBufferIdentifier()); - return; - } - Symtab->addFile(make(MBRef)); - break; - - case file_magic::bitcode: - Symtab->addFile(make(MBRef)); - break; - - case file_magic::coff_cl_gl_object: - error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " - "Recompile without /GL"); - break; - - default: - Symtab->addFile(make(MBRef)); - break; - } -} - -void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { - auto Future = - std::make_shared>(createFutureForFile(Path)); - std::string PathStr = Path; - enqueueTask([=]() { - auto MBOrErr = Future->get(); - if (MBOrErr.second) - error("could not open " + PathStr + ": " + MBOrErr.second.message()); - else - Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); - }); -} - -void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, - StringRef ParentName) { - file_magic Magic = identify_magic(MB.getBuffer()); - if (Magic == file_magic::coff_import_library) { - Symtab->addFile(make(MB)); - return; - } - - InputFile *Obj; - if (Magic == file_magic::coff_object) { - Obj = make(MB); - } else if (Magic == file_magic::bitcode) { - Obj = make(MB); - } else { - error("unknown file type: " + MB.getBufferIdentifier()); - return; - } - - Obj->ParentName = ParentName; - Symtab->addFile(Obj); - log("Loaded " + toString(Obj) + " for " + SymName); -} - -void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, - StringRef SymName, - StringRef ParentName) { - if (!C.getParent()->isThin()) { - MemoryBufferRef MB = CHECK( - C.getMemoryBufferRef(), - "could not get the buffer for the member defining symbol " + SymName); - enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); }); - return; - } - - auto Future = std::make_shared>(createFutureForFile( - CHECK(C.getFullName(), - "could not get the filename for the member defining symbol " + - SymName))); - enqueueTask([=]() { - auto MBOrErr = Future->get(); - if (MBOrErr.second) - fatal("could not get the buffer for the member defining " + SymName + - ": " + MBOrErr.second.message()); - Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, - ParentName); - }); -} - -static bool isDecorated(StringRef Sym) { - return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") || - (!Config->MinGW && Sym.contains('@')); -} - -// Parses .drectve section contents and returns a list of files -// specified by /defaultlib. -void LinkerDriver::parseDirectives(StringRef S) { - ArgParser Parser; - // .drectve is always tokenized using Windows shell rules. - opt::InputArgList Args = Parser.parseDirectives(S); - - for (auto *Arg : Args) { - switch (Arg->getOption().getUnaliasedOption().getID()) { - case OPT_aligncomm: - parseAligncomm(Arg->getValue()); - break; - case OPT_alternatename: - parseAlternateName(Arg->getValue()); - break; - case OPT_defaultlib: - if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path, false); - break; - case OPT_entry: - Config->Entry = addUndefined(mangle(Arg->getValue())); - break; - case OPT_export: { - // If a common header file contains dllexported function - // declarations, many object files may end up with having the - // same /EXPORT options. In order to save cost of parsing them, - // we dedup them first. - if (!DirectivesExports.insert(Arg->getValue()).second) - break; - - Export E = parseExport(Arg->getValue()); - if (Config->Machine == I386 && Config->MinGW) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - E.Directives = true; - Config->Exports.push_back(E); - break; - } - case OPT_failifmismatch: - checkFailIfMismatch(Arg->getValue()); - break; - case OPT_incl: - addUndefined(Arg->getValue()); - break; - case OPT_merge: - parseMerge(Arg->getValue()); - break; - case OPT_nodefaultlib: - Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); - break; - case OPT_section: - parseSection(Arg->getValue()); - break; - case OPT_subsystem: - parseSubsystem(Arg->getValue(), &Config->Subsystem, - &Config->MajorOSVersion, &Config->MinorOSVersion); - break; - case OPT_editandcontinue: - case OPT_fastfail: - case OPT_guardsym: - case OPT_natvis: - case OPT_throwingnew: - break; - default: - error(Arg->getSpelling() + " is not allowed in .drectve"); - } - } -} - -// Find file from search paths. You can omit ".obj", this function takes -// care of that. Note that the returned path is not guaranteed to exist. -StringRef LinkerDriver::doFindFile(StringRef Filename) { - bool HasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); - if (HasPathSep) - return Filename; - bool HasExt = Filename.contains('.'); - for (StringRef Dir : SearchPaths) { - SmallString<128> Path = Dir; - sys::path::append(Path, Filename); - if (sys::fs::exists(Path.str())) - return Saver.save(Path.str()); - if (!HasExt) { - Path.append(".obj"); - if (sys::fs::exists(Path.str())) - return Saver.save(Path.str()); - } - } - return Filename; -} - -// Resolves a file path. This never returns the same path -// (in that case, it returns None). -Optional LinkerDriver::findFile(StringRef Filename) { - StringRef Path = doFindFile(Filename); - bool Seen = !VisitedFiles.insert(Path.lower()).second; - if (Seen) - return None; - if (Path.endswith_lower(".lib")) - VisitedLibs.insert(sys::path::filename(Path)); - return Path; -} - -// Find library file from search path. -StringRef LinkerDriver::doFindLib(StringRef Filename) { - // Add ".lib" to Filename if that has no file extension. - bool HasExt = Filename.contains('.'); - if (!HasExt) - Filename = Saver.save(Filename + ".lib"); - return doFindFile(Filename); -} - -// Resolves a library path. /nodefaultlib options are taken into -// consideration. This never returns the same path (in that case, -// it returns None). -Optional LinkerDriver::findLib(StringRef Filename) { - if (Config->NoDefaultLibAll) - return None; - if (!VisitedLibs.insert(Filename.lower()).second) - return None; - StringRef Path = doFindLib(Filename); - if (Config->NoDefaultLibs.count(Path)) - return None; - if (!VisitedFiles.insert(Path.lower()).second) - return None; - return Path; -} - -// Parses LIB environment which contains a list of search paths. -void LinkerDriver::addLibSearchPaths() { - Optional EnvOpt = Process::GetEnv("LIB"); - if (!EnvOpt.hasValue()) - return; - StringRef Env = Saver.save(*EnvOpt); - while (!Env.empty()) { - StringRef Path; - std::tie(Path, Env) = Env.split(';'); - SearchPaths.push_back(Path); - } -} - -Symbol *LinkerDriver::addUndefined(StringRef Name) { - Symbol *B = Symtab->addUndefined(Name); - if (!B->IsGCRoot) { - B->IsGCRoot = true; - Config->GCRoot.push_back(B); - } - return B; -} - -// Symbol names are mangled by appending "_" prefix on x86. -StringRef LinkerDriver::mangle(StringRef Sym) { - assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); - if (Config->Machine == I386) - return Saver.save("_" + Sym); - return Sym; -} - -// Windows specific -- find default entry point name. -StringRef LinkerDriver::findDefaultEntry() { - // User-defined main functions and their corresponding entry points. - static const char *Entries[][2] = { - {"main", "mainCRTStartup"}, - {"wmain", "wmainCRTStartup"}, - {"WinMain", "WinMainCRTStartup"}, - {"wWinMain", "wWinMainCRTStartup"}, - }; - for (auto E : Entries) { - StringRef Entry = Symtab->findMangle(mangle(E[0])); - if (!Entry.empty() && !isa(Symtab->find(Entry))) - return mangle(E[1]); - } - return ""; -} - -WindowsSubsystem LinkerDriver::inferSubsystem() { - if (Config->DLL) - return IMAGE_SUBSYSTEM_WINDOWS_GUI; - if (Symtab->findUnderscore("main") || Symtab->findUnderscore("wmain")) - return IMAGE_SUBSYSTEM_WINDOWS_CUI; - if (Symtab->findUnderscore("WinMain") || Symtab->findUnderscore("wWinMain")) - return IMAGE_SUBSYSTEM_WINDOWS_GUI; - return IMAGE_SUBSYSTEM_UNKNOWN; -} - -static uint64_t getDefaultImageBase() { - if (Config->is64()) - return Config->DLL ? 0x180000000 : 0x140000000; - return Config->DLL ? 0x10000000 : 0x400000; -} - -static std::string createResponseFile(const opt::InputArgList &Args, - ArrayRef FilePaths, - ArrayRef SearchPaths) { - SmallString<0> Data; - raw_svector_ostream OS(Data); - - for (auto *Arg : Args) { - switch (Arg->getOption().getID()) { - case OPT_linkrepro: - case OPT_INPUT: - case OPT_defaultlib: - case OPT_libpath: - case OPT_manifest: - case OPT_manifest_colon: - case OPT_manifestdependency: - case OPT_manifestfile: - case OPT_manifestinput: - case OPT_manifestuac: - break; - default: - OS << toString(*Arg) << "\n"; - } - } - - for (StringRef Path : SearchPaths) { - std::string RelPath = relativeToRoot(Path); - OS << "/libpath:" << quote(RelPath) << "\n"; - } - - for (StringRef Path : FilePaths) - OS << quote(relativeToRoot(Path)) << "\n"; - - return Data.str(); -} - -static unsigned getDefaultDebugType(const opt::InputArgList &Args) { - unsigned DebugTypes = static_cast(DebugType::CV); - if (Args.hasArg(OPT_driver)) - DebugTypes |= static_cast(DebugType::PData); - if (Args.hasArg(OPT_profile)) - DebugTypes |= static_cast(DebugType::Fixup); - return DebugTypes; -} - -static unsigned parseDebugType(StringRef Arg) { - SmallVector Types; - Arg.split(Types, ',', /*KeepEmpty=*/false); - - unsigned DebugTypes = static_cast(DebugType::None); - for (StringRef Type : Types) - DebugTypes |= StringSwitch(Type.lower()) - .Case("cv", static_cast(DebugType::CV)) - .Case("pdata", static_cast(DebugType::PData)) - .Case("fixup", static_cast(DebugType::Fixup)) - .Default(0); - return DebugTypes; -} - -static std::string getMapFile(const opt::InputArgList &Args) { - auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); - if (!Arg) - return ""; - if (Arg->getOption().getID() == OPT_lldmap_file) - return Arg->getValue(); - - assert(Arg->getOption().getID() == OPT_lldmap); - StringRef OutFile = Config->OutputFile; - return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); -} - -static std::string getImplibPath() { - if (!Config->Implib.empty()) - return Config->Implib; - SmallString<128> Out = StringRef(Config->OutputFile); - sys::path::replace_extension(Out, ".lib"); - return Out.str(); -} - -// -// The import name is caculated as the following: -// -// | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY -// -----+----------------+---------------------+------------------ -// LINK | {value} | {value}.{.dll/.exe} | {output name} -// LIB | {value} | {value}.dll | {output name}.dll -// -static std::string getImportName(bool AsLib) { - SmallString<128> Out; - - if (Config->ImportName.empty()) { - Out.assign(sys::path::filename(Config->OutputFile)); - if (AsLib) - sys::path::replace_extension(Out, ".dll"); - } else { - Out.assign(Config->ImportName); - if (!sys::path::has_extension(Out)) - sys::path::replace_extension(Out, - (Config->DLL || AsLib) ? ".dll" : ".exe"); - } - - return Out.str(); -} - -static void createImportLibrary(bool AsLib) { - std::vector Exports; - for (Export &E1 : Config->Exports) { - COFFShortExport E2; - E2.Name = E1.Name; - E2.SymbolName = E1.SymbolName; - E2.ExtName = E1.ExtName; - E2.Ordinal = E1.Ordinal; - E2.Noname = E1.Noname; - E2.Data = E1.Data; - E2.Private = E1.Private; - E2.Constant = E1.Constant; - Exports.push_back(E2); - } - - auto E = writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports, - Config->Machine, false); - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); -} - -static void parseModuleDefs(StringRef Path) { - std::unique_ptr MB = CHECK( - MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); - COFFModuleDefinition M = check(parseCOFFModuleDefinition( - MB->getMemBufferRef(), Config->Machine, Config->MinGW)); - - if (Config->OutputFile.empty()) - Config->OutputFile = Saver.save(M.OutputFile); - Config->ImportName = Saver.save(M.ImportName); - if (M.ImageBase) - Config->ImageBase = M.ImageBase; - if (M.StackReserve) - Config->StackReserve = M.StackReserve; - if (M.StackCommit) - Config->StackCommit = M.StackCommit; - if (M.HeapReserve) - Config->HeapReserve = M.HeapReserve; - if (M.HeapCommit) - Config->HeapCommit = M.HeapCommit; - if (M.MajorImageVersion) - Config->MajorImageVersion = M.MajorImageVersion; - if (M.MinorImageVersion) - Config->MinorImageVersion = M.MinorImageVersion; - if (M.MajorOSVersion) - Config->MajorOSVersion = M.MajorOSVersion; - if (M.MinorOSVersion) - Config->MinorOSVersion = M.MinorOSVersion; - - for (COFFShortExport E1 : M.Exports) { - Export E2; - E2.Name = Saver.save(E1.Name); - if (E1.isWeak()) - E2.ExtName = Saver.save(E1.ExtName); - E2.Ordinal = E1.Ordinal; - E2.Noname = E1.Noname; - E2.Data = E1.Data; - E2.Private = E1.Private; - E2.Constant = E1.Constant; - Config->Exports.push_back(E2); - } -} - -// A helper function for filterBitcodeFiles. -static bool needsRebuilding(MemoryBufferRef MB) { - // The MSVC linker doesn't support thin archives, so if it's a thin - // archive, we always need to rebuild it. - std::unique_ptr File = - CHECK(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); - if (File->isThin()) - return true; - - // Returns true if the archive contains at least one bitcode file. - for (MemoryBufferRef Member : getArchiveMembers(File.get())) - if (identify_magic(Member.getBuffer()) == file_magic::bitcode) - return true; - return false; -} - -// Opens a given path as an archive file and removes bitcode files -// from them if exists. This function is to appease the MSVC linker as -// their linker doesn't like archive files containing non-native -// object files. -// -// If a given archive doesn't contain bitcode files, the archive path -// is returned as-is. Otherwise, a new temporary file is created and -// its path is returned. -static Optional -filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { - std::unique_ptr MB = CHECK( - MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); - MemoryBufferRef MBRef = MB->getMemBufferRef(); - file_magic Magic = identify_magic(MBRef.getBuffer()); - - if (Magic == file_magic::bitcode) - return None; - if (Magic != file_magic::archive) - return Path.str(); - if (!needsRebuilding(MBRef)) - return Path.str(); - - std::unique_ptr File = - CHECK(Archive::create(MBRef), - MBRef.getBufferIdentifier() + ": failed to parse archive"); - - std::vector New; - for (MemoryBufferRef Member : getArchiveMembers(File.get())) - if (identify_magic(Member.getBuffer()) != file_magic::bitcode) - New.emplace_back(Member); - - if (New.empty()) - return None; - - log("Creating a temporary archive for " + Path + " to remove bitcode files"); - - SmallString<128> S; - if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), - ".lib", S)) - fatal("cannot create a temporary file: " + EC.message()); - std::string Temp = S.str(); - TemporaryFiles.push_back(Temp); - - Error E = - llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, - /*Deterministics=*/true, - /*Thin=*/false); - handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { - error("failed to create a new archive " + S.str() + ": " + EI.message()); - }); - return Temp; -} - -// Create response file contents and invoke the MSVC linker. -void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { - std::string Rsp = "/nologo\n"; - std::vector Temps; - - // Write out archive members that we used in symbol resolution and pass these - // to MSVC before any archives, so that MSVC uses the same objects to satisfy - // references. - for (ObjFile *Obj : ObjFile::Instances) { - if (Obj->ParentName.empty()) - continue; - SmallString<128> S; - int Fd; - if (auto EC = sys::fs::createTemporaryFile( - "lld-" + sys::path::filename(Obj->ParentName), ".obj", Fd, S)) - fatal("cannot create a temporary file: " + EC.message()); - raw_fd_ostream OS(Fd, /*shouldClose*/ true); - OS << Obj->MB.getBuffer(); - Temps.push_back(S.str()); - Rsp += quote(S) + "\n"; - } - - for (auto *Arg : Args) { - switch (Arg->getOption().getID()) { - case OPT_linkrepro: - case OPT_lldmap: - case OPT_lldmap_file: - case OPT_lldsavetemps: - case OPT_msvclto: - // LLD-specific options are stripped. - break; - case OPT_opt: - if (!StringRef(Arg->getValue()).startswith("lld")) - Rsp += toString(*Arg) + " "; - break; - case OPT_INPUT: { - if (Optional Path = doFindFile(Arg->getValue())) { - if (Optional S = filterBitcodeFiles(*Path, Temps)) - Rsp += quote(*S) + "\n"; - continue; - } - Rsp += quote(Arg->getValue()) + "\n"; - break; - } - default: - Rsp += toString(*Arg) + "\n"; - } - } - - std::vector ObjFiles = Symtab->compileBitcodeFiles(); - runMSVCLinker(Rsp, ObjFiles); - - for (StringRef Path : Temps) - sys::fs::remove(Path); -} - -void LinkerDriver::enqueueTask(std::function Task) { - TaskQueue.push_back(std::move(Task)); -} - -bool LinkerDriver::run() { - bool DidWork = !TaskQueue.empty(); - while (!TaskQueue.empty()) { - TaskQueue.front()(); - TaskQueue.pop_front(); - } - return DidWork; -} - -void LinkerDriver::link(ArrayRef ArgsArr) { - // If the first command line argument is "/lib", link.exe acts like lib.exe. - // We call our own implementation of lib.exe that understands bitcode files. - if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { - if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) - fatal("lib failed"); - return; - } - - // Needed for LTO. - InitializeAllTargetInfos(); - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - InitializeAllAsmPrinters(); - InitializeAllDisassemblers(); - - // Parse command line options. - ArgParser Parser; - opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); - - // Parse and evaluate -mllvm options. - std::vector V; - V.push_back("lld-link (LLVM option parsing)"); - for (auto *Arg : Args.filtered(OPT_mllvm)) - V.push_back(Arg->getValue()); - cl::ParseCommandLineOptions(V.size(), V.data()); - - // Handle /errorlimit early, because error() depends on it. - if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { - int N = 20; - StringRef S = Arg->getValue(); - if (S.getAsInteger(10, N)) - error(Arg->getSpelling() + " number expected, but got " + S); - errorHandler().ErrorLimit = N; - } - - // Handle /help - if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); - return; - } - - // Handle --version, which is an lld extension. This option is a bit odd - // because it doesn't start with "/", but we deliberately chose "--" to - // avoid conflict with /version and for compatibility with clang-cl. - if (Args.hasArg(OPT_dash_dash_version)) { - outs() << getLLDVersion() << "\n"; - return; - } - - // Handle /lldmingw early, since it can potentially affect how other - // options are handled. - Config->MinGW = Args.hasArg(OPT_lldmingw); - - if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { - SmallString<64> Path = StringRef(Arg->getValue()); - sys::path::append(Path, "repro.tar"); - - Expected> ErrOrWriter = - TarWriter::create(Path, "repro"); - - if (ErrOrWriter) { - Tar = std::move(*ErrOrWriter); - } else { - error("/linkrepro: failed to open " + Path + ": " + - toString(ErrOrWriter.takeError())); - } - } - - if (!Args.hasArg(OPT_INPUT)) { - if (Args.hasArg(OPT_deffile)) - Config->NoEntry = true; - else - fatal("no input files"); - } - - // Construct search path list. - SearchPaths.push_back(""); - for (auto *Arg : Args.filtered(OPT_libpath)) - SearchPaths.push_back(Arg->getValue()); - addLibSearchPaths(); - - // Handle /ignore - for (auto *Arg : Args.filtered(OPT_ignore)) { - if (StringRef(Arg->getValue()) == "4217") - Config->WarnLocallyDefinedImported = false; - // Other warning numbers are ignored. - } - - // Handle /out - if (auto *Arg = Args.getLastArg(OPT_out)) - Config->OutputFile = Arg->getValue(); - - // Handle /verbose - if (Args.hasArg(OPT_verbose)) - Config->Verbose = true; - errorHandler().Verbose = Config->Verbose; - - // Handle /force or /force:unresolved - if (Args.hasArg(OPT_force, OPT_force_unresolved)) - Config->Force = true; - - // Handle /debug - if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { - Config->Debug = true; - if (auto *Arg = Args.getLastArg(OPT_debugtype)) - Config->DebugTypes = parseDebugType(Arg->getValue()); - else - Config->DebugTypes = getDefaultDebugType(Args); - } - - // Handle /pdb - bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); - if (ShouldCreatePDB) - if (auto *Arg = Args.getLastArg(OPT_pdb)) - Config->PDBPath = Arg->getValue(); - - // Handle /noentry - if (Args.hasArg(OPT_noentry)) { - if (Args.hasArg(OPT_dll)) - Config->NoEntry = true; - else - error("/noentry must be specified with /dll"); - } - - // Handle /dll - if (Args.hasArg(OPT_dll)) { - Config->DLL = true; - Config->ManifestID = 2; - } - - // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase - // because we need to explicitly check whether that option or its inverse was - // present in the argument list in order to handle /fixed. - auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); - if (DynamicBaseArg && - DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) - Config->DynamicBase = false; - - bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false); - if (Fixed) { - if (DynamicBaseArg && - DynamicBaseArg->getOption().getID() == OPT_dynamicbase) { - error("/fixed must not be specified with /dynamicbase"); - } else { - Config->Relocatable = false; - Config->DynamicBase = false; - } - } - - // Handle /appcontainer - Config->AppContainer = - Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); - - // Handle /machine - if (auto *Arg = Args.getLastArg(OPT_machine)) - Config->Machine = getMachineType(Arg->getValue()); - - // Handle /nodefaultlib: - for (auto *Arg : Args.filtered(OPT_nodefaultlib)) - Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); - - // Handle /nodefaultlib - if (Args.hasArg(OPT_nodefaultlib_all)) - Config->NoDefaultLibAll = true; - - // Handle /base - if (auto *Arg = Args.getLastArg(OPT_base)) - parseNumbers(Arg->getValue(), &Config->ImageBase); - - // Handle /stack - if (auto *Arg = Args.getLastArg(OPT_stack)) - parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); - - // Handle /heap - if (auto *Arg = Args.getLastArg(OPT_heap)) - parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); - - // Handle /version - if (auto *Arg = Args.getLastArg(OPT_version)) - parseVersion(Arg->getValue(), &Config->MajorImageVersion, - &Config->MinorImageVersion); - - // Handle /subsystem - if (auto *Arg = Args.getLastArg(OPT_subsystem)) - parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, - &Config->MinorOSVersion); - - // Handle /alternatename - for (auto *Arg : Args.filtered(OPT_alternatename)) - parseAlternateName(Arg->getValue()); - - // Handle /include - for (auto *Arg : Args.filtered(OPT_incl)) - addUndefined(Arg->getValue()); - - // Handle /implib - if (auto *Arg = Args.getLastArg(OPT_implib)) - Config->Implib = Arg->getValue(); - - // Handle /opt. - bool DoGC = !Args.hasArg(OPT_debug); - unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on - for (auto *Arg : Args.filtered(OPT_opt)) { - std::string Str = StringRef(Arg->getValue()).lower(); - SmallVector Vec; - StringRef(Str).split(Vec, ','); - for (StringRef S : Vec) { - if (S == "ref") { - DoGC = true; - } else if (S == "noref") { - DoGC = false; - } else if (S == "icf" || S.startswith("icf=")) { - ICFLevel = 2; - } else if (S == "noicf") { - ICFLevel = 0; - } else if (S.startswith("lldlto=")) { - StringRef OptLevel = S.substr(7); - if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || - Config->LTOOptLevel > 3) - error("/opt:lldlto: invalid optimization level: " + OptLevel); - } else if (S.startswith("lldltojobs=")) { - StringRef Jobs = S.substr(11); - if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) - error("/opt:lldltojobs: invalid job count: " + Jobs); - } else if (S.startswith("lldltopartitions=")) { - StringRef N = S.substr(17); - if (N.getAsInteger(10, Config->LTOPartitions) || - Config->LTOPartitions == 0) - error("/opt:lldltopartitions: invalid partition count: " + N); - } else if (S != "lbr" && S != "nolbr") - error("/opt: unknown option: " + S); - } - } - - // Limited ICF is enabled if GC is enabled and ICF was never mentioned - // explicitly. - // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical - // code. If the user passes /OPT:ICF explicitly, LLD should merge identical - // comdat readonly data. - if (ICFLevel == 1 && !DoGC) - ICFLevel = 0; - Config->DoGC = DoGC; - Config->DoICF = ICFLevel > 0; - - // Handle /lldsavetemps - if (Args.hasArg(OPT_lldsavetemps)) - Config->SaveTemps = true; - - // Handle /lldltocache - if (auto *Arg = Args.getLastArg(OPT_lldltocache)) - Config->LTOCache = Arg->getValue(); - - // Handle /lldsavecachepolicy - if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy)) - Config->LTOCachePolicy = CHECK( - parseCachePruningPolicy(Arg->getValue()), - Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue()); - - // Handle /failifmismatch - for (auto *Arg : Args.filtered(OPT_failifmismatch)) - checkFailIfMismatch(Arg->getValue()); - - // Handle /merge - for (auto *Arg : Args.filtered(OPT_merge)) - parseMerge(Arg->getValue()); - - // Handle /section - for (auto *Arg : Args.filtered(OPT_section)) - parseSection(Arg->getValue()); - - // Handle /aligncomm - for (auto *Arg : Args.filtered(OPT_aligncomm)) - parseAligncomm(Arg->getValue()); - - // Handle /manifestdependency. This enables /manifest unless /manifest:no is - // also passed. - if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { - Config->ManifestDependency = Arg->getValue(); - Config->Manifest = Configuration::SideBySide; - } - - // Handle /manifest and /manifest: - if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { - if (Arg->getOption().getID() == OPT_manifest) - Config->Manifest = Configuration::SideBySide; - else - parseManifest(Arg->getValue()); - } - - // Handle /manifestuac - if (auto *Arg = Args.getLastArg(OPT_manifestuac)) - parseManifestUAC(Arg->getValue()); - - // Handle /manifestfile - if (auto *Arg = Args.getLastArg(OPT_manifestfile)) - Config->ManifestFile = Arg->getValue(); - - // Handle /manifestinput - for (auto *Arg : Args.filtered(OPT_manifestinput)) - Config->ManifestInput.push_back(Arg->getValue()); - - if (!Config->ManifestInput.empty() && - Config->Manifest != Configuration::Embed) { - fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED"); - } - - // Handle miscellaneous boolean flags. - Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); - Config->AllowIsolation = - Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); - Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); - Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); - Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf); - Config->DebugGHashes = Args.hasArg(OPT_debug_ghash); - - Config->MapFile = getMapFile(Args); - - if (errorCount()) - return; - - bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); - // Create a list of input files. Files can be given as arguments - // for /defaultlib option. - std::vector MBs; - for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) { - switch (Arg->getOption().getID()) { - case OPT_INPUT: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, WholeArchiveFlag); - break; - case OPT_wholearchive_file: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, true); - break; - } - } - for (auto *Arg : Args.filtered(OPT_defaultlib)) - if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path, false); - - // Windows specific -- Create a resource file containing a manifest file. - if (Config->Manifest == Configuration::Embed) - addBuffer(createManifestRes(), false); - - // Read all input files given via the command line. - run(); - - // We should have inferred a machine type by now from the input files, but if - // not we assume x64. - if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { - warn("/machine is not specified. x64 is assumed"); - Config->Machine = AMD64; - } - - // Input files can be Windows resource files (.res files). We use - // WindowsResource to convert resource files to a regular COFF file, - // then link the resulting file normally. - if (!Resources.empty()) - Symtab->addFile(make(convertResToCOFF(Resources))); - - if (Tar) - Tar->append("response.txt", - createResponseFile(Args, FilePaths, - ArrayRef(SearchPaths).slice(1))); - - // Handle /largeaddressaware - Config->LargeAddressAware = Args.hasFlag( - OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64()); - - // Handle /highentropyva - Config->HighEntropyVA = - Config->is64() && - Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); - - if (!Config->DynamicBase && - (Config->Machine == ARMNT || Config->Machine == ARM64)) - error("/dynamicbase:no is not compatible with " + - machineToStr(Config->Machine)); - - // Handle /entry and /dll - if (auto *Arg = Args.getLastArg(OPT_entry)) { - Config->Entry = addUndefined(mangle(Arg->getValue())); - } else if (!Config->Entry && !Config->NoEntry) { - if (Args.hasArg(OPT_dll)) { - StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" - : "_DllMainCRTStartup"; - Config->Entry = addUndefined(S); - } else { - // Windows specific -- If entry point name is not given, we need to - // infer that from user-defined entry name. - StringRef S = findDefaultEntry(); - if (S.empty()) - fatal("entry point must be defined"); - Config->Entry = addUndefined(S); - log("Entry name inferred: " + S); - } - } - - // Handle /export - for (auto *Arg : Args.filtered(OPT_export)) { - Export E = parseExport(Arg->getValue()); - if (Config->Machine == I386) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - Config->Exports.push_back(E); - } - - // Handle /def - if (auto *Arg = Args.getLastArg(OPT_deffile)) { - // parseModuleDefs mutates Config object. - parseModuleDefs(Arg->getValue()); - } - - // Handle generation of import library from a def file. - if (!Args.hasArg(OPT_INPUT)) { - fixupExports(); - createImportLibrary(/*AsLib=*/true); - return; - } - - // Handle /delayload - for (auto *Arg : Args.filtered(OPT_delayload)) { - Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); - if (Config->Machine == I386) { - Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); - } else { - Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); - } - } - - // Set default image name if neither /out or /def set it. - if (Config->OutputFile.empty()) { - Config->OutputFile = - getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); - } - - // Put the PDB next to the image if no /pdb flag was passed. - if (ShouldCreatePDB && Config->PDBPath.empty()) { - Config->PDBPath = Config->OutputFile; - sys::path::replace_extension(Config->PDBPath, ".pdb"); - } - - // Set default image base if /base is not given. - if (Config->ImageBase == uint64_t(-1)) - Config->ImageBase = getDefaultImageBase(); - - Symtab->addSynthetic(mangle("__ImageBase"), nullptr); - if (Config->Machine == I386) { - Symtab->addAbsolute("___safe_se_handler_table", 0); - Symtab->addAbsolute("___safe_se_handler_count", 0); - } - - // We do not support /guard:cf (control flow protection) yet. - // Define CFG symbols anyway so that we can link MSVC 2015 CRT. - Symtab->addAbsolute(mangle("__guard_fids_count"), 0); - Symtab->addAbsolute(mangle("__guard_fids_table"), 0); - Symtab->addAbsolute(mangle("__guard_flags"), 0x100); - Symtab->addAbsolute(mangle("__guard_iat_count"), 0); - Symtab->addAbsolute(mangle("__guard_iat_table"), 0); - Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); - Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); - // Needed for MSVC 2017 15.5 CRT. - Symtab->addAbsolute(mangle("__enclave_config"), 0); - - // This code may add new undefined symbols to the link, which may enqueue more - // symbol resolution tasks, so we need to continue executing tasks until we - // converge. - do { - // Windows specific -- if entry point is not found, - // search for its mangled names. - if (Config->Entry) - Symtab->mangleMaybe(Config->Entry); - - // Windows specific -- Make sure we resolve all dllexported symbols. - for (Export &E : Config->Exports) { - if (!E.ForwardTo.empty()) - continue; - E.Sym = addUndefined(E.Name); - if (!E.Directives) - Symtab->mangleMaybe(E.Sym); - } - - // Add weak aliases. Weak aliases is a mechanism to give remaining - // undefined symbols final chance to be resolved successfully. - for (auto Pair : Config->AlternateNames) { - StringRef From = Pair.first; - StringRef To = Pair.second; - Symbol *Sym = Symtab->find(From); - if (!Sym) - continue; - if (auto *U = dyn_cast(Sym)) - if (!U->WeakAlias) - U->WeakAlias = Symtab->addUndefined(To); - } - - // Windows specific -- if __load_config_used can be resolved, resolve it. - if (Symtab->findUnderscore("_load_config_used")) - addUndefined(mangle("_load_config_used")); - } while (run()); - - if (errorCount()) - return; - - // If /msvclto is given, we use the MSVC linker to link LTO output files. - // This is useful because MSVC link.exe can generate complete PDBs. - if (Args.hasArg(OPT_msvclto)) { - invokeMSVC(Args); - return; - } - - // Do LTO by compiling bitcode input files to a set of native COFF files then - // link those files. - Symtab->addCombinedLTOObjects(); - run(); - - // Make sure we have resolved all symbols. - Symtab->reportRemainingUndefines(); - if (errorCount()) - return; - - // Windows specific -- if no /subsystem is given, we need to infer - // that from entry point name. - if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { - Config->Subsystem = inferSubsystem(); - if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) - fatal("subsystem must be defined"); - } - - // Handle /safeseh. - if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { - for (ObjFile *File : ObjFile::Instances) - if (!File->SEHCompat) - error("/safeseh: " + File->getName() + " is not compatible with SEH"); - if (errorCount()) - return; - } - - // In MinGW, all symbols are automatically exported if no symbols - // are chosen to be exported. - if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) || - Args.hasArg(OPT_export_all_symbols))) { - AutoExporter Exporter; - - Symtab->forEachSymbol([=](Symbol *S) { - auto *Def = dyn_cast(S); - if (!Exporter.shouldExport(Def)) - return; - Export E; - E.Name = Def->getName(); - E.Sym = Def; - if (Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) - E.Data = true; - Config->Exports.push_back(E); - }); - } - - // Windows specific -- when we are creating a .dll file, we also - // need to create a .lib file. - if (!Config->Exports.empty() || Config->DLL) { - fixupExports(); - createImportLibrary(/*AsLib=*/false); - assignExportOrdinals(); - } - - // Handle /output-def (MinGW specific). - if (auto *Arg = Args.getLastArg(OPT_output_def)) - writeDefFile(Arg->getValue()); - - // Set extra alignment for .comm symbols - for (auto Pair : Config->AlignComm) { - StringRef Name = Pair.first; - uint32_t Alignment = Pair.second; - - Symbol *Sym = Symtab->find(Name); - if (!Sym) { - warn("/aligncomm symbol " + Name + " not found"); - continue; - } - - auto *DC = dyn_cast(Sym); - if (!DC) { - warn("/aligncomm symbol " + Name + " of wrong kind"); - continue; - } - - CommonChunk *C = DC->getChunk(); - C->Alignment = std::max(C->Alignment, Alignment); - } - - // Windows specific -- Create a side-by-side manifest file. - if (Config->Manifest == Configuration::SideBySide) - createSideBySideManifest(); - - // Identify unreferenced COMDAT sections. - if (Config->DoGC) - markLive(Symtab->getChunks()); - - // Identify identical COMDAT sections to merge them. - if (Config->DoICF) - doICF(Symtab->getChunks()); - - // Write the result. - writeResult(); -} - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Driver.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Driver.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Driver.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Driver.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -//===- Driver.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_DRIVER_H -#define LLD_COFF_DRIVER_H - -#include "Config.h" -#include "SymbolTable.h" -#include "lld/Common/LLVM.h" -#include "lld/Common/Reproduce.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/COFF.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/TarWriter.h" -#include -#include -#include - -namespace lld { -namespace coff { - -class LinkerDriver; -extern LinkerDriver *Driver; - -using llvm::COFF::MachineTypes; -using llvm::COFF::WindowsSubsystem; -using llvm::Optional; - -// Implemented in MarkLive.cpp. -void markLive(ArrayRef Chunks); - -// Implemented in ICF.cpp. -void doICF(ArrayRef Chunks); - -class COFFOptTable : public llvm::opt::OptTable { -public: - COFFOptTable(); -}; - -class ArgParser { -public: - // Concatenate LINK environment variable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(std::vector Args); - - // Tokenizes a given string and then parses as command line options. - llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } - - // Tokenizes a given string and then parses as command line options in - // .drectve section. - llvm::opt::InputArgList parseDirectives(StringRef S); - -private: - // Parses command line options. - llvm::opt::InputArgList parse(llvm::ArrayRef Args); - - std::vector tokenize(StringRef S); - - COFFOptTable Table; -}; - -class LinkerDriver { -public: - void link(llvm::ArrayRef Args); - - // Used by the resolver to parse .drectve section contents. - void parseDirectives(StringRef S); - - // Used by ArchiveFile to enqueue members. - void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, - StringRef ParentName); - - MemoryBufferRef takeBuffer(std::unique_ptr MB); - -private: - std::unique_ptr Tar; // for /linkrepro - - // Opens a file. Path has to be resolved already. - MemoryBufferRef openFile(StringRef Path); - - // Searches a file from search paths. - Optional findFile(StringRef Filename); - Optional findLib(StringRef Filename); - StringRef doFindFile(StringRef Filename); - StringRef doFindLib(StringRef Filename); - - // Parses LIB environment which contains a list of search paths. - void addLibSearchPaths(); - - // Library search path. The first element is always "" (current directory). - std::vector SearchPaths; - std::set VisitedFiles; - std::set VisitedLibs; - - Symbol *addUndefined(StringRef Sym); - StringRef mangle(StringRef Sym); - - // Windows specific -- "main" is not the only main function in Windows. - // You can choose one from these four -- {w,}{WinMain,main}. - // There are four different entry point functions for them, - // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to - // choose the right one depending on which "main" function is defined. - // This function looks up the symbol table and resolve corresponding - // entry point name. - StringRef findDefaultEntry(); - WindowsSubsystem inferSubsystem(); - - void invokeMSVC(llvm::opt::InputArgList &Args); - - void addBuffer(std::unique_ptr MB, bool WholeArchive); - void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, - StringRef ParentName); - - void enqueuePath(StringRef Path, bool WholeArchive); - - void enqueueTask(std::function Task); - bool run(); - - std::list> TaskQueue; - std::vector FilePaths; - std::vector Resources; - - llvm::StringSet<> DirectivesExports; -}; - -// Functions below this line are defined in DriverUtils.cpp. - -void printHelp(const char *Argv0); - -// For /machine option. -MachineTypes getMachineType(StringRef Arg); -StringRef machineToStr(MachineTypes MT); - -// Parses a string in the form of "[,]". -void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); - -// Parses a string in the form of "[.]". -// Minor's default value is 0. -void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); - -// Parses a string in the form of "[,[.]]". -void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, - uint32_t *Minor); - -void parseAlternateName(StringRef); -void parseMerge(StringRef); -void parseSection(StringRef); -void parseAligncomm(StringRef); - -// Parses a string in the form of "EMBED[,=]|NO". -void parseManifest(StringRef Arg); - -// Parses a string in the form of "level=|uiAccess=" -void parseManifestUAC(StringRef Arg); - -// Create a resource file containing a manifest XML. -std::unique_ptr createManifestRes(); -void createSideBySideManifest(); - -// Used for dllexported symbols. -Export parseExport(StringRef Arg); -void fixupExports(); -void assignExportOrdinals(); - -// Parses a string in the form of "key=value" and check -// if value matches previous values for the key. -// This feature used in the directive section to reject -// incompatible objects. -void checkFailIfMismatch(StringRef Arg); - -// Convert Windows resource files (.res files) to a .obj file. -MemoryBufferRef convertResToCOFF(ArrayRef MBs); - -void runMSVCLinker(std::string Rsp, ArrayRef Objects); - -// Create enum with OPT_xxx values for each option in Options.td -enum { - OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, -#include "Options.inc" -#undef OPTION -}; - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DriverUtils.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DriverUtils.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/DriverUtils.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/DriverUtils.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,796 +0,0 @@ -//===- DriverUtils.cpp ----------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains utility functions for the driver. Because there -// are so many small functions, we created this separate file to make -// Driver.cpp less cluttered. -// -//===----------------------------------------------------------------------===// - -#include "Config.h" -#include "Driver.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/WindowsResource.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileUtilities.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/WindowsManifest/WindowsManifestMerger.h" -#include - -using namespace llvm::COFF; -using namespace llvm; -using llvm::sys::Process; - -namespace lld { -namespace coff { -namespace { - -const uint16_t SUBLANG_ENGLISH_US = 0x0409; -const uint16_t RT_MANIFEST = 24; - -class Executor { -public: - explicit Executor(StringRef S) : Prog(Saver.save(S)) {} - void add(StringRef S) { Args.push_back(Saver.save(S)); } - void add(std::string &S) { Args.push_back(Saver.save(S)); } - void add(Twine S) { Args.push_back(Saver.save(S)); } - void add(const char *S) { Args.push_back(Saver.save(S)); } - - void run() { - ErrorOr ExeOrErr = sys::findProgramByName(Prog); - if (auto EC = ExeOrErr.getError()) - fatal("unable to find " + Prog + " in PATH: " + EC.message()); - StringRef Exe = Saver.save(*ExeOrErr); - Args.insert(Args.begin(), Exe); - - std::vector Vec; - for (StringRef S : Args) - Vec.push_back(S.data()); - Vec.push_back(nullptr); - - if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0) - fatal("ExecuteAndWait failed: " + - llvm::join(Args.begin(), Args.end(), " ")); - } - -private: - StringRef Prog; - std::vector Args; -}; - -} // anonymous namespace - -// Returns /machine's value. -MachineTypes getMachineType(StringRef S) { - MachineTypes MT = StringSwitch(S.lower()) - .Cases("x64", "amd64", AMD64) - .Cases("x86", "i386", I386) - .Case("arm", ARMNT) - .Case("arm64", ARM64) - .Default(IMAGE_FILE_MACHINE_UNKNOWN); - if (MT != IMAGE_FILE_MACHINE_UNKNOWN) - return MT; - fatal("unknown /machine argument: " + S); -} - -StringRef machineToStr(MachineTypes MT) { - switch (MT) { - case ARMNT: - return "arm"; - case ARM64: - return "arm64"; - case AMD64: - return "x64"; - case I386: - return "x86"; - default: - llvm_unreachable("unknown machine type"); - } -} - -// Parses a string in the form of "[,]". -void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) { - StringRef S1, S2; - std::tie(S1, S2) = Arg.split(','); - if (S1.getAsInteger(0, *Addr)) - fatal("invalid number: " + S1); - if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) - fatal("invalid number: " + S2); -} - -// Parses a string in the form of "[.]". -// If second number is not present, Minor is set to 0. -void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { - StringRef S1, S2; - std::tie(S1, S2) = Arg.split('.'); - if (S1.getAsInteger(0, *Major)) - fatal("invalid number: " + S1); - *Minor = 0; - if (!S2.empty() && S2.getAsInteger(0, *Minor)) - fatal("invalid number: " + S2); -} - -// Parses a string in the form of "[,[.]]". -void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, - uint32_t *Minor) { - StringRef SysStr, Ver; - std::tie(SysStr, Ver) = Arg.split(','); - *Sys = StringSwitch(SysStr.lower()) - .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) - .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI) - .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION) - .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) - .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM) - .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) - .Case("native", IMAGE_SUBSYSTEM_NATIVE) - .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI) - .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI) - .Default(IMAGE_SUBSYSTEM_UNKNOWN); - if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) - fatal("unknown subsystem: " + SysStr); - if (!Ver.empty()) - parseVersion(Ver, Major, Minor); -} - -// Parse a string of the form of "=". -// Results are directly written to Config. -void parseAlternateName(StringRef S) { - StringRef From, To; - std::tie(From, To) = S.split('='); - if (From.empty() || To.empty()) - fatal("/alternatename: invalid argument: " + S); - auto It = Config->AlternateNames.find(From); - if (It != Config->AlternateNames.end() && It->second != To) - fatal("/alternatename: conflicts: " + S); - Config->AlternateNames.insert(It, std::make_pair(From, To)); -} - -// Parse a string of the form of "=". -// Results are directly written to Config. -void parseMerge(StringRef S) { - StringRef From, To; - std::tie(From, To) = S.split('='); - if (From.empty() || To.empty()) - fatal("/merge: invalid argument: " + S); - auto Pair = Config->Merge.insert(std::make_pair(From, To)); - bool Inserted = Pair.second; - if (!Inserted) { - StringRef Existing = Pair.first->second; - if (Existing != To) - warn(S + ": already merged into " + Existing); - } -} - -static uint32_t parseSectionAttributes(StringRef S) { - uint32_t Ret = 0; - for (char C : S.lower()) { - switch (C) { - case 'd': - Ret |= IMAGE_SCN_MEM_DISCARDABLE; - break; - case 'e': - Ret |= IMAGE_SCN_MEM_EXECUTE; - break; - case 'k': - Ret |= IMAGE_SCN_MEM_NOT_CACHED; - break; - case 'p': - Ret |= IMAGE_SCN_MEM_NOT_PAGED; - break; - case 'r': - Ret |= IMAGE_SCN_MEM_READ; - break; - case 's': - Ret |= IMAGE_SCN_MEM_SHARED; - break; - case 'w': - Ret |= IMAGE_SCN_MEM_WRITE; - break; - default: - fatal("/section: invalid argument: " + S); - } - } - return Ret; -} - -// Parses /section option argument. -void parseSection(StringRef S) { - StringRef Name, Attrs; - std::tie(Name, Attrs) = S.split(','); - if (Name.empty() || Attrs.empty()) - fatal("/section: invalid argument: " + S); - Config->Section[Name] = parseSectionAttributes(Attrs); -} - -// Parses /aligncomm option argument. -void parseAligncomm(StringRef S) { - StringRef Name, Align; - std::tie(Name, Align) = S.split(','); - if (Name.empty() || Align.empty()) { - error("/aligncomm: invalid argument: " + S); - return; - } - int V; - if (Align.getAsInteger(0, V)) { - error("/aligncomm: invalid argument: " + S); - return; - } - Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V); -} - -// Parses a string in the form of "EMBED[,=]|NO". -// Results are directly written to Config. -void parseManifest(StringRef Arg) { - if (Arg.equals_lower("no")) { - Config->Manifest = Configuration::No; - return; - } - if (!Arg.startswith_lower("embed")) - fatal("invalid option " + Arg); - Config->Manifest = Configuration::Embed; - Arg = Arg.substr(strlen("embed")); - if (Arg.empty()) - return; - if (!Arg.startswith_lower(",id=")) - fatal("invalid option " + Arg); - Arg = Arg.substr(strlen(",id=")); - if (Arg.getAsInteger(0, Config->ManifestID)) - fatal("invalid option " + Arg); -} - -// Parses a string in the form of "level=|uiAccess=|NO". -// Results are directly written to Config. -void parseManifestUAC(StringRef Arg) { - if (Arg.equals_lower("no")) { - Config->ManifestUAC = false; - return; - } - for (;;) { - Arg = Arg.ltrim(); - if (Arg.empty()) - return; - if (Arg.startswith_lower("level=")) { - Arg = Arg.substr(strlen("level=")); - std::tie(Config->ManifestLevel, Arg) = Arg.split(" "); - continue; - } - if (Arg.startswith_lower("uiaccess=")) { - Arg = Arg.substr(strlen("uiaccess=")); - std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" "); - continue; - } - fatal("invalid option " + Arg); - } -} - -// An RAII temporary file class that automatically removes a temporary file. -namespace { -class TemporaryFile { -public: - TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { - SmallString<128> S; - if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) - fatal("cannot create a temporary file: " + EC.message()); - Path = S.str(); - - if (!Contents.empty()) { - std::error_code EC; - raw_fd_ostream OS(Path, EC, sys::fs::F_None); - if (EC) - fatal("failed to open " + Path + ": " + EC.message()); - OS << Contents; - } - } - - TemporaryFile(TemporaryFile &&Obj) { - std::swap(Path, Obj.Path); - } - - ~TemporaryFile() { - if (Path.empty()) - return; - if (sys::fs::remove(Path)) - fatal("failed to remove " + Path); - } - - // Returns a memory buffer of this temporary file. - // Note that this function does not leave the file open, - // so it is safe to remove the file immediately after this function - // is called (you cannot remove an opened file on Windows.) - std::unique_ptr getMemoryBuffer() { - // IsVolatileSize=true forces MemoryBuffer to not use mmap(). - return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false, - /*IsVolatileSize=*/true), - "could not open " + Path); - } - - std::string Path; -}; -} - -static std::string createDefaultXml() { - std::string Ret; - raw_string_ostream OS(Ret); - - // Emit the XML. Note that we do *not* verify that the XML attributes are - // syntactically correct. This is intentional for link.exe compatibility. - OS << "\n" - << "\n"; - if (Config->ManifestUAC) { - OS << " \n" - << " \n" - << " \n" - << " \n" - << " \n" - << " \n" - << " \n"; - } - if (!Config->ManifestDependency.empty()) { - OS << " \n" - << " \n" - << " ManifestDependency << " />\n" - << " \n" - << " \n"; - } - OS << "\n"; - return OS.str(); -} - -static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) { - std::unique_ptr DefaultXmlCopy = - MemoryBuffer::getMemBufferCopy(DefaultXml); - - windows_manifest::WindowsManifestMerger Merger; - if (auto E = Merger.merge(*DefaultXmlCopy.get())) - fatal("internal manifest tool failed on default xml: " + - toString(std::move(E))); - - for (StringRef Filename : Config->ManifestInput) { - std::unique_ptr Manifest = - check(MemoryBuffer::getFile(Filename)); - if (auto E = Merger.merge(*Manifest.get())) - fatal("internal manifest tool failed on file " + Filename + ": " + - toString(std::move(E))); - } - - return Merger.getMergedManifest().get()->getBuffer(); -} - -static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) { - // Create the default manifest file as a temporary file. - TemporaryFile Default("defaultxml", "manifest"); - std::error_code EC; - raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); - if (EC) - fatal("failed to open " + Default.Path + ": " + EC.message()); - OS << DefaultXml; - OS.close(); - - // Merge user-supplied manifests if they are given. Since libxml2 is not - // enabled, we must shell out to Microsoft's mt.exe tool. - TemporaryFile User("user", "manifest"); - - Executor E("mt.exe"); - E.add("/manifest"); - E.add(Default.Path); - for (StringRef Filename : Config->ManifestInput) { - E.add("/manifest"); - E.add(Filename); - } - E.add("/nologo"); - E.add("/out:" + StringRef(User.Path)); - E.run(); - - return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path) - .get() - ->getBuffer(); -} - -static std::string createManifestXml() { - std::string DefaultXml = createDefaultXml(); - if (Config->ManifestInput.empty()) - return DefaultXml; - - if (windows_manifest::isAvailable()) - return createManifestXmlWithInternalMt(DefaultXml); - - return createManifestXmlWithExternalMt(DefaultXml); -} - -static std::unique_ptr -createMemoryBufferForManifestRes(size_t ManifestSize) { - size_t ResSize = alignTo( - object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + - sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + - sizeof(object::WinResHeaderSuffix) + ManifestSize, - object::WIN_RES_DATA_ALIGNMENT); - return MemoryBuffer::getNewMemBuffer(ResSize, - Config->OutputFile + ".manifest.res"); -} - -static void writeResFileHeader(char *&Buf) { - memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); - Buf += sizeof(COFF::WinResMagic); - memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); - Buf += object::WIN_RES_NULL_ENTRY_SIZE; -} - -static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { - // Write the prefix. - auto *Prefix = reinterpret_cast(Buf); - Prefix->DataSize = ManifestSize; - Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + - sizeof(object::WinResIDs) + - sizeof(object::WinResHeaderSuffix); - Buf += sizeof(object::WinResHeaderPrefix); - - // Write the Type/Name IDs. - auto *IDs = reinterpret_cast(Buf); - IDs->setType(RT_MANIFEST); - IDs->setName(Config->ManifestID); - Buf += sizeof(object::WinResIDs); - - // Write the suffix. - auto *Suffix = reinterpret_cast(Buf); - Suffix->DataVersion = 0; - Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; - Suffix->Language = SUBLANG_ENGLISH_US; - Suffix->Version = 0; - Suffix->Characteristics = 0; - Buf += sizeof(object::WinResHeaderSuffix); -} - -// Create a resource file containing a manifest XML. -std::unique_ptr createManifestRes() { - std::string Manifest = createManifestXml(); - - std::unique_ptr Res = - createMemoryBufferForManifestRes(Manifest.size()); - - char *Buf = const_cast(Res->getBufferStart()); - writeResFileHeader(Buf); - writeResEntryHeader(Buf, Manifest.size()); - - // Copy the manifest data into the .res file. - std::copy(Manifest.begin(), Manifest.end(), Buf); - return Res; -} - -void createSideBySideManifest() { - std::string Path = Config->ManifestFile; - if (Path == "") - Path = Config->OutputFile + ".manifest"; - std::error_code EC; - raw_fd_ostream Out(Path, EC, sys::fs::F_Text); - if (EC) - fatal("failed to create manifest: " + EC.message()); - Out << createManifestXml(); -} - -// Parse a string in the form of -// "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]" -// or "=.". -// Used for parsing /export arguments. -Export parseExport(StringRef Arg) { - Export E; - StringRef Rest; - std::tie(E.Name, Rest) = Arg.split(","); - if (E.Name.empty()) - goto err; - - if (E.Name.contains('=')) { - StringRef X, Y; - std::tie(X, Y) = E.Name.split("="); - - // If "=.". - if (Y.contains(".")) { - E.Name = X; - E.ForwardTo = Y; - return E; - } - - E.ExtName = X; - E.Name = Y; - if (E.Name.empty()) - goto err; - } - - // If "=[,@ordinal[,NONAME]][,DATA][,PRIVATE]" - while (!Rest.empty()) { - StringRef Tok; - std::tie(Tok, Rest) = Rest.split(","); - if (Tok.equals_lower("noname")) { - if (E.Ordinal == 0) - goto err; - E.Noname = true; - continue; - } - if (Tok.equals_lower("data")) { - E.Data = true; - continue; - } - if (Tok.equals_lower("constant")) { - E.Constant = true; - continue; - } - if (Tok.equals_lower("private")) { - E.Private = true; - continue; - } - if (Tok.startswith("@")) { - int32_t Ord; - if (Tok.substr(1).getAsInteger(0, Ord)) - goto err; - if (Ord <= 0 || 65535 < Ord) - goto err; - E.Ordinal = Ord; - continue; - } - goto err; - } - return E; - -err: - fatal("invalid /export: " + Arg); -} - -static StringRef undecorate(StringRef Sym) { - if (Config->Machine != I386) - return Sym; - return Sym.startswith("_") ? Sym.substr(1) : Sym; -} - -// Performs error checking on all /export arguments. -// It also sets ordinals. -void fixupExports() { - // Symbol ordinals must be unique. - std::set Ords; - for (Export &E : Config->Exports) { - if (E.Ordinal == 0) - continue; - if (!Ords.insert(E.Ordinal).second) - fatal("duplicate export ordinal: " + E.Name); - } - - for (Export &E : Config->Exports) { - Symbol *Sym = E.Sym; - if (!E.ForwardTo.empty() || !Sym) { - E.SymbolName = E.Name; - } else { - if (auto *U = dyn_cast(Sym)) - if (U->WeakAlias) - Sym = U->WeakAlias; - E.SymbolName = Sym->getName(); - } - } - - for (Export &E : Config->Exports) { - if (!E.ForwardTo.empty()) { - E.ExportName = undecorate(E.Name); - } else { - E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); - } - } - - // Uniquefy by name. - DenseMap Map(Config->Exports.size()); - std::vector V; - for (Export &E : Config->Exports) { - auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); - bool Inserted = Pair.second; - if (Inserted) { - V.push_back(E); - continue; - } - Export *Existing = Pair.first->second; - if (E == *Existing || E.Name != Existing->Name) - continue; - warn("duplicate /export option: " + E.Name); - } - Config->Exports = std::move(V); - - // Sort by name. - std::sort(Config->Exports.begin(), Config->Exports.end(), - [](const Export &A, const Export &B) { - return A.ExportName < B.ExportName; - }); -} - -void assignExportOrdinals() { - // Assign unique ordinals if default (= 0). - uint16_t Max = 0; - for (Export &E : Config->Exports) - Max = std::max(Max, E.Ordinal); - for (Export &E : Config->Exports) - if (E.Ordinal == 0) - E.Ordinal = ++Max; -} - -// Parses a string in the form of "key=value" and check -// if value matches previous values for the same key. -void checkFailIfMismatch(StringRef Arg) { - StringRef K, V; - std::tie(K, V) = Arg.split('='); - if (K.empty() || V.empty()) - fatal("/failifmismatch: invalid argument: " + Arg); - StringRef Existing = Config->MustMatch[K]; - if (!Existing.empty() && V != Existing) - fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V + - " for key " + K); - Config->MustMatch[K] = V; -} - -// Convert Windows resource files (.res files) to a .obj file. -MemoryBufferRef convertResToCOFF(ArrayRef MBs) { - object::WindowsResourceParser Parser; - - for (MemoryBufferRef MB : MBs) { - std::unique_ptr Bin = check(object::createBinary(MB)); - object::WindowsResource *RF = dyn_cast(Bin.get()); - if (!RF) - fatal("cannot compile non-resource file as resource"); - if (auto EC = Parser.parse(RF)) - fatal("failed to parse .res file: " + toString(std::move(EC))); - } - - Expected> E = - llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); - if (!E) - fatal("failed to write .res to COFF: " + toString(E.takeError())); - - MemoryBufferRef MBRef = **E; - make>(std::move(*E)); // take ownership - return MBRef; -} - -// Run MSVC link.exe for given in-memory object files. -// Command line options are copied from those given to LLD. -// This is for the /msvclto option. -void runMSVCLinker(std::string Rsp, ArrayRef Objects) { - // Write the in-memory object files to disk. - std::vector Temps; - for (StringRef S : Objects) { - Temps.emplace_back("lto", "obj", S); - Rsp += quote(Temps.back().Path) + "\n"; - } - - log("link.exe " + Rsp); - - // Run MSVC link.exe. - Temps.emplace_back("lto", "rsp", Rsp); - Executor E("link.exe"); - E.add(Twine("@" + Temps.back().Path)); - E.run(); -} - -// Create OptTable - -// Create prefix string literals used in Options.td -#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "Options.inc" -#undef PREFIX - -// Create table mapping all options defined in Options.td -static const llvm::opt::OptTable::Info InfoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ - {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ - X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, -#include "Options.inc" -#undef OPTION -}; - -COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} - -static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { - if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { - StringRef S = Arg->getValue(); - if (S != "windows" && S != "posix") - error("invalid response file quoting: " + S); - if (S == "windows") - return cl::TokenizeWindowsCommandLine; - return cl::TokenizeGNUCommandLine; - } - // The COFF linker always defaults to Windows quoting. - return cl::TokenizeWindowsCommandLine; -} - -// Parses a given list of options. -opt::InputArgList ArgParser::parse(ArrayRef Argv) { - // Make InputArgList from string vectors. - unsigned MissingIndex; - unsigned MissingCount; - SmallVector Vec(Argv.data(), Argv.data() + Argv.size()); - - // We need to get the quoting style for response files before parsing all - // options so we parse here before and ignore all the options but - // --rsp-quoting. - opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); - - // Expand response files (arguments in the form of @) - // and then parse the argument again. - cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); - Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); - - // Print the real command line if response files are expanded. - if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) { - std::string Msg = "Command line:"; - for (const char *S : Vec) - Msg += " " + std::string(S); - message(Msg); - } - - // Handle /WX early since it converts missing argument warnings to errors. - errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); - - if (MissingCount) - fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); - for (auto *Arg : Args.filtered(OPT_UNKNOWN)) - warn("ignoring unknown argument: " + Arg->getSpelling()); - return Args; -} - -// Tokenizes and parses a given string as command line in .drective section. -opt::InputArgList ArgParser::parseDirectives(StringRef S) { - // Make InputArgList from string vectors. - unsigned MissingIndex; - unsigned MissingCount; - - opt::InputArgList Args = - Table.ParseArgs(tokenize(S), MissingIndex, MissingCount); - - if (MissingCount) - fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); - for (auto *Arg : Args.filtered(OPT_UNKNOWN)) - warn("ignoring unknown argument: " + Arg->getSpelling()); - return Args; -} - -// link.exe has an interesting feature. If LINK or _LINK_ environment -// variables exist, their contents are handled as command line strings. -// So you can pass extra arguments using them. -opt::InputArgList ArgParser::parseLINK(std::vector Argv) { - // Concatenate LINK env and command line arguments, and then parse them. - if (Optional S = Process::GetEnv("LINK")) { - std::vector V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); - } - if (Optional S = Process::GetEnv("_LINK_")) { - std::vector V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); - } - return parse(Argv); -} - -std::vector ArgParser::tokenize(StringRef S) { - SmallVector Tokens; - cl::TokenizeWindowsCommandLine(S, Saver, Tokens); - return std::vector(Tokens.begin(), Tokens.end()); -} - -void printHelp(const char *Argv0) { - COFFOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false); -} - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/ICF.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/ICF.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/ICF.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/ICF.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,263 +0,0 @@ -//===- ICF.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// ICF is short for Identical Code Folding. That is a size optimization to -// identify and merge two or more read-only sections (typically functions) -// that happened to have the same contents. It usually reduces output size -// by a few percent. -// -// On Windows, ICF is enabled by default. -// -// See ELF/ICF.cpp for the details about the algortihm. -// -//===----------------------------------------------------------------------===// - -#include "Chunks.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Parallel.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -using namespace llvm; - -namespace lld { -namespace coff { - -class ICF { -public: - void run(ArrayRef V); - -private: - void segregate(size_t Begin, size_t End, bool Constant); - - bool equalsConstant(const SectionChunk *A, const SectionChunk *B); - bool equalsVariable(const SectionChunk *A, const SectionChunk *B); - - uint32_t getHash(SectionChunk *C); - bool isEligible(SectionChunk *C); - - size_t findBoundary(size_t Begin, size_t End); - - void forEachClassRange(size_t Begin, size_t End, - std::function Fn); - - void forEachClass(std::function Fn); - - std::vector Chunks; - int Cnt = 0; - std::atomic Repeat = {false}; -}; - -// Returns a hash value for S. -uint32_t ICF::getHash(SectionChunk *C) { - return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs, - C->Alignment, uint32_t(C->Header->SizeOfRawData), - C->Checksum, C->getContents()); -} - -// Returns true if section S is subject of ICF. -// -// Microsoft's documentation -// (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April -// 2017) says that /opt:icf folds both functions and read-only data. -// Despite that, the MSVC linker folds only functions. We found -// a few instances of programs that are not safe for data merging. -// Therefore, we merge only functions just like the MSVC tool. However, we merge -// identical .xdata sections, because the address of unwind information is -// insignificant to the user program and the Visual C++ linker does this. -bool ICF::isEligible(SectionChunk *C) { - // Non-comdat chunks, dead chunks, and writable chunks are not elegible. - bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - if (!C->isCOMDAT() || !C->isLive() || Writable) - return false; - - // Code sections are eligible. - if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) - return true; - - // .xdata unwind info sections are eligble. - return C->getSectionName().split('$').first == ".xdata"; -} - -// Split an equivalence class into smaller classes. -void ICF::segregate(size_t Begin, size_t End, bool Constant) { - while (Begin < End) { - // Divide [Begin, End) into two. Let Mid be the start index of the - // second group. - auto Bound = std::stable_partition( - Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { - if (Constant) - return equalsConstant(Chunks[Begin], S); - return equalsVariable(Chunks[Begin], S); - }); - size_t Mid = Bound - Chunks.begin(); - - // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an - // equivalence class ID because every group ends with a unique index. - for (size_t I = Begin; I < Mid; ++I) - Chunks[I]->Class[(Cnt + 1) % 2] = Mid; - - // If we created a group, we need to iterate the main loop again. - if (Mid != End) - Repeat = true; - - Begin = Mid; - } -} - -// Compare "non-moving" part of two sections, namely everything -// except relocation targets. -bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { - if (A->NumRelocs != B->NumRelocs) - return false; - - // Compare relocations. - auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { - if (R1.Type != R2.Type || - R1.VirtualAddress != R2.VirtualAddress) { - return false; - } - Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); - Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); - if (B1 == B2) - return true; - if (auto *D1 = dyn_cast(B1)) - if (auto *D2 = dyn_cast(B2)) - return D1->getValue() == D2->getValue() && - D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; - return false; - }; - if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) - return false; - - // Compare section attributes and contents. - return A->getPermissions() == B->getPermissions() && - A->SectionName == B->SectionName && A->Alignment == B->Alignment && - A->Header->SizeOfRawData == B->Header->SizeOfRawData && - A->Checksum == B->Checksum && A->getContents() == B->getContents(); -} - -// Compare "moving" part of two sections, namely relocation targets. -bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { - // Compare relocations. - auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { - Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); - Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); - if (B1 == B2) - return true; - if (auto *D1 = dyn_cast(B1)) - if (auto *D2 = dyn_cast(B2)) - return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; - return false; - }; - return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); -} - -size_t ICF::findBoundary(size_t Begin, size_t End) { - for (size_t I = Begin + 1; I < End; ++I) - if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) - return I; - return End; -} - -void ICF::forEachClassRange(size_t Begin, size_t End, - std::function Fn) { - if (Begin > 0) - Begin = findBoundary(Begin - 1, End); - - while (Begin < End) { - size_t Mid = findBoundary(Begin, Chunks.size()); - Fn(Begin, Mid); - Begin = Mid; - } -} - -// Call Fn on each class group. -void ICF::forEachClass(std::function Fn) { - // If the number of sections are too small to use threading, - // call Fn sequentially. - if (Chunks.size() < 1024) { - forEachClassRange(0, Chunks.size(), Fn); - ++Cnt; - return; - } - - // Split sections into 256 shards and call Fn in parallel. - size_t NumShards = 256; - size_t Step = Chunks.size() / NumShards; - for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { - size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; - forEachClassRange(I * Step, End, Fn); - }); - ++Cnt; -} - -// Merge identical COMDAT sections. -// Two sections are considered the same if their section headers, -// contents and relocations are all the same. -void ICF::run(ArrayRef Vec) { - // Collect only mergeable sections and group by hash value. - uint32_t NextId = 1; - for (Chunk *C : Vec) { - if (auto *SC = dyn_cast(C)) { - if (isEligible(SC)) - Chunks.push_back(SC); - else - SC->Class[0] = NextId++; - } - } - - // Initially, we use hash values to partition sections. - for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) { - // Set MSB to 1 to avoid collisions with non-hash classs. - SC->Class[0] = getHash(SC) | (1 << 31); - }); - - // From now on, sections in Chunks are ordered so that sections in - // the same group are consecutive in the vector. - std::stable_sort(Chunks.begin(), Chunks.end(), - [](SectionChunk *A, SectionChunk *B) { - return A->Class[0] < B->Class[0]; - }); - - // Compare static contents and assign unique IDs for each static content. - forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); - - // Split groups by comparing relocations until convergence is obtained. - do { - Repeat = false; - forEachClass( - [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); - } while (Repeat); - - log("ICF needed " + Twine(Cnt) + " iterations"); - - // Merge sections in the same classs. - forEachClass([&](size_t Begin, size_t End) { - if (End - Begin == 1) - return; - - log("Selected " + Chunks[Begin]->getDebugName()); - for (size_t I = Begin + 1; I < End; ++I) { - log(" Removed " + Chunks[I]->getDebugName()); - Chunks[Begin]->replace(Chunks[I]); - } - }); -} - -// Entry point to ICF. -void doICF(ArrayRef Chunks) { ICF().run(Chunks); } - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/InputFiles.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/InputFiles.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/InputFiles.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/InputFiles.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,505 +0,0 @@ -//===- InputFiles.cpp -----------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Chunks.h" -#include "Config.h" -#include "Driver.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm-c/lto.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ADT/Twine.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Target/TargetOptions.h" -#include -#include -#include - -using namespace llvm; -using namespace llvm::COFF; -using namespace llvm::object; -using namespace llvm::support::endian; - -using llvm::Triple; -using llvm::support::ulittle32_t; - -namespace lld { -namespace coff { - -std::vector ObjFile::Instances; -std::vector ImportFile::Instances; -std::vector BitcodeFile::Instances; - -/// Checks that Source is compatible with being a weak alias to Target. -/// If Source is Undefined and has no weak alias set, makes it a weak -/// alias to Target. -static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, - Symbol *Source, Symbol *Target) { - if (auto *U = dyn_cast(Source)) { - if (U->WeakAlias && U->WeakAlias != Target) - Symtab->reportDuplicate(Source, F); - U->WeakAlias = Target; - } -} - -ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} - -void ArchiveFile::parse() { - // Parse a MemoryBufferRef as an archive file. - File = CHECK(Archive::create(MB), this); - - // Read the symbol table to construct Lazy objects. - for (const Archive::Symbol &Sym : File->symbols()) - Symtab->addLazy(this, Sym); -} - -// Returns a buffer pointing to a member file containing a given symbol. -void ArchiveFile::addMember(const Archive::Symbol *Sym) { - const Archive::Child &C = - CHECK(Sym->getMember(), - "could not get the member for symbol " + Sym->getName()); - - // Return an empty buffer if we have already returned the same buffer. - if (!Seen.insert(C.getChildOffset()).second) - return; - - Driver->enqueueArchiveMember(C, Sym->getName(), getName()); -} - -std::vector getArchiveMembers(Archive *File) { - std::vector V; - Error Err = Error::success(); - for (const ErrorOr &COrErr : File->children(Err)) { - Archive::Child C = - CHECK(COrErr, - File->getFileName() + ": could not get the child of the archive"); - MemoryBufferRef MBRef = - CHECK(C.getMemoryBufferRef(), - File->getFileName() + - ": could not get the buffer for a child of the archive"); - V.push_back(MBRef); - } - if (Err) - fatal(File->getFileName() + - ": Archive::children failed: " + toString(std::move(Err))); - return V; -} - -void ObjFile::parse() { - // Parse a memory buffer as a COFF file. - std::unique_ptr Bin = CHECK(createBinary(MB), this); - - if (auto *Obj = dyn_cast(Bin.get())) { - Bin.release(); - COFFObj.reset(Obj); - } else { - fatal(toString(this) + " is not a COFF file"); - } - - // Read section and symbol tables. - initializeChunks(); - initializeSymbols(); -} - -// We set SectionChunk pointers in the SparseChunks vector to this value -// temporarily to mark comdat sections as having an unknown resolution. As we -// walk the object file's symbol table, once we visit either a leader symbol or -// an associative section definition together with the parent comdat's leader, -// we set the pointer to either nullptr (to mark the section as discarded) or a -// valid SectionChunk for that section. -static SectionChunk *const PendingComdat = reinterpret_cast(1); - -void ObjFile::initializeChunks() { - uint32_t NumSections = COFFObj->getNumberOfSections(); - Chunks.reserve(NumSections); - SparseChunks.resize(NumSections + 1); - for (uint32_t I = 1; I < NumSections + 1; ++I) { - const coff_section *Sec; - if (auto EC = COFFObj->getSection(I, Sec)) - fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); - - if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) - SparseChunks[I] = PendingComdat; - else - SparseChunks[I] = readSection(I, nullptr); - } -} - -SectionChunk *ObjFile::readSection(uint32_t SectionNumber, - const coff_aux_section_definition *Def) { - const coff_section *Sec; - StringRef Name; - if (auto EC = COFFObj->getSection(SectionNumber, Sec)) - fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message()); - if (auto EC = COFFObj->getSectionName(Sec, Name)) - fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + - EC.message()); - if (Name == ".sxdata") { - ArrayRef Data; - COFFObj->getSectionContents(Sec, Data); - if (Data.size() % 4 != 0) - fatal(".sxdata must be an array of symbol table indices"); - SXData = {reinterpret_cast(Data.data()), - Data.size() / 4}; - return nullptr; - } - if (Name == ".drectve") { - ArrayRef Data; - COFFObj->getSectionContents(Sec, Data); - Directives = std::string((const char *)Data.data(), Data.size()); - return nullptr; - } - - // Object files may have DWARF debug info or MS CodeView debug info - // (or both). - // - // DWARF sections don't need any special handling from the perspective - // of the linker; they are just a data section containing relocations. - // We can just link them to complete debug info. - // - // CodeView needs a linker support. We need to interpret and debug - // info, and then write it to a separate .pdb file. - - // Ignore debug info unless /debug is given. - if (!Config->Debug && Name.startswith(".debug")) - return nullptr; - - if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) - return nullptr; - auto *C = make(this, Sec); - if (Def) - C->Checksum = Def->CheckSum; - - // CodeView sections are stored to a different vector because they are not - // linked in the regular manner. - if (C->isCodeView()) - DebugChunks.push_back(C); - else - Chunks.push_back(C); - - return C; -} - -void ObjFile::readAssociativeDefinition( - COFFSymbolRef Sym, const coff_aux_section_definition *Def) { - SectionChunk *Parent = SparseChunks[Def->getNumber(Sym.isBigObj())]; - - // If the parent is pending, it probably means that its section definition - // appears after us in the symbol table. Leave the associated section as - // pending; we will handle it during the second pass in initializeSymbols(). - if (Parent == PendingComdat) - return; - - // Check whether the parent is prevailing. If it is, so are we, and we read - // the section; otherwise mark it as discarded. - int32_t SectionNumber = Sym.getSectionNumber(); - if (Parent) { - SparseChunks[SectionNumber] = readSection(SectionNumber, Def); - if (SparseChunks[SectionNumber]) - Parent->addAssociative(SparseChunks[SectionNumber]); - } else { - SparseChunks[SectionNumber] = nullptr; - } -} - -Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { - SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; - if (Sym.isExternal()) { - StringRef Name; - COFFObj->getSymbolName(Sym, Name); - if (SC) - return Symtab->addRegular(this, Name, Sym.getGeneric(), SC); - return Symtab->addUndefined(Name, this, false); - } - if (SC) - return make(this, /*Name*/ "", false, - /*IsExternal*/ false, Sym.getGeneric(), SC); - return nullptr; -} - -void ObjFile::initializeSymbols() { - uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); - Symbols.resize(NumSymbols); - - SmallVector, 8> WeakAliases; - std::vector PendingIndexes; - PendingIndexes.reserve(NumSymbols); - - std::vector ComdatDefs( - COFFObj->getNumberOfSections() + 1); - - for (uint32_t I = 0; I < NumSymbols; ++I) { - COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); - if (COFFSym.isUndefined()) { - Symbols[I] = createUndefined(COFFSym); - } else if (COFFSym.isWeakExternal()) { - Symbols[I] = createUndefined(COFFSym); - uint32_t TagIndex = COFFSym.getAux()->TagIndex; - WeakAliases.emplace_back(Symbols[I], TagIndex); - } else if (Optional OptSym = createDefined(COFFSym, ComdatDefs)) { - Symbols[I] = *OptSym; - } else { - // createDefined() returns None if a symbol belongs to a section that - // was pending at the point when the symbol was read. This can happen in - // two cases: - // 1) section definition symbol for a comdat leader; - // 2) symbol belongs to a comdat section associated with a section whose - // section definition symbol appears later in the symbol table. - // In both of these cases, we can expect the section to be resolved by - // the time we finish visiting the remaining symbols in the symbol - // table. So we postpone the handling of this symbol until that time. - PendingIndexes.push_back(I); - } - I += COFFSym.getNumberOfAuxSymbols(); - } - - for (uint32_t I : PendingIndexes) { - COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); - if (auto *Def = Sym.getSectionDefinition()) - if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) - readAssociativeDefinition(Sym, Def); - Symbols[I] = createRegular(Sym); - } - - for (auto &KV : WeakAliases) { - Symbol *Sym = KV.first; - uint32_t Idx = KV.second; - checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]); - } -} - -Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { - StringRef Name; - COFFObj->getSymbolName(Sym, Name); - return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); -} - -Optional ObjFile::createDefined( - COFFSymbolRef Sym, - std::vector &ComdatDefs) { - StringRef Name; - if (Sym.isCommon()) { - auto *C = make(Sym); - Chunks.push_back(C); - COFFObj->getSymbolName(Sym, Name); - Symbol *S = - Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); - return S; - } - if (Sym.isAbsolute()) { - COFFObj->getSymbolName(Sym, Name); - // Skip special symbols. - if (Name == "@comp.id") - return nullptr; - // COFF spec 5.10.1. The .sxdata section. - if (Name == "@feat.00") { - if (Sym.getValue() & 1) - SEHCompat = true; - return nullptr; - } - if (Sym.isExternal()) - return Symtab->addAbsolute(Name, Sym); - else - return make(Name, Sym); - } - int32_t SectionNumber = Sym.getSectionNumber(); - if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) - return nullptr; - - // Reserved sections numbers don't have contents. - if (llvm::COFF::isReservedSectionNumber(SectionNumber)) - fatal("broken object file: " + toString(this)); - - // This symbol references a section which is not present in the section - // header. - if ((uint32_t)SectionNumber >= SparseChunks.size()) - fatal("broken object file: " + toString(this)); - - // Handle comdat leader symbols. - if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { - ComdatDefs[SectionNumber] = nullptr; - Symbol *Leader; - bool Prevailing; - if (Sym.isExternal()) { - COFFObj->getSymbolName(Sym, Name); - std::tie(Leader, Prevailing) = - Symtab->addComdat(this, Name, Sym.getGeneric()); - } else { - Leader = make(this, /*Name*/ "", false, - /*IsExternal*/ false, Sym.getGeneric()); - Prevailing = true; - } - if (Prevailing) { - SectionChunk *C = readSection(SectionNumber, Def); - SparseChunks[SectionNumber] = C; - C->Sym = cast(Leader); - cast(Leader)->Data = &C->Repl; - } else { - SparseChunks[SectionNumber] = nullptr; - } - return Leader; - } - - // Read associative section definitions and prepare to handle the comdat - // leader symbol by setting the section's ComdatDefs pointer if we encounter a - // non-associative comdat. - if (SparseChunks[SectionNumber] == PendingComdat) { - if (auto *Def = Sym.getSectionDefinition()) { - if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) - readAssociativeDefinition(Sym, Def); - else - ComdatDefs[SectionNumber] = Def; - } - } - - if (SparseChunks[SectionNumber] == PendingComdat) - return None; - return createRegular(Sym); -} - -MachineTypes ObjFile::getMachineType() { - if (COFFObj) - return static_cast(COFFObj->getMachine()); - return IMAGE_FILE_MACHINE_UNKNOWN; -} - -StringRef ltrim1(StringRef S, const char *Chars) { - if (!S.empty() && strchr(Chars, S[0])) - return S.substr(1); - return S; -} - -void ImportFile::parse() { - const char *Buf = MB.getBufferStart(); - const char *End = MB.getBufferEnd(); - const auto *Hdr = reinterpret_cast(Buf); - - // Check if the total size is valid. - if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) - fatal("broken import library"); - - // Read names and create an __imp_ symbol. - StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); - StringRef ImpName = Saver.save("__imp_" + Name); - const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; - DLLName = StringRef(NameStart); - StringRef ExtName; - switch (Hdr->getNameType()) { - case IMPORT_ORDINAL: - ExtName = ""; - break; - case IMPORT_NAME: - ExtName = Name; - break; - case IMPORT_NAME_NOPREFIX: - ExtName = ltrim1(Name, "?@_"); - break; - case IMPORT_NAME_UNDECORATE: - ExtName = ltrim1(Name, "?@_"); - ExtName = ExtName.substr(0, ExtName.find('@')); - break; - } - - this->Hdr = Hdr; - ExternalName = ExtName; - - ImpSym = Symtab->addImportData(ImpName, this); - - if (Hdr->getType() == llvm::COFF::IMPORT_CONST) - static_cast(Symtab->addImportData(Name, this)); - - // If type is function, we need to create a thunk which jump to an - // address pointed by the __imp_ symbol. (This allows you to call - // DLL functions just like regular non-DLL functions.) - if (Hdr->getType() == llvm::COFF::IMPORT_CODE) - ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine); -} - -void BitcodeFile::parse() { - Obj = check(lto::InputFile::create(MemoryBufferRef( - MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); - std::vector> Comdat(Obj->getComdatTable().size()); - for (size_t I = 0; I != Obj->getComdatTable().size(); ++I) - Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I])); - for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { - StringRef SymName = Saver.save(ObjSym.getName()); - int ComdatIndex = ObjSym.getComdatIndex(); - Symbol *Sym; - if (ObjSym.isUndefined()) { - Sym = Symtab->addUndefined(SymName, this, false); - } else if (ObjSym.isCommon()) { - Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); - } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { - // Weak external. - Sym = Symtab->addUndefined(SymName, this, true); - std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); - Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback)); - checkAndSetWeakAlias(Symtab, this, Sym, Alias); - } else if (ComdatIndex != -1) { - if (SymName == Obj->getComdatTable()[ComdatIndex]) - Sym = Comdat[ComdatIndex].first; - else if (Comdat[ComdatIndex].second) - Sym = Symtab->addRegular(this, SymName); - else - Sym = Symtab->addUndefined(SymName, this, false); - } else { - Sym = Symtab->addRegular(this, SymName); - } - SymbolBodies.push_back(Sym); - } - Directives = Obj->getCOFFLinkerOpts(); -} - -MachineTypes BitcodeFile::getMachineType() { - switch (Triple(Obj->getTargetTriple()).getArch()) { - case Triple::x86_64: - return AMD64; - case Triple::x86: - return I386; - case Triple::arm: - return ARMNT; - case Triple::aarch64: - return ARM64; - default: - return IMAGE_FILE_MACHINE_UNKNOWN; - } -} -} // namespace coff -} // namespace lld - -// Returns the last element of a path, which is supposed to be a filename. -static StringRef getBasename(StringRef Path) { - size_t Pos = Path.find_last_of("\\/"); - if (Pos == StringRef::npos) - return Path; - return Path.substr(Pos + 1); -} - -// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". -std::string lld::toString(const coff::InputFile *File) { - if (!File) - return ""; - if (File->ParentName.empty()) - return File->getName(); - - return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + - ")") - .str(); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/InputFiles.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/InputFiles.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/InputFiles.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/InputFiles.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -//===- InputFiles.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_INPUT_FILES_H -#define LLD_COFF_INPUT_FILES_H - -#include "Config.h" -#include "lld/Common/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/LTO/LTO.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/StringSaver.h" -#include -#include -#include - -namespace llvm { -namespace pdb { -class DbiModuleDescriptorBuilder; -} -} - -namespace lld { -namespace coff { - -std::vector getArchiveMembers(llvm::object::Archive *File); - -using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; -using llvm::COFF::MachineTypes; -using llvm::object::Archive; -using llvm::object::COFFObjectFile; -using llvm::object::COFFSymbolRef; -using llvm::object::coff_import_header; -using llvm::object::coff_section; - -class Chunk; -class Defined; -class DefinedImportData; -class DefinedImportThunk; -class Lazy; -class SectionChunk; -class Symbol; -class Undefined; - -// The root class of input files. -class InputFile { -public: - enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; - Kind kind() const { return FileKind; } - virtual ~InputFile() {} - - // Returns the filename. - StringRef getName() const { return MB.getBufferIdentifier(); } - - // Reads a file (the constructor doesn't do that). - virtual void parse() = 0; - - // Returns the CPU type this file was compiled to. - virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } - - MemoryBufferRef MB; - - // An archive file name if this file is created from an archive. - StringRef ParentName; - - // Returns .drectve section contents if exist. - StringRef getDirectives() { return StringRef(Directives).trim(); } - -protected: - InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} - - std::string Directives; - -private: - const Kind FileKind; -}; - -// .lib or .a file. -class ArchiveFile : public InputFile { -public: - explicit ArchiveFile(MemoryBufferRef M); - static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - void parse() override; - - // Enqueues an archive member load for the given symbol. If we've already - // enqueued a load for the same archive member, this function does nothing, - // which ensures that we don't load the same member more than once. - void addMember(const Archive::Symbol *Sym); - -private: - std::unique_ptr File; - std::string Filename; - llvm::DenseSet Seen; -}; - -// .obj or .o file. This may be a member of an archive file. -class ObjFile : public InputFile { -public: - explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} - static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } - void parse() override; - MachineTypes getMachineType() override; - ArrayRef getChunks() { return Chunks; } - ArrayRef getDebugChunks() { return DebugChunks; } - ArrayRef getSymbols() { return Symbols; } - - // Returns a Symbol object for the SymbolIndex'th symbol in the - // underlying object file. - Symbol *getSymbol(uint32_t SymbolIndex) { - return Symbols[SymbolIndex]; - } - - // Returns the underying COFF file. - COFFObjectFile *getCOFFObj() { return COFFObj.get(); } - - static std::vector Instances; - - // True if this object file is compatible with SEH. - // COFF-specific and x86-only. - bool SEHCompat = false; - - // The symbol table indexes of the safe exception handlers. - // COFF-specific and x86-only. - ArrayRef SXData; - - // Pointer to the PDB module descriptor builder. Various debug info records - // will reference object files by "module index", which is here. Things like - // source files and section contributions are also recorded here. Will be null - // if we are not producing a PDB. - llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr; - -private: - void initializeChunks(); - void initializeSymbols(); - - SectionChunk * - readSection(uint32_t SectionNumber, - const llvm::object::coff_aux_section_definition *Def); - - void readAssociativeDefinition( - COFFSymbolRef COFFSym, - const llvm::object::coff_aux_section_definition *Def); - - llvm::Optional - createDefined(COFFSymbolRef Sym, - std::vector - &ComdatDefs); - Symbol *createRegular(COFFSymbolRef Sym); - Symbol *createUndefined(COFFSymbolRef Sym); - - std::unique_ptr COFFObj; - - // List of all chunks defined by this file. This includes both section - // chunks and non-section chunks for common symbols. - std::vector Chunks; - - // CodeView debug info sections. - std::vector DebugChunks; - - // This vector contains the same chunks as Chunks, but they are - // indexed such that you can get a SectionChunk by section index. - // Nonexistent section indices are filled with null pointers. - // (Because section number is 1-based, the first slot is always a - // null pointer.) - std::vector SparseChunks; - - // This vector contains a list of all symbols defined or referenced by this - // file. They are indexed such that you can get a Symbol by symbol - // index. Nonexistent indices (which are occupied by auxiliary - // symbols in the real symbol table) are filled with null pointers. - std::vector Symbols; -}; - -// This type represents import library members that contain DLL names -// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7 -// for details about the format. -class ImportFile : public InputFile { -public: - explicit ImportFile(MemoryBufferRef M) - : InputFile(ImportKind, M), Live(!Config->DoGC) {} - - static bool classof(const InputFile *F) { return F->kind() == ImportKind; } - - static std::vector Instances; - - DefinedImportData *ImpSym = nullptr; - DefinedImportThunk *ThunkSym = nullptr; - std::string DLLName; - -private: - void parse() override; - -public: - StringRef ExternalName; - const coff_import_header *Hdr; - Chunk *Location = nullptr; - - // We want to eliminate dllimported symbols if no one actually refers them. - // This "Live" bit is used to keep track of which import library members - // are actually in use. - // - // If the Live bit is turned off by MarkLive, Writer will ignore dllimported - // symbols provided by this import library member. - bool Live; -}; - -// Used for LTO. -class BitcodeFile : public InputFile { -public: - explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} - static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - ArrayRef getSymbols() { return SymbolBodies; } - MachineTypes getMachineType() override; - static std::vector Instances; - std::unique_ptr Obj; - -private: - void parse() override; - - std::vector SymbolBodies; -}; -} // namespace coff - -std::string toString(const coff::InputFile *File); -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/LTO.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/LTO.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/LTO.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/LTO.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -//===- LTO.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LTO.h" -#include "Config.h" -#include "InputFiles.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/TargetOptionsCommandFlags.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/IR/DiagnosticPrinter.h" -#include "llvm/LTO/Caching.h" -#include "llvm/LTO/Config.h" -#include "llvm/LTO/LTO.h" -#include "llvm/Object/SymbolicFile.h" -#include "llvm/Support/CodeGen.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::object; - -using namespace lld; -using namespace lld::coff; - -static void diagnosticHandler(const DiagnosticInfo &DI) { - SmallString<128> ErrStorage; - raw_svector_ostream OS(ErrStorage); - DiagnosticPrinterRawOStream DP(OS); - DI.print(DP); - warn(ErrStorage); -} - -static void checkError(Error E) { - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); -} - -static void saveBuffer(StringRef Buffer, const Twine &Path) { - std::error_code EC; - raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); - if (EC) - error("cannot create " + Path + ": " + EC.message()); - OS << Buffer; -} - -static std::unique_ptr createLTO() { - lto::Config Conf; - Conf.Options = InitTargetOptionsFromCodeGenFlags(); - // Use static reloc model on 32-bit x86 because it usually results in more - // compact code, and because there are also known code generation bugs when - // using the PIC model (see PR34306). - if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386) - Conf.RelocModel = Reloc::Static; - else - Conf.RelocModel = Reloc::PIC_; - Conf.DisableVerify = true; - Conf.DiagHandler = diagnosticHandler; - Conf.OptLevel = Config->LTOOptLevel; - if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", - /*UseInputModulePath*/ true)); - lto::ThinBackend Backend; - if (Config->LTOJobs != 0) - Backend = lto::createInProcessThinBackend(Config->LTOJobs); - return llvm::make_unique(std::move(Conf), Backend, - Config->LTOPartitions); -} - -BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} - -BitcodeCompiler::~BitcodeCompiler() = default; - -static void undefine(Symbol *S) { replaceSymbol(S, S->getName()); } - -void BitcodeCompiler::add(BitcodeFile &F) { - lto::InputFile &Obj = *F.Obj; - unsigned SymNum = 0; - std::vector SymBodies = F.getSymbols(); - std::vector Resols(SymBodies.size()); - - // Provide a resolution to the LTO API for each symbol. - for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { - Symbol *Sym = SymBodies[SymNum]; - lto::SymbolResolution &R = Resols[SymNum]; - ++SymNum; - - // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile - // reports two symbols for module ASM defined. Without this check, lld - // flags an undefined in IR with a definition in ASM as prevailing. - // Once IRObjectFile is fixed to report only one symbol this hack can - // be removed. - R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; - R.VisibleToRegularObj = Sym->IsUsedInRegularObj; - if (R.Prevailing) - undefine(Sym); - } - checkError(LTOObj->add(std::move(F.Obj), Resols)); -} - -// Merge all the bitcode files we have seen, codegen the result -// and return the resulting objects. -std::vector BitcodeCompiler::compile() { - unsigned MaxTasks = LTOObj->getMaxTasks(); - Buff.resize(MaxTasks); - Files.resize(MaxTasks); - - // The /lldltocache option specifies the path to a directory in which to cache - // native object files for ThinLTO incremental builds. If a path was - // specified, configure LTO to use it as the cache directory. - lto::NativeObjectCache Cache; - if (!Config->LTOCache.empty()) - Cache = check( - lto::localCache(Config->LTOCache, - [&](size_t Task, std::unique_ptr MB, - StringRef Path) { Files[Task] = std::move(MB); })); - - checkError(LTOObj->run( - [&](size_t Task) { - return llvm::make_unique( - llvm::make_unique(Buff[Task])); - }, - Cache)); - - if (!Config->LTOCache.empty()) - pruneCache(Config->LTOCache, Config->LTOCachePolicy); - - std::vector Ret; - for (unsigned I = 0; I != MaxTasks; ++I) { - if (Buff[I].empty()) - continue; - if (Config->SaveTemps) { - if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); - else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); - } - Ret.emplace_back(Buff[I].data(), Buff[I].size()); - } - - for (std::unique_ptr &File : Files) - if (File) - Ret.push_back(File->getBuffer()); - - return Ret; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/LTO.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/LTO.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/LTO.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/LTO.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -//===- LTO.h ----------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides a way to combine bitcode files into one COFF -// file by compiling them using LLVM. -// -// If LTO is in use, your input files are not in regular COFF files -// but instead LLVM bitcode files. In that case, the linker has to -// convert bitcode files into the native format so that we can create -// a COFF file that contains native code. This file provides that -// functionality. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_LTO_H -#define LLD_COFF_LTO_H - -#include "lld/Common/LLVM.h" -#include "llvm/ADT/SmallString.h" -#include -#include - -namespace llvm { -namespace lto { -class LTO; -} -} - -namespace lld { -namespace coff { - -class BitcodeFile; -class InputFile; - -class BitcodeCompiler { -public: - BitcodeCompiler(); - ~BitcodeCompiler(); - - void add(BitcodeFile &F); - std::vector compile(); - -private: - std::unique_ptr LTOObj; - std::vector> Buff; - std::vector> Files; -}; -} -} - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MapFile.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MapFile.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MapFile.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MapFile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -//===- MapFile.cpp --------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the /lldmap option. It shows lists in order and -// hierarchically the output sections, input sections, input files and -// symbol: -// -// Address Size Align Out File Symbol -// 00201000 00000015 4 .text -// 00201000 0000000e 4 test.o:(.text) -// 0020100e 00000000 0 local -// 00201005 00000000 0 f(int) -// -//===----------------------------------------------------------------------===// - -#include "MapFile.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "Writer.h" - -#include "lld/Common/ErrorHandler.h" -#include "llvm/Support/Parallel.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::object; - -using namespace lld; -using namespace lld::coff; - -typedef DenseMap> - SymbolMapTy; - -// Print out the first three columns of a line. -static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, - uint64_t Align) { - OS << format("%08llx %08llx %5lld ", Addr, Size, Align); -} - -static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } - -// Returns a list of all symbols that we want to print out. -static std::vector getSymbols() { - std::vector V; - for (ObjFile *File : ObjFile::Instances) - for (Symbol *B : File->getSymbols()) - if (auto *Sym = dyn_cast_or_null(B)) - if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) - V.push_back(Sym); - return V; -} - -// Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef Syms) { - SymbolMapTy Ret; - for (DefinedRegular *S : Syms) - Ret[S->getChunk()].push_back(S); - - // Sort symbols by address. - for (auto &It : Ret) { - SmallVectorImpl &V = It.second; - std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { - return A->getRVA() < B->getRVA(); - }); - } - return Ret; -} - -// Construct a map from symbols to their stringified representations. -static DenseMap -getSymbolStrings(ArrayRef Syms) { - std::vector Str(Syms.size()); - for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) { - raw_string_ostream OS(Str[I]); - writeHeader(OS, Syms[I]->getRVA(), 0, 0); - OS << indent(2) << toString(*Syms[I]); - }); - - DenseMap Ret; - for (size_t I = 0, E = Syms.size(); I < E; ++I) - Ret[Syms[I]] = std::move(Str[I]); - return Ret; -} - -void coff::writeMapFile(ArrayRef OutputSections) { - if (Config->MapFile.empty()) - return; - - std::error_code EC; - raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); - if (EC) - fatal("cannot open " + Config->MapFile + ": " + EC.message()); - - // Collect symbol info that we want to print out. - std::vector Syms = getSymbols(); - SymbolMapTy SectionSyms = getSectionSyms(Syms); - DenseMap SymStr = getSymbolStrings(Syms); - - // Print out the header line. - OS << "Address Size Align Out In Symbol\n"; - - // Print out file contents. - for (OutputSection *Sec : OutputSections) { - writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); - OS << Sec->getName() << '\n'; - - for (Chunk *C : Sec->getChunks()) { - auto *SC = dyn_cast(C); - if (!SC) - continue; - - writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment); - OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName() - << ")\n"; - for (DefinedRegular *Sym : SectionSyms[SC]) - OS << SymStr[Sym] << '\n'; - } - } -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MapFile.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MapFile.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MapFile.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MapFile.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -//===- MapFile.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_MAPFILE_H -#define LLD_COFF_MAPFILE_H - -#include "llvm/ADT/ArrayRef.h" - -namespace lld { -namespace coff { -class OutputSection; -void writeMapFile(llvm::ArrayRef OutputSections); -} -} - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MarkLive.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MarkLive.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MarkLive.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MarkLive.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -//===- MarkLive.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Chunks.h" -#include "Symbols.h" -#include "llvm/ADT/STLExtras.h" -#include - -namespace lld { -namespace coff { - -// Set live bit on for each reachable chunk. Unmarked (unreachable) -// COMDAT chunks will be ignored by Writer, so they will be excluded -// from the final output. -void markLive(ArrayRef Chunks) { - // We build up a worklist of sections which have been marked as live. We only - // push into the worklist when we discover an unmarked section, and we mark - // as we push, so sections never appear twice in the list. - SmallVector Worklist; - - // COMDAT section chunks are dead by default. Add non-COMDAT chunks. - for (Chunk *C : Chunks) - if (auto *SC = dyn_cast(C)) - if (SC->isLive()) - Worklist.push_back(SC); - - auto Enqueue = [&](SectionChunk *C) { - if (C->isLive()) - return; - C->markLive(); - Worklist.push_back(C); - }; - - auto AddSym = [&](Symbol *B) { - if (auto *Sym = dyn_cast(B)) - Enqueue(Sym->getChunk()); - else if (auto *Sym = dyn_cast(B)) - Sym->File->Live = true; - else if (auto *Sym = dyn_cast(B)) - Sym->WrappedSym->File->Live = true; - }; - - // Add GC root chunks. - for (Symbol *B : Config->GCRoot) - AddSym(B); - - while (!Worklist.empty()) { - SectionChunk *SC = Worklist.pop_back_val(); - assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); - - // Mark all symbols listed in the relocation table for this section. - for (Symbol *B : SC->symbols()) - if (B) - AddSym(B); - - // Mark associative sections if any. - for (SectionChunk *C : SC->children()) - Enqueue(C); - } -} - -} -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MinGW.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MinGW.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MinGW.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MinGW.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -//===- MinGW.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MinGW.h" -#include "SymbolTable.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; -using namespace lld::coff; -using namespace llvm; -using namespace llvm::COFF; - -AutoExporter::AutoExporter() { - if (Config->Machine == I386) { - ExcludeSymbols = { - "__NULL_IMPORT_DESCRIPTOR", - "__pei386_runtime_relocator", - "_do_pseudo_reloc", - "_impure_ptr", - "__impure_ptr", - "__fmode", - "_environ", - "___dso_handle", - // These are the MinGW names that differ from the standard - // ones (lacking an extra underscore). - "_DllMain@12", - "_DllEntryPoint@12", - "_DllMainCRTStartup@12", - }; - } else { - ExcludeSymbols = { - "_NULL_IMPORT_DESCRIPTOR", - "_pei386_runtime_relocator", - "do_pseudo_reloc", - "impure_ptr", - "_impure_ptr", - "_fmode", - "environ", - "__dso_handle", - // These are the MinGW names that differ from the standard - // ones (lacking an extra underscore). - "DllMain", - "DllEntryPoint", - "DllMainCRTStartup", - }; - } - - ExcludeLibs = { - "libgcc", - "libgcc_s", - "libstdc++", - "libmingw32", - "libmingwex", - "libg2c", - "libsupc++", - "libobjc", - "libgcj", - "libclang_rt.builtins-aarch64", - "libclang_rt.builtins-arm", - "libclang_rt.builtins-i386", - "libclang_rt.builtins-x86_64", - "libc++", - "libc++abi", - "libunwind", - "libmsvcrt", - "libucrtbase", - }; - ExcludeObjects = { - "crt0.o", - "crt1.o", - "crt1u.o", - "crt2.o", - "crt2u.o", - "dllcrt1.o", - "dllcrt2.o", - "gcrt0.o", - "gcrt1.o", - "gcrt2.o", - "crtbegin.o", - "crtend.o", - }; -} - -bool AutoExporter::shouldExport(Defined *Sym) const { - if (!Sym || !Sym->isLive() || !Sym->getChunk()) - return false; - - // Only allow the symbol kinds that make sense to export; in particular, - // disallow import symbols. - if (!isa(Sym) && !isa(Sym)) - return false; - if (ExcludeSymbols.count(Sym->getName())) - return false; - - // Don't export anything that looks like an import symbol (which also can be - // a manually defined data symbol with such a name). - if (Sym->getName().startswith("__imp_")) - return false; - - // If a corresponding __imp_ symbol exists and is defined, don't export it. - if (Symtab->find(("__imp_" + Sym->getName()).str())) - return false; - - // Check that file is non-null before dereferencing it, symbols not - // originating in regular object files probably shouldn't be exported. - if (!Sym->getFile()) - return false; - - StringRef LibName = sys::path::filename(Sym->getFile()->ParentName); - - // Drop the file extension. - LibName = LibName.substr(0, LibName.rfind('.')); - if (!LibName.empty()) - return !ExcludeLibs.count(LibName); - - StringRef FileName = sys::path::filename(Sym->getFile()->getName()); - return !ExcludeObjects.count(FileName); -} - -void coff::writeDefFile(StringRef Name) { - std::error_code EC; - raw_fd_ostream OS(Name, EC, sys::fs::F_None); - if (EC) - fatal("cannot open " + Name + ": " + EC.message()); - - OS << "EXPORTS\n"; - for (Export &E : Config->Exports) { - OS << " " << E.ExportName << " " - << "@" << E.Ordinal; - if (auto *Def = dyn_cast_or_null(E.Sym)) { - if (Def && Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) - OS << " DATA"; - } - OS << "\n"; - } -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MinGW.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MinGW.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/MinGW.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/MinGW.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -//===- MinGW.h --------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_MINGW_H -#define LLD_COFF_MINGW_H - -#include "Config.h" -#include "Symbols.h" -#include "lld/Common/LLVM.h" - -namespace lld { -namespace coff { - -// Logic for deciding what symbols to export, when exporting all -// symbols for MinGW. -class AutoExporter { -public: - AutoExporter(); - - llvm::StringSet<> ExcludeSymbols; - llvm::StringSet<> ExcludeLibs; - llvm::StringSet<> ExcludeObjects; - - bool shouldExport(Defined *Sym) const; -}; - -void writeDefFile(StringRef Name); - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Options.td rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Options.td --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Options.td 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Options.td 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -include "llvm/Option/OptParser.td" - -// link.exe accepts options starting with either a dash or a slash. - -// Flag that takes no arguments. -class F : Flag<["/", "-", "-?"], name>; - -// Flag that takes one argument after ":". -class P : - Joined<["/", "-", "-?"], name#":">, HelpText; - -// Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the -// flag on and using it suffixed by ":no" turns it off. -multiclass B { - def "" : F, HelpText; - def _no : F, HelpText; -} - -def align : P<"align", "Section alignment">; -def aligncomm : P<"aligncomm", "Set common symbol alignment">; -def alternatename : P<"alternatename", "Define weak alias">; -def base : P<"base", "Base address of the program">; -def defaultlib : P<"defaultlib", "Add the library to the list of input files">; -def delayload : P<"delayload", "Delay loaded DLL name">; -def entry : P<"entry", "Name of entry point symbol">; -def errorlimit : P<"errorlimit", - "Maximum number of errors to emit before stopping (0 = no limit)">; -def export : P<"export", "Export a function">; -// No help text because /failifmismatch is not intended to be used by the user. -def failifmismatch : P<"failifmismatch", "">; -def heap : P<"heap", "Size of the heap">; -def ignore : P<"ignore", "Specify warning codes to ignore">; -def implib : P<"implib", "Import library name">; -def libpath : P<"libpath", "Additional library search path">; -def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; -def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">; -def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">; -def lldsavetemps : F<"lldsavetemps">, - HelpText<"Save temporary files instead of deleting them">; -def machine : P<"machine", "Specify target platform">; -def merge : P<"merge", "Combine sections">; -def mllvm : P<"mllvm", "Options to pass to LLVM">; -def nodefaultlib : P<"nodefaultlib", "Remove a default library">; -def opt : P<"opt", "Control optimizations">; -def out : P<"out", "Path to file to write output">; -def pdb : P<"pdb", "PDB file path">; -def section : P<"section", "Specify section attributes">; -def stack : P<"stack", "Size of the stack">; -def stub : P<"stub", "Specify DOS stub file">; -def subsystem : P<"subsystem", "Specify subsystem">; -def version : P<"version", "Specify a version number in the PE header">; -def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; - -def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; - -def manifest : F<"manifest">; -def manifest_colon : P<"manifest", "Create manifest file">; -def manifestuac : P<"manifestuac", "User access control">; -def manifestfile : P<"manifestfile", "Manifest file path">; -def manifestdependency : P<"manifestdependency", - "Attributes for in manifest file">; -def manifestinput : P<"manifestinput", "Specify manifest file">; - -// We cannot use multiclass P because class name "incl" is different -// from its command line option name. We do this because "include" is -// a reserved keyword in tablegen. -def incl : Joined<["/", "-"], "include:">, - HelpText<"Force symbol to be added to symbol table as undefined one">; - -// "def" is also a keyword. -def deffile : Joined<["/", "-"], "def:">, - HelpText<"Use module-definition file">; - -def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; -def debugtype : P<"debugtype", "Debug Info Options">; -def dll : F<"dll">, HelpText<"Create a DLL">; -def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; -def nodefaultlib_all : F<"nodefaultlib">; -def noentry : F<"noentry">; -def profile : F<"profile">; -def swaprun_cd : F<"swaprun:cd">; -def swaprun_net : F<"swaprun:net">; -def verbose : F<"verbose">; -def wholearchive_flag : F<"wholearchive">; - -def force : F<"force">, - HelpText<"Allow undefined symbols when creating executables">; -def force_unresolved : F<"force:unresolved">; -defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">; - -defm allowbind : B<"allowbind", "Enable DLL binding (default)", - "Disable DLL binding">; -defm allowisolation : B<"allowisolation", "Enable DLL isolation (default)", - "Disable DLL isolation">; -defm appcontainer : B<"appcontainer", - "Image can only be run in an app container", - "Image can run outside an app container (default)">; -defm dynamicbase : B<"dynamicbase", "Enable ASLR (default unless /fixed)", - "Disable ASLR (default when /fixed)">; -defm fixed : B<"fixed", "Disable base relocations", - "Enable base relocations (default)">; -defm highentropyva : B<"highentropyva", - "Enable 64-bit ASLR (default on 64-bit)", - "Disable 64-bit ASLR">; -defm largeaddressaware : B<"largeaddressaware", - "Enable large addresses (default on 64-bit)", - "Disable large addresses (default on 32-bit)">; -defm nxcompat : B<"nxcompat", "Enable data execution prevention (default)", - "Disable data execution provention">; -defm safeseh : B<"safeseh", - "Produce an image with Safe Exception Handler (only for x86)", - "Don't produce an image with Safe Exception Handler">; -defm tsaware : B<"tsaware", - "Create Terminal Server aware executable (default)", - "Create non-Terminal Server aware executable">; - -def help : F<"help">; -def help_q : Flag<["/?", "-?"], "">, Alias; - -// LLD extensions -def debug_ghash : F<"debug:ghash">; -def debug_dwarf : F<"debug:dwarf">; -def export_all_symbols : F<"export-all-symbols">; -def lldmingw : F<"lldmingw">; -def msvclto : F<"msvclto">; -def output_def : Joined<["/", "-"], "output-def:">; -def rsp_quoting : Joined<["--"], "rsp-quoting=">, - HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; -def dash_dash_version : Flag<["--"], "version">, - HelpText<"Print version information">; - -// Flags for debugging -def lldmap : F<"lldmap">; -def lldmap_file : Joined<["/", "-"], "lldmap:">; - -//============================================================================== -// The flags below do nothing. They are defined only for link.exe compatibility. -//============================================================================== - -class QF : Joined<["/", "-", "-?"], name#":">; - -multiclass QB { - def "" : F; - def _no : F; -} - -def functionpadmin : F<"functionpadmin">; -def ignoreidl : F<"ignoreidl">; -def incremental : F<"incremental">; -def no_incremental : F<"incremental:no">; -def nologo : F<"nologo">; -def throwingnew : F<"throwingnew">; -def editandcontinue : F<"editandcontinue">; -def fastfail : F<"fastfail">; - -def delay : QF<"delay">; -def errorreport : QF<"errorreport">; -def idlout : QF<"idlout">; -def maxilksize : QF<"maxilksize">; -def natvis : QF<"natvis">; -def pdbaltpath : QF<"pdbaltpath">; -def tlbid : QF<"tlbid">; -def tlbout : QF<"tlbout">; -def verbose_all : QF<"verbose">; -def guardsym : QF<"guardsym">; diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/PDB.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/PDB.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/PDB.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/PDB.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1022 +0,0 @@ -//===- PDB.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PDB.h" -#include "Chunks.h" -#include "Config.h" -#include "Driver.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "Writer.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/DebugInfo/CodeView/CVDebugRecord.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" -#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/PDB/GenericError.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/PDB.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/JamCRC.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/ScopedPrinter.h" -#include - -using namespace lld; -using namespace lld::coff; -using namespace llvm; -using namespace llvm::codeview; - -using llvm::object::coff_section; - -static ExitOnError ExitOnErr; - -namespace { -/// Map from type index and item index in a type server PDB to the -/// corresponding index in the destination PDB. -struct CVIndexMap { - SmallVector TPIMap; - SmallVector IPIMap; - bool IsTypeServerMap = false; -}; - -class PDBLinker { -public: - PDBLinker(SymbolTable *Symtab) - : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), - IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {} - - /// Emit the basic PDB structure: initial streams, headers, etc. - void initialize(const llvm::codeview::DebugInfo &BuildId); - - /// Link CodeView from each object file in the symbol table into the PDB. - void addObjectsToPDB(); - - /// Link CodeView from a single object file into the PDB. - void addObjFile(ObjFile *File); - - /// Produce a mapping from the type and item indices used in the object - /// file to those in the destination PDB. - /// - /// If the object file uses a type server PDB (compiled with /Zi), merge TPI - /// and IPI from the type server PDB and return a map for it. Each unique type - /// server PDB is merged at most once, so this may return an existing index - /// mapping. - /// - /// If the object does not use a type server PDB (compiled with /Z7), we merge - /// all the type and item records from the .debug$S stream and fill in the - /// caller-provided ObjectIndexMap. - Expected mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap); - - Expected maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS); - - /// Add the section map and section contributions to the PDB. - void addSections(ArrayRef OutputSections, - ArrayRef SectionTable); - - void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C); - - /// Write the PDB to disk. - void commit(); - -private: - BumpPtrAllocator Alloc; - - SymbolTable *Symtab; - - pdb::PDBFileBuilder Builder; - - /// Type records that will go into the PDB TPI stream. - MergingTypeTableBuilder TypeTable; - - /// Item records that will go into the PDB IPI stream. - MergingTypeTableBuilder IDTable; - - /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH) - GlobalTypeTableBuilder GlobalTypeTable; - - /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH) - GlobalTypeTableBuilder GlobalIDTable; - - /// PDBs use a single global string table for filenames in the file checksum - /// table. - DebugStringTableSubsection PDBStrTab; - - llvm::SmallString<128> NativePath; - - std::vector SectionMap; - - /// Type index mappings of type server PDBs that we've loaded so far. - std::map TypeServerIndexMappings; - - /// List of TypeServer PDBs which cannot be loaded. - /// Cached to prevent repeated load attempts. - std::set MissingTypeServerPDBs; -}; -} - -static SectionChunk *findByName(ArrayRef Sections, - StringRef Name) { - for (SectionChunk *C : Sections) - if (C->getSectionName() == Name) - return C; - return nullptr; -} - -static ArrayRef consumeDebugMagic(ArrayRef Data, - StringRef SecName) { - // First 4 bytes are section magic. - if (Data.size() < 4) - fatal(SecName + " too short"); - if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) - fatal(SecName + " has an invalid magic"); - return Data.slice(4); -} - -static ArrayRef getDebugSection(ObjFile *File, StringRef SecName) { - if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) - return consumeDebugMagic(Sec->getContents(), SecName); - return {}; -} - -// A COFF .debug$H section is currently a clang extension. This function checks -// if a .debug$H section is in a format that we expect / understand, so that we -// can ignore any sections which are coincidentally also named .debug$H but do -// not contain a format we recognize. -static bool canUseDebugH(ArrayRef DebugH) { - if (DebugH.size() < sizeof(object::debug_h_header)) - return false; - auto *Header = - reinterpret_cast(DebugH.data()); - DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); - return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && - Header->Version == 0 && - Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) && - (DebugH.size() % 20 == 0); -} - -static Optional> getDebugH(ObjFile *File) { - SectionChunk *Sec = findByName(File->getDebugChunks(), ".debug$H"); - if (!Sec) - return llvm::None; - ArrayRef Contents = Sec->getContents(); - if (!canUseDebugH(Contents)) - return None; - return Contents; -} - -static ArrayRef -getHashesFromDebugH(ArrayRef DebugH) { - assert(canUseDebugH(DebugH)); - - DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); - uint32_t Count = DebugH.size() / sizeof(GloballyHashedType); - return {reinterpret_cast(DebugH.data()), Count}; -} - -static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, - TypeCollection &TypeTable) { - // Start the TPI or IPI stream header. - TpiBuilder.setVersionHeader(pdb::PdbTpiV80); - - // Flatten the in memory type table and hash each type. - TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) { - auto Hash = pdb::hashTypeRecord(Type); - if (auto E = Hash.takeError()) - fatal("type hashing error"); - TpiBuilder.addTypeRecord(Type.RecordData, *Hash); - }); -} - -static Optional -maybeReadTypeServerRecord(CVTypeArray &Types) { - auto I = Types.begin(); - if (I == Types.end()) - return None; - const CVType &Type = *I; - if (Type.kind() != LF_TYPESERVER2) - return None; - TypeServer2Record TS; - if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) - fatal("error reading type server record: " + toString(std::move(EC))); - return std::move(TS); -} - -Expected PDBLinker::mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap) { - ArrayRef Data = getDebugSection(File, ".debug$T"); - if (Data.empty()) - return ObjectIndexMap; - - BinaryByteStream Stream(Data, support::little); - CVTypeArray Types; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal("Reader::readArray failed: " + toString(std::move(EC))); - - // Look through type servers. If we've already seen this type server, don't - // merge any type information. - if (Optional TS = maybeReadTypeServerRecord(Types)) - return maybeMergeTypeServerPDB(File, *TS); - - // This is a /Z7 object. Fill in the temporary, caller-provided - // ObjectIndexMap. - if (Config->DebugGHashes) { - ArrayRef Hashes; - std::vector OwnedHashes; - if (Optional> DebugH = getDebugH(File)) - Hashes = getHashesFromDebugH(*DebugH); - else { - OwnedHashes = GloballyHashedType::hashTypes(Types); - Hashes = OwnedHashes; - } - - if (auto Err = mergeTypeAndIdRecords(GlobalIDTable, GlobalTypeTable, - ObjectIndexMap.TPIMap, Types, Hashes)) - fatal("codeview::mergeTypeAndIdRecords failed: " + - toString(std::move(Err))); - } else { - if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, - ObjectIndexMap.TPIMap, Types)) - fatal("codeview::mergeTypeAndIdRecords failed: " + - toString(std::move(Err))); - } - return ObjectIndexMap; -} - -static Expected> -tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { - ErrorOr> MBOrErr = MemoryBuffer::getFile( - TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); - if (!MBOrErr) - return errorCodeToError(MBOrErr.getError()); - - std::unique_ptr ThisSession; - if (auto EC = pdb::NativeSession::createFromPdb( - MemoryBuffer::getMemBuffer(Driver->takeBuffer(std::move(*MBOrErr)), - /*RequiresNullTerminator=*/false), - ThisSession)) - return std::move(EC); - - std::unique_ptr NS( - static_cast(ThisSession.release())); - pdb::PDBFile &File = NS->getPDBFile(); - auto ExpectedInfo = File.getPDBInfoStream(); - // All PDB Files should have an Info stream. - if (!ExpectedInfo) - return ExpectedInfo.takeError(); - - // Just because a file with a matching name was found and it was an actual - // PDB file doesn't mean it matches. For it to match the InfoStream's GUID - // must match the GUID specified in the TypeServer2 record. - if (ExpectedInfo->getGuid() != GuidFromObj) - return make_error( - pdb::generic_error_code::type_server_not_found, TSPath); - - return std::move(NS); -} - -Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS) { - const GUID& TSId = TS.getGuid(); - StringRef TSPath = TS.getName(); - - // First, check if the PDB has previously failed to load. - if (MissingTypeServerPDBs.count(TSId)) - return make_error( - pdb::generic_error_code::type_server_not_found, TSPath); - - // Second, check if we already loaded a PDB with this GUID. Return the type - // index mapping if we have it. - auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()}); - CVIndexMap &IndexMap = Insertion.first->second; - if (!Insertion.second) - return IndexMap; - - // Mark this map as a type server map. - IndexMap.IsTypeServerMap = true; - - // Check for a PDB at: - // 1. The given file path - // 2. Next to the object file or archive file - auto ExpectedSession = tryToLoadPDB(TSId, TSPath); - if (!ExpectedSession) { - consumeError(ExpectedSession.takeError()); - StringRef LocalPath = - !File->ParentName.empty() ? File->ParentName : File->getName(); - SmallString<128> Path = sys::path::parent_path(LocalPath); - sys::path::append( - Path, sys::path::filename(TSPath, sys::path::Style::windows)); - ExpectedSession = tryToLoadPDB(TSId, Path); - } - if (auto E = ExpectedSession.takeError()) { - TypeServerIndexMappings.erase(TSId); - MissingTypeServerPDBs.emplace(TSId); - return std::move(E); - } - - auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); - if (auto E = ExpectedTpi.takeError()) - fatal("Type server does not have TPI stream: " + toString(std::move(E))); - auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); - if (auto E = ExpectedIpi.takeError()) - fatal("Type server does not have TPI stream: " + toString(std::move(E))); - - if (Config->DebugGHashes) { - // PDBs do not actually store global hashes, so when merging a type server - // PDB we have to synthesize global hashes. To do this, we first synthesize - // global hashes for the TPI stream, since it is independent, then we - // synthesize hashes for the IPI stream, using the hashes for the TPI stream - // as inputs. - auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray()); - auto IpiHashes = - GloballyHashedType::hashIds(ExpectedIpi->typeArray(), TpiHashes); - - // Merge TPI first, because the IPI stream will reference type indices. - if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap, - ExpectedTpi->typeArray(), TpiHashes)) - fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); - - // Merge IPI. - if (auto Err = - mergeIdRecords(GlobalIDTable, IndexMap.TPIMap, IndexMap.IPIMap, - ExpectedIpi->typeArray(), IpiHashes)) - fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); - } else { - // Merge TPI first, because the IPI stream will reference type indices. - if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, - ExpectedTpi->typeArray())) - fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); - - // Merge IPI. - if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, - ExpectedIpi->typeArray())) - fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); - } - - return IndexMap; -} - -static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { - if (TI.isSimple()) - return true; - if (TI.toArrayIndex() >= TypeIndexMap.size()) - return false; - TI = TypeIndexMap[TI.toArrayIndex()]; - return true; -} - -static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, - MutableArrayRef Contents, - const CVIndexMap &IndexMap, - ArrayRef TypeRefs) { - for (const TiReference &Ref : TypeRefs) { - unsigned ByteSize = Ref.Count * sizeof(TypeIndex); - if (Contents.size() < Ref.Offset + ByteSize) - fatal("symbol record too short"); - - // This can be an item index or a type index. Choose the appropriate map. - ArrayRef TypeOrItemMap = IndexMap.TPIMap; - bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef; - if (IsItemIndex && IndexMap.IsTypeServerMap) - TypeOrItemMap = IndexMap.IPIMap; - - MutableArrayRef TIs( - reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); - for (TypeIndex &TI : TIs) { - if (!remapTypeIndex(TI, TypeOrItemMap)) { - log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " + - File->getName() + " with bad " + (IsItemIndex ? "item" : "type") + - " index 0x" + utohexstr(TI.getIndex())); - TI = TypeIndex(SimpleTypeKind::NotTranslated); - continue; - } - } - } -} - -static SymbolKind symbolKind(ArrayRef RecordData) { - const RecordPrefix *Prefix = - reinterpret_cast(RecordData.data()); - return static_cast(uint16_t(Prefix->RecordKind)); -} - -/// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32 -static void translateIdSymbols(MutableArrayRef &RecordData, - TypeCollection &IDTable) { - RecordPrefix *Prefix = reinterpret_cast(RecordData.data()); - - SymbolKind Kind = symbolKind(RecordData); - - if (Kind == SymbolKind::S_PROC_ID_END) { - Prefix->RecordKind = SymbolKind::S_END; - return; - } - - // In an object file, GPROC32_ID has an embedded reference which refers to the - // single object file type index namespace. This has already been translated - // to the PDB file's ID stream index space, but we need to convert this to a - // symbol that refers to the type stream index space. So we remap again from - // ID index space to type index space. - if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) { - SmallVector Refs; - auto Content = RecordData.drop_front(sizeof(RecordPrefix)); - CVSymbol Sym(Kind, RecordData); - discoverTypeIndicesInSymbol(Sym, Refs); - assert(Refs.size() == 1); - assert(Refs.front().Count == 1); - - TypeIndex *TI = - reinterpret_cast(Content.data() + Refs[0].Offset); - // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in - // the IPI stream, whose `FunctionType` member refers to the TPI stream. - // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and - // in both cases we just need the second type index. - if (!TI->isSimple() && !TI->isNoneType()) { - CVType FuncIdData = IDTable.getType(*TI); - SmallVector Indices; - discoverTypeIndices(FuncIdData, Indices); - assert(Indices.size() == 2); - *TI = Indices[1]; - } - - Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 - : SymbolKind::S_LPROC32; - Prefix->RecordKind = uint16_t(Kind); - } -} - -/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. -/// The object file may not be aligned. -static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, - BumpPtrAllocator &Alloc) { - size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); - assert(Size >= 4 && "record too short"); - assert(Size <= MaxRecordLength && "record too long"); - void *Mem = Alloc.Allocate(Size, 4); - - // Copy the symbol record and zero out any padding bytes. - MutableArrayRef NewData(reinterpret_cast(Mem), Size); - memcpy(NewData.data(), Sym.data().data(), Sym.length()); - memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); - - // Update the record prefix length. It should point to the beginning of the - // next record. - auto *Prefix = reinterpret_cast(Mem); - Prefix->RecordLen = Size - 2; - return NewData; -} - -/// Return true if this symbol opens a scope. This implies that the symbol has -/// "parent" and "end" fields, which contain the offset of the S_END or -/// S_INLINESITE_END record. -static bool symbolOpensScope(SymbolKind Kind) { - switch (Kind) { - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - case SymbolKind::S_LPROC32_ID: - case SymbolKind::S_GPROC32_ID: - case SymbolKind::S_BLOCK32: - case SymbolKind::S_SEPCODE: - case SymbolKind::S_THUNK32: - case SymbolKind::S_INLINESITE: - case SymbolKind::S_INLINESITE2: - return true; - default: - break; - } - return false; -} - -static bool symbolEndsScope(SymbolKind Kind) { - switch (Kind) { - case SymbolKind::S_END: - case SymbolKind::S_PROC_ID_END: - case SymbolKind::S_INLINESITE_END: - return true; - default: - break; - } - return false; -} - -struct ScopeRecord { - ulittle32_t PtrParent; - ulittle32_t PtrEnd; -}; - -struct SymbolScope { - ScopeRecord *OpeningRecord; - uint32_t ScopeOffset; -}; - -static void scopeStackOpen(SmallVectorImpl &Stack, - uint32_t CurOffset, CVSymbol &Sym) { - assert(symbolOpensScope(Sym.kind())); - SymbolScope S; - S.ScopeOffset = CurOffset; - S.OpeningRecord = const_cast( - reinterpret_cast(Sym.content().data())); - S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; - Stack.push_back(S); -} - -static void scopeStackClose(SmallVectorImpl &Stack, - uint32_t CurOffset, ObjFile *File) { - if (Stack.empty()) { - warn("symbol scopes are not balanced in " + File->getName()); - return; - } - SymbolScope S = Stack.pop_back_val(); - S.OpeningRecord->PtrEnd = CurOffset; -} - -static bool symbolGoesInModuleStream(const CVSymbol &Sym) { - switch (Sym.kind()) { - case SymbolKind::S_GDATA32: - case SymbolKind::S_CONSTANT: - case SymbolKind::S_UDT: - // We really should not be seeing S_PROCREF and S_LPROCREF in the first place - // since they are synthesized by the linker in response to S_GPROC32 and - // S_LPROC32, but if we do see them, don't put them in the module stream I - // guess. - case SymbolKind::S_PROCREF: - case SymbolKind::S_LPROCREF: - return false; - // S_GDATA32 does not go in the module stream, but S_LDATA32 does. - case SymbolKind::S_LDATA32: - default: - return true; - } -} - -static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) { - switch (Sym.kind()) { - case SymbolKind::S_CONSTANT: - case SymbolKind::S_GDATA32: - // S_LDATA32 goes in both the module stream and the globals stream. - case SymbolKind::S_LDATA32: - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - // We really should not be seeing S_PROCREF and S_LPROCREF in the first place - // since they are synthesized by the linker in response to S_GPROC32 and - // S_LPROC32, but if we do see them, copy them straight through. - case SymbolKind::S_PROCREF: - case SymbolKind::S_LPROCREF: - return true; - // FIXME: For now, we drop all S_UDT symbols (i.e. they don't go in the - // globals stream or the modules stream). These have special handling which - // needs more investigation before we can get right, but by putting them all - // into the globals stream WinDbg fails to display local variables of class - // types saying that it cannot find the type Foo *. So as a stopgap just to - // keep things working, we drop them. - case SymbolKind::S_UDT: - default: - return false; - } -} - -static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File, - const CVSymbol &Sym) { - switch (Sym.kind()) { - case SymbolKind::S_CONSTANT: - case SymbolKind::S_UDT: - case SymbolKind::S_GDATA32: - case SymbolKind::S_LDATA32: - case SymbolKind::S_PROCREF: - case SymbolKind::S_LPROCREF: - Builder.addGlobalSymbol(Sym); - break; - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: { - SymbolRecordKind K = SymbolRecordKind::ProcRefSym; - if (Sym.kind() == SymbolKind::S_LPROC32) - K = SymbolRecordKind::LocalProcRef; - ProcRefSym PS(K); - PS.Module = static_cast(File.ModuleDBI->getModuleIndex()); - // For some reason, MSVC seems to add one to this value. - ++PS.Module; - PS.Name = getSymbolName(Sym); - PS.SumName = 0; - PS.SymOffset = File.ModuleDBI->getNextSymbolOffset(); - Builder.addGlobalSymbol(PS); - break; - } - default: - llvm_unreachable("Invalid symbol kind!"); - } -} - -static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, - pdb::GSIStreamBuilder &GsiBuilder, - const CVIndexMap &IndexMap, - TypeCollection &IDTable, - BinaryStreamRef SymData) { - // FIXME: Improve error recovery by warning and skipping records when - // possible. - CVSymbolArray Syms; - BinaryStreamReader Reader(SymData); - ExitOnErr(Reader.readArray(Syms, Reader.getLength())); - SmallVector Scopes; - for (CVSymbol Sym : Syms) { - // Discover type index references in the record. Skip it if we don't know - // where they are. - SmallVector TypeRefs; - if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { - log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); - continue; - } - - // Copy the symbol record so we can mutate it. - MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); - - // Re-map all the type index references. - MutableArrayRef Contents = - NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs); - - // An object file may have S_xxx_ID symbols, but these get converted to - // "real" symbols in a PDB. - translateIdSymbols(NewData, IDTable); - - SymbolKind NewKind = symbolKind(NewData); - - // Fill in "Parent" and "End" fields by maintaining a stack of scopes. - CVSymbol NewSym(NewKind, NewData); - if (symbolOpensScope(NewKind)) - scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); - else if (symbolEndsScope(NewKind)) - scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); - - // Add the symbol to the globals stream if necessary. Do this before adding - // the symbol to the module since we may need to get the next symbol offset, - // and writing to the module's symbol stream will update that offset. - if (symbolGoesInGlobalsStream(NewSym)) - addGlobalSymbol(GsiBuilder, *File, NewSym); - - // Add the symbol to the module. - if (symbolGoesInModuleStream(NewSym)) - File->ModuleDBI->addSymbol(NewSym); - } -} - -// Allocate memory for a .debug$S section and relocate it. -static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, - SectionChunk *DebugChunk) { - uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); - assert(DebugChunk->OutputSectionOff == 0 && - "debug sections should not be in output sections"); - DebugChunk->writeTo(Buffer); - return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), - ".debug$S"); -} - -void PDBLinker::addObjFile(ObjFile *File) { - // Add a module descriptor for every object file. We need to put an absolute - // path to the object into the PDB. If this is a plain object, we make its - // path absolute. If it's an object in an archive, we make the archive path - // absolute. - bool InArchive = !File->ParentName.empty(); - SmallString<128> Path = InArchive ? File->ParentName : File->getName(); - sys::fs::make_absolute(Path); - sys::path::native(Path, sys::path::Style::windows); - StringRef Name = InArchive ? File->getName() : StringRef(Path); - - File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); - File->ModuleDBI->setObjFileName(Path); - - // Before we can process symbol substreams from .debug$S, we need to process - // type information, file checksums, and the string table. Add type info to - // the PDB first, so that we can get the map from object file type and item - // indices to PDB type and item indices. - CVIndexMap ObjectIndexMap; - auto IndexMapResult = mergeDebugT(File, ObjectIndexMap); - - // If the .debug$T sections fail to merge, assume there is no debug info. - if (!IndexMapResult) { - warn("Type server PDB for " + Name + " is invalid, ignoring debug info. " + - toString(IndexMapResult.takeError())); - return; - } - - const CVIndexMap &IndexMap = *IndexMapResult; - - // Now do all live .debug$S sections. - for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") - continue; - - ArrayRef RelocatedDebugContents = - relocateDebugChunk(Alloc, DebugChunk); - if (RelocatedDebugContents.empty()) - continue; - - DebugSubsectionArray Subsections; - BinaryStreamReader Reader(RelocatedDebugContents, support::little); - ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - - DebugStringTableSubsectionRef CVStrTab; - DebugChecksumsSubsectionRef Checksums; - for (const DebugSubsectionRecord &SS : Subsections) { - switch (SS.kind()) { - case DebugSubsectionKind::StringTable: - ExitOnErr(CVStrTab.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::FileChecksums: - ExitOnErr(Checksums.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::Lines: - // We can add the relocated line table directly to the PDB without - // modification because the file checksum offsets will stay the same. - File->ModuleDBI->addDebugSubsection(SS); - break; - case DebugSubsectionKind::Symbols: - if (Config->DebugGHashes) { - mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - GlobalIDTable, SS.getRecordData()); - } else { - mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - IDTable, SS.getRecordData()); - } - break; - default: - // FIXME: Process the rest of the subsections. - break; - } - } - - if (Checksums.valid()) { - // Make a new file checksum table that refers to offsets in the PDB-wide - // string table. Generally the string table subsection appears after the - // checksum table, so we have to do this after looping over all the - // subsections. - if (!CVStrTab.valid()) - fatal(".debug$S sections must have both a string table subsection " - "and a checksum subsection table or neither"); - auto NewChecksums = make_unique(PDBStrTab); - for (FileChecksumEntry &FC : Checksums) { - StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); - ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, - FileName)); - NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); - } - File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); - } - } -} - -static PublicSym32 createPublic(Defined *Def) { - PublicSym32 Pub(SymbolKind::S_PUB32); - Pub.Name = Def->getName(); - if (auto *D = dyn_cast(Def)) { - if (D->getCOFFSymbol().isFunctionDefinition()) - Pub.Flags = PublicSymFlags::Function; - } else if (isa(Def)) { - Pub.Flags = PublicSymFlags::Function; - } - - OutputSection *OS = Def->getChunk()->getOutputSection(); - assert(OS && "all publics should be in final image"); - Pub.Offset = Def->getRVA() - OS->getRVA(); - Pub.Segment = OS->SectionIndex; - return Pub; -} - -// Add all object files to the PDB. Merge .debug$T sections into IpiData and -// TpiData. -void PDBLinker::addObjectsToPDB() { - for (ObjFile *File : ObjFile::Instances) - addObjFile(File); - - Builder.getStringTableBuilder().setStrings(PDBStrTab); - - // Construct TPI and IPI stream contents. - if (Config->DebugGHashes) { - addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable); - addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable); - } else { - addTypeInfo(Builder.getTpiBuilder(), TypeTable); - addTypeInfo(Builder.getIpiBuilder(), IDTable); - } - - // Compute the public and global symbols. - auto &GsiBuilder = Builder.getGsiBuilder(); - std::vector Publics; - Symtab->forEachSymbol([&Publics](Symbol *S) { - // Only emit defined, live symbols that have a chunk. - auto *Def = dyn_cast(S); - if (Def && Def->isLive() && Def->getChunk()) - Publics.push_back(createPublic(Def)); - }); - - if (!Publics.empty()) { - // Sort the public symbols and add them to the stream. - std::sort(Publics.begin(), Publics.end(), - [](const PublicSym32 &L, const PublicSym32 &R) { - return L.Name < R.Name; - }); - for (const PublicSym32 &Pub : Publics) - GsiBuilder.addPublicSymbol(Pub); - } -} - -static void addCommonLinkerModuleSymbols(StringRef Path, - pdb::DbiModuleDescriptorBuilder &Mod, - BumpPtrAllocator &Allocator) { - ObjNameSym ONS(SymbolRecordKind::ObjNameSym); - Compile3Sym CS(SymbolRecordKind::Compile3Sym); - EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); - - ONS.Name = "* Linker *"; - ONS.Signature = 0; - - CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; - // Interestingly, if we set the string to 0.0.0.0, then when trying to view - // local variables WinDbg emits an error that private symbols are not present. - // By setting this to a valid MSVC linker version string, local variables are - // displayed properly. As such, even though it is not representative of - // LLVM's version information, we need this for compatibility. - CS.Flags = CompileSym3Flags::None; - CS.VersionBackendBuild = 25019; - CS.VersionBackendMajor = 14; - CS.VersionBackendMinor = 10; - CS.VersionBackendQFE = 0; - - // MSVC also sets the frontend to 0.0.0.0 since this is specifically for the - // linker module (which is by definition a backend), so we don't need to do - // anything here. Also, it seems we can use "LLVM Linker" for the linker name - // without any problems. Only the backend version has to be hardcoded to a - // magic number. - CS.VersionFrontendBuild = 0; - CS.VersionFrontendMajor = 0; - CS.VersionFrontendMinor = 0; - CS.VersionFrontendQFE = 0; - CS.Version = "LLVM Linker"; - CS.setLanguage(SourceLanguage::Link); - - ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); - std::string ArgStr = llvm::join(Args, " "); - EBS.Fields.push_back("cwd"); - SmallString<64> cwd; - sys::fs::current_path(cwd); - EBS.Fields.push_back(cwd); - EBS.Fields.push_back("exe"); - SmallString<64> exe = Config->Argv[0]; - llvm::sys::fs::make_absolute(exe); - EBS.Fields.push_back(exe); - EBS.Fields.push_back("pdb"); - EBS.Fields.push_back(Path); - EBS.Fields.push_back("cmd"); - EBS.Fields.push_back(ArgStr); - Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - ONS, Allocator, CodeViewContainer::Pdb)); - Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - CS, Allocator, CodeViewContainer::Pdb)); - Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - EBS, Allocator, CodeViewContainer::Pdb)); -} - -static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, - OutputSection &OS, - BumpPtrAllocator &Allocator) { - SectionSym Sym(SymbolRecordKind::SectionSym); - Sym.Alignment = 12; // 2^12 = 4KB - Sym.Characteristics = OS.getCharacteristics(); - Sym.Length = OS.getVirtualSize(); - Sym.Name = OS.getName(); - Sym.Rva = OS.getRVA(); - Sym.SectionNumber = OS.SectionIndex; - Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( - Sym, Allocator, CodeViewContainer::Pdb)); -} - -// Creates a PDB file. -void coff::createPDB(SymbolTable *Symtab, - ArrayRef OutputSections, - ArrayRef SectionTable, - const llvm::codeview::DebugInfo &BuildId) { - PDBLinker PDB(Symtab); - PDB.initialize(BuildId); - PDB.addObjectsToPDB(); - PDB.addSections(OutputSections, SectionTable); - PDB.commit(); -} - -void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { - ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize - - // Create streams in MSF for predefined streams, namely - // PDB, TPI, DBI and IPI. - for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) - ExitOnErr(Builder.getMsfBuilder().addStream(0)); - - // Add an Info stream. - auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(BuildId.PDB70.Age); - - GUID uuid; - memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); - InfoBuilder.setGuid(uuid); - InfoBuilder.setSignature(time(nullptr)); - InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); - - // Add an empty DBI stream. - pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(BuildId.PDB70.Age); - DbiBuilder.setVersionHeader(pdb::PdbDbiV70); - ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); -} - -void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C) { - pdb::SectionContrib SC; - memset(&SC, 0, sizeof(SC)); - SC.ISect = OS->SectionIndex; - SC.Off = C->getRVA() - OS->getRVA(); - SC.Size = C->getSize(); - if (auto *SecChunk = dyn_cast(C)) { - SC.Characteristics = SecChunk->Header->Characteristics; - SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); - ArrayRef Contents = SecChunk->getContents(); - JamCRC CRC(0); - ArrayRef CharContents = makeArrayRef( - reinterpret_cast(Contents.data()), Contents.size()); - CRC.update(CharContents); - SC.DataCrc = CRC.getCRC(); - } else { - SC.Characteristics = OS->getCharacteristics(); - // FIXME: When we start creating DBI for import libraries, use those here. - SC.Imod = LinkerModule.getModuleIndex(); - } - SC.RelocCrc = 0; // FIXME - Builder.getDbiBuilder().addSectionContrib(SC); -} - -void PDBLinker::addSections(ArrayRef OutputSections, - ArrayRef SectionTable) { - // It's not entirely clear what this is, but the * Linker * module uses it. - pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - NativePath = Config->PDBPath; - sys::fs::make_absolute(NativePath); - sys::path::native(NativePath, sys::path::Style::windows); - uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); - auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); - LinkerModule.setPdbFilePathNI(PdbFilePathNI); - addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc); - - // Add section contributions. They must be ordered by ascending RVA. - for (OutputSection *OS : OutputSections) { - addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc); - for (Chunk *C : OS->getChunks()) - addSectionContrib(LinkerModule, OS, C); - } - - // Add Section Map stream. - ArrayRef Sections = { - (const object::coff_section *)SectionTable.data(), - SectionTable.size() / sizeof(object::coff_section)}; - SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); - DbiBuilder.setSectionMap(SectionMap); - - // Add COFF section header stream. - ExitOnErr( - DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); -} - -void PDBLinker::commit() { - // Write to a file. - ExitOnErr(Builder.commit(Config->PDBPath)); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/PDB.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/PDB.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/PDB.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/PDB.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -//===- PDB.h ----------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_PDB_H -#define LLD_COFF_PDB_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" - -namespace llvm { -namespace codeview { -union DebugInfo; -} -} - -namespace lld { -namespace coff { -class OutputSection; -class SymbolTable; - -void createPDB(SymbolTable *Symtab, - llvm::ArrayRef OutputSections, - llvm::ArrayRef SectionTable, - const llvm::codeview::DebugInfo &BuildId); -} -} - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/README.md rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/README.md --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/README.md 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -See docs/NewLLD.rst diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Strings.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Strings.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Strings.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Strings.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Strings.h" -#include - -#if defined(_MSC_VER) -#include -#include -#pragma comment(lib, "dbghelp.lib") -#endif - -using namespace lld; -using namespace lld::coff; -using namespace llvm; - -Optional coff::demangleMSVC(StringRef S) { -#if defined(_MSC_VER) - // UnDecorateSymbolName is not thread-safe, so we need a mutex. - static std::mutex Mu; - std::lock_guard Lock(Mu); - - char Buf[4096]; - if (S.startswith("?")) - if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) - return std::string(Buf, Len); -#endif - return None; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Strings.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Strings.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Strings.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Strings.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -//===- Strings.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_STRINGS_H -#define LLD_COFF_STRINGS_H - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace lld { -namespace coff { -llvm::Optional demangleMSVC(llvm::StringRef S); -} -} - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Symbols.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Symbols.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Symbols.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Symbols.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -//===- Symbols.cpp --------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Symbols.h" -#include "InputFiles.h" -#include "Strings.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::object; - -// Returns a symbol name for an error message. -std::string lld::toString(coff::Symbol &B) { - if (Optional S = coff::demangleMSVC(B.getName())) - return ("\"" + *S + "\" (" + B.getName() + ")").str(); - return B.getName(); -} - -namespace lld { -namespace coff { - -StringRef Symbol::getName() { - // COFF symbol names are read lazily for a performance reason. - // Non-external symbol names are never used by the linker except for logging - // or debugging. Their internal references are resolved not by name but by - // symbol index. And because they are not external, no one can refer them by - // name. Object files contain lots of non-external symbols, and creating - // StringRefs for them (which involves lots of strlen() on the string table) - // is a waste of time. - if (Name.empty()) { - auto *D = cast(this); - cast(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name); - } - return Name; -} - -InputFile *Symbol::getFile() { - if (auto *Sym = dyn_cast(this)) - return Sym->File; - if (auto *Sym = dyn_cast(this)) - return Sym->File; - return nullptr; -} - -bool Symbol::isLive() const { - if (auto *R = dyn_cast(this)) - return R->getChunk()->isLive(); - if (auto *Imp = dyn_cast(this)) - return Imp->File->Live; - if (auto *Imp = dyn_cast(this)) - return Imp->WrappedSym->File->Live; - // Assume any other kind of symbol is live. - return true; -} - -COFFSymbolRef DefinedCOFF::getCOFFSymbol() { - size_t SymSize = cast(File)->getCOFFObj()->getSymbolTableEntrySize(); - if (SymSize == sizeof(coff_symbol16)) - return COFFSymbolRef(reinterpret_cast(Sym)); - assert(SymSize == sizeof(coff_symbol32)); - return COFFSymbolRef(reinterpret_cast(Sym)); -} - -uint16_t DefinedAbsolute::OutputSectionIndex = 0; - -static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { - if (Machine == AMD64) - return make(S); - if (Machine == I386) - return make(S); - if (Machine == ARM64) - return make(S); - assert(Machine == ARMNT); - return make(S); -} - -DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, - uint16_t Machine) - : Defined(DefinedImportThunkKind, Name), WrappedSym(S), - Data(makeImportThunk(S, Machine)) {} - -Defined *Undefined::getWeakAlias() { - // A weak alias may be a weak alias to another symbol, so check recursively. - for (Symbol *A = WeakAlias; A; A = cast(A)->WeakAlias) - if (auto *D = dyn_cast(A)) - return D; - return nullptr; -} -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Symbols.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Symbols.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Symbols.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Symbols.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,431 +0,0 @@ -//===- Symbols.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_SYMBOLS_H -#define LLD_COFF_SYMBOLS_H - -#include "Chunks.h" -#include "Config.h" -#include "lld/Common/LLVM.h" -#include "lld/Common/Memory.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/COFF.h" -#include -#include -#include - -namespace lld { -namespace coff { - -using llvm::object::Archive; -using llvm::object::COFFSymbolRef; -using llvm::object::coff_import_header; -using llvm::object::coff_symbol_generic; - -class ArchiveFile; -class InputFile; -class ObjFile; -class SymbolTable; - -// The base class for real symbol classes. -class Symbol { -public: - enum Kind { - // The order of these is significant. We start with the regular defined - // symbols as those are the most prevelant and the zero tag is the cheapest - // to set. Among the defined kinds, the lower the kind is preferred over - // the higher kind when testing wether one symbol should take precedence - // over another. - DefinedRegularKind = 0, - DefinedCommonKind, - DefinedLocalImportKind, - DefinedImportThunkKind, - DefinedImportDataKind, - DefinedAbsoluteKind, - DefinedSyntheticKind, - - UndefinedKind, - LazyKind, - - LastDefinedCOFFKind = DefinedCommonKind, - LastDefinedKind = DefinedSyntheticKind, - }; - - Kind kind() const { return static_cast(SymbolKind); } - - // Returns true if this is an external symbol. - bool isExternal() { return IsExternal; } - - // Returns the symbol name. - StringRef getName(); - - // Returns the file from which this symbol was created. - InputFile *getFile(); - - // Indicates that this symbol will be included in the final image. Only valid - // after calling markLive. - bool isLive() const; - -protected: - friend SymbolTable; - explicit Symbol(Kind K, StringRef N = "") - : SymbolKind(K), IsExternal(true), IsCOMDAT(false), - WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false), - Name(N) {} - - const unsigned SymbolKind : 8; - unsigned IsExternal : 1; - - // This bit is used by the \c DefinedRegular subclass. - unsigned IsCOMDAT : 1; - -public: - // This bit is used by Writer::createSymbolAndStringTable() to prevent - // symbols from being written to the symbol table more than once. - unsigned WrittenToSymtab : 1; - - // True if this symbol was referenced by a regular (non-bitcode) object. - unsigned IsUsedInRegularObj : 1; - - // True if we've seen both a lazy and an undefined symbol with this symbol - // name, which means that we have enqueued an archive member load and should - // not load any more archive members to resolve the same symbol. - unsigned PendingArchiveLoad : 1; - - /// True if we've already added this symbol to the list of GC roots. - unsigned IsGCRoot : 1; - -protected: - StringRef Name; -}; - -// The base class for any defined symbols, including absolute symbols, -// etc. -class Defined : public Symbol { -public: - Defined(Kind K, StringRef N) : Symbol(K, N) {} - - static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; } - - // Returns the RVA (relative virtual address) of this symbol. The - // writer sets and uses RVAs. - uint64_t getRVA(); - - // Returns the chunk containing this symbol. Absolute symbols and __ImageBase - // do not have chunks, so this may return null. - Chunk *getChunk(); -}; - -// Symbols defined via a COFF object file or bitcode file. For COFF files, this -// stores a coff_symbol_generic*, and names of internal symbols are lazily -// loaded through that. For bitcode files, Sym is nullptr and the name is stored -// as a StringRef. -class DefinedCOFF : public Defined { - friend Symbol; - -public: - DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) - : Defined(K, N), File(F), Sym(S) {} - - static bool classof(const Symbol *S) { - return S->kind() <= LastDefinedCOFFKind; - } - - InputFile *getFile() { return File; } - - COFFSymbolRef getCOFFSymbol(); - - InputFile *File; - -protected: - const coff_symbol_generic *Sym; -}; - -// Regular defined symbols read from object file symbol tables. -class DefinedRegular : public DefinedCOFF { -public: - DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, - bool IsExternal = false, - const coff_symbol_generic *S = nullptr, - SectionChunk *C = nullptr) - : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) { - this->IsExternal = IsExternal; - this->IsCOMDAT = IsCOMDAT; - } - - static bool classof(const Symbol *S) { - return S->kind() == DefinedRegularKind; - } - - uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; } - bool isCOMDAT() const { return IsCOMDAT; } - SectionChunk *getChunk() const { return *Data; } - uint32_t getValue() const { return Sym->Value; } - - SectionChunk **Data; -}; - -class DefinedCommon : public DefinedCOFF { -public: - DefinedCommon(InputFile *F, StringRef N, uint64_t Size, - const coff_symbol_generic *S = nullptr, - CommonChunk *C = nullptr) - : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { - this->IsExternal = true; - } - - static bool classof(const Symbol *S) { - return S->kind() == DefinedCommonKind; - } - - uint64_t getRVA() { return Data->getRVA(); } - CommonChunk *getChunk() { return Data; } - -private: - friend SymbolTable; - uint64_t getSize() const { return Size; } - CommonChunk *Data; - uint64_t Size; -}; - -// Absolute symbols. -class DefinedAbsolute : public Defined { -public: - DefinedAbsolute(StringRef N, COFFSymbolRef S) - : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { - IsExternal = S.isExternal(); - } - - DefinedAbsolute(StringRef N, uint64_t V) - : Defined(DefinedAbsoluteKind, N), VA(V) {} - - static bool classof(const Symbol *S) { - return S->kind() == DefinedAbsoluteKind; - } - - uint64_t getRVA() { return VA - Config->ImageBase; } - void setVA(uint64_t V) { VA = V; } - - // The sentinel absolute symbol section index. Section index relocations - // against absolute symbols resolve to this 16 bit number, and it is the - // largest valid section index plus one. This is written by the Writer. - static uint16_t OutputSectionIndex; - uint16_t getSecIdx() { return OutputSectionIndex; } - -private: - uint64_t VA; -}; - -// This symbol is used for linker-synthesized symbols like __ImageBase and -// __safe_se_handler_table. -class DefinedSynthetic : public Defined { -public: - explicit DefinedSynthetic(StringRef Name, Chunk *C) - : Defined(DefinedSyntheticKind, Name), C(C) {} - - static bool classof(const Symbol *S) { - return S->kind() == DefinedSyntheticKind; - } - - // A null chunk indicates that this is __ImageBase. Otherwise, this is some - // other synthesized chunk, like SEHTableChunk. - uint32_t getRVA() { return C ? C->getRVA() : 0; } - Chunk *getChunk() { return C; } - -private: - Chunk *C; -}; - -// This class represents a symbol defined in an archive file. It is -// created from an archive file header, and it knows how to load an -// object file from an archive to replace itself with a defined -// symbol. If the resolver finds both Undefined and Lazy for -// the same name, it will ask the Lazy to load a file. -class Lazy : public Symbol { -public: - Lazy(ArchiveFile *F, const Archive::Symbol S) - : Symbol(LazyKind, S.getName()), File(F), Sym(S) {} - - static bool classof(const Symbol *S) { return S->kind() == LazyKind; } - - ArchiveFile *File; - -private: - friend SymbolTable; - -private: - const Archive::Symbol Sym; -}; - -// Undefined symbols. -class Undefined : public Symbol { -public: - explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {} - - static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } - - // An undefined symbol can have a fallback symbol which gives an - // undefined symbol a second chance if it would remain undefined. - // If it remains undefined, it'll be replaced with whatever the - // Alias pointer points to. - Symbol *WeakAlias = nullptr; - - // If this symbol is external weak, try to resolve it to a defined - // symbol by searching the chain of fallback symbols. Returns the symbol if - // successful, otherwise returns null. - Defined *getWeakAlias(); -}; - -// Windows-specific classes. - -// This class represents a symbol imported from a DLL. This has two -// names for internal use and external use. The former is used for -// name resolution, and the latter is used for the import descriptor -// table in an output. The former has "__imp_" prefix. -class DefinedImportData : public Defined { -public: - DefinedImportData(StringRef N, ImportFile *F) - : Defined(DefinedImportDataKind, N), File(F) { - } - - static bool classof(const Symbol *S) { - return S->kind() == DefinedImportDataKind; - } - - uint64_t getRVA() { return File->Location->getRVA(); } - Chunk *getChunk() { return File->Location; } - void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } - - StringRef getDLLName() { return File->DLLName; } - StringRef getExternalName() { return File->ExternalName; } - uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } - - ImportFile *File; -}; - -// This class represents a symbol for a jump table entry which jumps -// to a function in a DLL. Linker are supposed to create such symbols -// without "__imp_" prefix for all function symbols exported from -// DLLs, so that you can call DLL functions as regular functions with -// a regular name. A function pointer is given as a DefinedImportData. -class DefinedImportThunk : public Defined { -public: - DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); - - static bool classof(const Symbol *S) { - return S->kind() == DefinedImportThunkKind; - } - - uint64_t getRVA() { return Data->getRVA(); } - Chunk *getChunk() { return Data; } - - DefinedImportData *WrappedSym; - -private: - Chunk *Data; -}; - -// If you have a symbol "__imp_foo" in your object file, a symbol name -// "foo" becomes automatically available as a pointer to "__imp_foo". -// This class is for such automatically-created symbols. -// Yes, this is an odd feature. We didn't intend to implement that. -// This is here just for compatibility with MSVC. -class DefinedLocalImport : public Defined { -public: - DefinedLocalImport(StringRef N, Defined *S) - : Defined(DefinedLocalImportKind, N), Data(make(S)) {} - - static bool classof(const Symbol *S) { - return S->kind() == DefinedLocalImportKind; - } - - uint64_t getRVA() { return Data->getRVA(); } - Chunk *getChunk() { return Data; } - -private: - LocalImportChunk *Data; -}; - -inline uint64_t Defined::getRVA() { - switch (kind()) { - case DefinedAbsoluteKind: - return cast(this)->getRVA(); - case DefinedSyntheticKind: - return cast(this)->getRVA(); - case DefinedImportDataKind: - return cast(this)->getRVA(); - case DefinedImportThunkKind: - return cast(this)->getRVA(); - case DefinedLocalImportKind: - return cast(this)->getRVA(); - case DefinedCommonKind: - return cast(this)->getRVA(); - case DefinedRegularKind: - return cast(this)->getRVA(); - case LazyKind: - case UndefinedKind: - llvm_unreachable("Cannot get the address for an undefined symbol."); - } - llvm_unreachable("unknown symbol kind"); -} - -inline Chunk *Defined::getChunk() { - switch (kind()) { - case DefinedRegularKind: - return cast(this)->getChunk(); - case DefinedAbsoluteKind: - return nullptr; - case DefinedSyntheticKind: - return cast(this)->getChunk(); - case DefinedImportDataKind: - return cast(this)->getChunk(); - case DefinedImportThunkKind: - return cast(this)->getChunk(); - case DefinedLocalImportKind: - return cast(this)->getChunk(); - case DefinedCommonKind: - return cast(this)->getChunk(); - case LazyKind: - case UndefinedKind: - llvm_unreachable("Cannot get the chunk of an undefined symbol."); - } - llvm_unreachable("unknown symbol kind"); -} - -// A buffer class that is large enough to hold any Symbol-derived -// object. We allocate memory using this class and instantiate a symbol -// using the placement new. -union SymbolUnion { - alignas(DefinedRegular) char A[sizeof(DefinedRegular)]; - alignas(DefinedCommon) char B[sizeof(DefinedCommon)]; - alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)]; - alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)]; - alignas(Lazy) char E[sizeof(Lazy)]; - alignas(Undefined) char F[sizeof(Undefined)]; - alignas(DefinedImportData) char G[sizeof(DefinedImportData)]; - alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)]; - alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)]; -}; - -template -void replaceSymbol(Symbol *S, ArgT &&... Arg) { - static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); - static_assert(alignof(T) <= alignof(SymbolUnion), - "SymbolUnion not aligned enough"); - assert(static_cast(static_cast(nullptr)) == nullptr && - "Not a Symbol"); - new (S) T(std::forward(Arg)...); -} -} // namespace coff - -std::string toString(coff::Symbol &B); -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,395 +0,0 @@ -//===- SymbolTable.cpp ----------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SymbolTable.h" -#include "Config.h" -#include "Driver.h" -#include "LTO.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; - -namespace lld { -namespace coff { - -SymbolTable *Symtab; - -void SymbolTable::addFile(InputFile *File) { - log("Reading " + toString(File)); - File->parse(); - - MachineTypes MT = File->getMachineType(); - if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { - Config->Machine = MT; - } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { - fatal(toString(File) + ": machine type " + machineToStr(MT) + - " conflicts with " + machineToStr(Config->Machine)); - } - - if (auto *F = dyn_cast(File)) { - ObjFile::Instances.push_back(F); - } else if (auto *F = dyn_cast(File)) { - BitcodeFile::Instances.push_back(F); - } else if (auto *F = dyn_cast(File)) { - ImportFile::Instances.push_back(F); - } - - StringRef S = File->getDirectives(); - if (S.empty()) - return; - - log("Directives: " + toString(File) + ": " + S); - Driver->parseDirectives(S); -} - -static void errorOrWarn(const Twine &S) { - if (Config->Force) - warn(S); - else - error(S); -} - -void SymbolTable::reportRemainingUndefines() { - SmallPtrSet Undefs; - DenseMap LocalImports; - - for (auto &I : SymMap) { - Symbol *Sym = I.second; - auto *Undef = dyn_cast(Sym); - if (!Undef) - continue; - if (!Sym->IsUsedInRegularObj) - continue; - - StringRef Name = Undef->getName(); - - // A weak alias may have been resolved, so check for that. - if (Defined *D = Undef->getWeakAlias()) { - // We want to replace Sym with D. However, we can't just blindly - // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an - // internal symbol, and internal symbols are stored as "unparented" - // Symbols. For that reason we need to check which type of symbol we - // are dealing with and copy the correct number of bytes. - if (isa(D)) - memcpy(Sym, D, sizeof(DefinedRegular)); - else if (isa(D)) - memcpy(Sym, D, sizeof(DefinedAbsolute)); - else - memcpy(Sym, D, sizeof(SymbolUnion)); - continue; - } - - // If we can resolve a symbol by removing __imp_ prefix, do that. - // This odd rule is for compatibility with MSVC linker. - if (Name.startswith("__imp_")) { - Symbol *Imp = find(Name.substr(strlen("__imp_"))); - if (Imp && isa(Imp)) { - auto *D = cast(Imp); - replaceSymbol(Sym, Name, D); - LocalImportChunks.push_back(cast(Sym)->getChunk()); - LocalImports[Sym] = D; - continue; - } - } - - // Remaining undefined symbols are not fatal if /force is specified. - // They are replaced with dummy defined symbols. - if (Config->Force) - replaceSymbol(Sym, Name, 0); - Undefs.insert(Sym); - } - - if (Undefs.empty() && LocalImports.empty()) - return; - - for (Symbol *B : Config->GCRoot) { - if (Undefs.count(B)) - errorOrWarn(": undefined symbol: " + B->getName()); - if (Config->WarnLocallyDefinedImported) - if (Symbol *Imp = LocalImports.lookup(B)) - warn(": locally defined symbol imported: " + Imp->getName() + - " (defined in " + toString(Imp->getFile()) + ")"); - } - - for (ObjFile *File : ObjFile::Instances) { - for (Symbol *Sym : File->getSymbols()) { - if (!Sym) - continue; - if (Undefs.count(Sym)) - errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName()); - if (Config->WarnLocallyDefinedImported) - if (Symbol *Imp = LocalImports.lookup(Sym)) - warn(toString(File) + ": locally defined symbol imported: " + - Imp->getName() + " (defined in " + toString(Imp->getFile()) + - ")"); - } - } -} - -std::pair SymbolTable::insert(StringRef Name) { - Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; - if (Sym) - return {Sym, false}; - Sym = (Symbol *)make(); - Sym->IsUsedInRegularObj = false; - Sym->PendingArchiveLoad = false; - return {Sym, true}; -} - -Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, - bool IsWeakAlias) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - if (!F || !isa(F)) - S->IsUsedInRegularObj = true; - if (WasInserted || (isa(S) && IsWeakAlias)) { - replaceSymbol(S, Name); - return S; - } - if (auto *L = dyn_cast(S)) { - if (!S->PendingArchiveLoad) { - S->PendingArchiveLoad = true; - L->File->addMember(&L->Sym); - } - } - return S; -} - -void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { - StringRef Name = Sym.getName(); - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - replaceSymbol(S, F, Sym); - return; - } - auto *U = dyn_cast(S); - if (!U || U->WeakAlias || S->PendingArchiveLoad) - return; - S->PendingArchiveLoad = true; - F->addMember(&Sym); -} - -void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { - error("duplicate symbol: " + toString(*Existing) + " in " + - toString(Existing->getFile()) + " and in " + toString(NewFile)); -} - -Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S) || isa(S)) - replaceSymbol(S, N, Sym); - else if (!isa(S)) - reportDuplicate(S, nullptr); - return S; -} - -Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S) || isa(S)) - replaceSymbol(S, N, VA); - else if (!isa(S)) - reportDuplicate(S, nullptr); - return S; -} - -Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S) || isa(S)) - replaceSymbol(S, N, C); - else if (!isa(S)) - reportDuplicate(S, nullptr); - return S; -} - -Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, - const coff_symbol_generic *Sym, - SectionChunk *C) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - if (!isa(F)) - S->IsUsedInRegularObj = true; - if (WasInserted || !isa(S)) - replaceSymbol(S, F, N, /*IsCOMDAT*/ false, - /*IsExternal*/ true, Sym, C); - else - reportDuplicate(S, F); - return S; -} - -std::pair -SymbolTable::addComdat(InputFile *F, StringRef N, - const coff_symbol_generic *Sym) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - if (!isa(F)) - S->IsUsedInRegularObj = true; - if (WasInserted || !isa(S)) { - replaceSymbol(S, F, N, /*IsCOMDAT*/ true, - /*IsExternal*/ true, Sym, nullptr); - return {S, true}; - } - if (!cast(S)->isCOMDAT()) - reportDuplicate(S, F); - return {S, false}; -} - -Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, - const coff_symbol_generic *Sym, CommonChunk *C) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - if (!isa(F)) - S->IsUsedInRegularObj = true; - if (WasInserted || !isa(S)) - replaceSymbol(S, F, N, Size, Sym, C); - else if (auto *DC = dyn_cast(S)) - if (Size > DC->getSize()) - replaceSymbol(S, F, N, Size, Sym, C); - return S; -} - -DefinedImportData *SymbolTable::addImportData(StringRef N, ImportFile *F) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(N); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S) || isa(S)) { - replaceSymbol(S, N, F); - return cast(S); - } - - reportDuplicate(S, F); - return nullptr; -} - -DefinedImportThunk *SymbolTable::addImportThunk(StringRef Name, - DefinedImportData *ID, - uint16_t Machine) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S) || isa(S)) { - replaceSymbol(S, Name, ID, Machine); - return cast(S); - } - - reportDuplicate(S, ID->File); - return nullptr; -} - -std::vector SymbolTable::getChunks() { - std::vector Res; - for (ObjFile *File : ObjFile::Instances) { - ArrayRef V = File->getChunks(); - Res.insert(Res.end(), V.begin(), V.end()); - } - return Res; -} - -Symbol *SymbolTable::find(StringRef Name) { - auto It = SymMap.find(CachedHashStringRef(Name)); - if (It == SymMap.end()) - return nullptr; - return It->second; -} - -Symbol *SymbolTable::findUnderscore(StringRef Name) { - if (Config->Machine == I386) - return find(("_" + Name).str()); - return find(Name); -} - -StringRef SymbolTable::findByPrefix(StringRef Prefix) { - for (auto Pair : SymMap) { - StringRef Name = Pair.first.val(); - if (Name.startswith(Prefix)) - return Name; - } - return ""; -} - -StringRef SymbolTable::findMangle(StringRef Name) { - if (Symbol *Sym = find(Name)) - if (!isa(Sym)) - return Name; - if (Config->Machine != I386) - return findByPrefix(("?" + Name + "@@Y").str()); - if (!Name.startswith("_")) - return ""; - // Search for x86 stdcall function. - StringRef S = findByPrefix((Name + "@").str()); - if (!S.empty()) - return S; - // Search for x86 fastcall function. - S = findByPrefix(("@" + Name.substr(1) + "@").str()); - if (!S.empty()) - return S; - // Search for x86 vectorcall function. - S = findByPrefix((Name.substr(1) + "@@").str()); - if (!S.empty()) - return S; - // Search for x86 C++ non-member function. - return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); -} - -void SymbolTable::mangleMaybe(Symbol *B) { - auto *U = dyn_cast(B); - if (!U || U->WeakAlias) - return; - StringRef Alias = findMangle(U->getName()); - if (!Alias.empty()) { - log(U->getName() + " aliased to " + Alias); - U->WeakAlias = addUndefined(Alias); - } -} - -Symbol *SymbolTable::addUndefined(StringRef Name) { - return addUndefined(Name, nullptr, false); -} - -std::vector SymbolTable::compileBitcodeFiles() { - LTO.reset(new BitcodeCompiler); - for (BitcodeFile *F : BitcodeFile::Instances) - LTO->add(*F); - return LTO->compile(); -} - -void SymbolTable::addCombinedLTOObjects() { - if (BitcodeFile::Instances.empty()) - return; - for (StringRef Object : compileBitcodeFiles()) { - auto *Obj = make(MemoryBufferRef(Object, "lto.tmp")); - Obj->parse(); - ObjFile::Instances.push_back(Obj); - } -} - -} // namespace coff -} // namespace lld diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/SymbolTable.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -//===- SymbolTable.h --------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_SYMBOL_TABLE_H -#define LLD_COFF_SYMBOL_TABLE_H - -#include "InputFiles.h" -#include "LTO.h" -#include "llvm/ADT/CachedHashString.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { -struct LTOCodeGenerator; -} - -namespace lld { -namespace coff { - -class Chunk; -class CommonChunk; -class Defined; -class DefinedAbsolute; -class DefinedRelative; -class Lazy; -class SectionChunk; -class Symbol; - -// SymbolTable is a bucket of all known symbols, including defined, -// undefined, or lazy symbols (the last one is symbols in archive -// files whose archive members are not yet loaded). -// -// We put all symbols of all files to a SymbolTable, and the -// SymbolTable selects the "best" symbols if there are name -// conflicts. For example, obviously, a defined symbol is better than -// an undefined symbol. Or, if there's a conflict between a lazy and a -// undefined, it'll read an archive member to read a real definition -// to replace the lazy symbol. The logic is implemented in the -// add*() functions, which are called by input files as they are parsed. -// There is one add* function per symbol type. -class SymbolTable { -public: - void addFile(InputFile *File); - - // Try to resolve any undefined symbols and update the symbol table - // accordingly, then print an error message for any remaining undefined - // symbols. - void reportRemainingUndefines(); - - // Returns a list of chunks of selected symbols. - std::vector getChunks(); - - // Returns a symbol for a given name. Returns a nullptr if not found. - Symbol *find(StringRef Name); - Symbol *findUnderscore(StringRef Name); - - // Occasionally we have to resolve an undefined symbol to its - // mangled symbol. This function tries to find a mangled name - // for U from the symbol table, and if found, set the symbol as - // a weak alias for U. - void mangleMaybe(Symbol *B); - StringRef findMangle(StringRef Name); - - // Build a set of COFF objects representing the combined contents of - // BitcodeFiles and add them to the symbol table. Called after all files are - // added and before the writer writes results to a file. - void addCombinedLTOObjects(); - std::vector compileBitcodeFiles(); - - // Creates an Undefined symbol for a given name. - Symbol *addUndefined(StringRef Name); - - Symbol *addSynthetic(StringRef N, Chunk *C); - Symbol *addAbsolute(StringRef N, uint64_t VA); - - Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); - void addLazy(ArchiveFile *F, const Archive::Symbol Sym); - Symbol *addAbsolute(StringRef N, COFFSymbolRef S); - Symbol *addRegular(InputFile *F, StringRef N, - const llvm::object::coff_symbol_generic *S = nullptr, - SectionChunk *C = nullptr); - std::pair - addComdat(InputFile *F, StringRef N, - const llvm::object::coff_symbol_generic *S = nullptr); - Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, - const llvm::object::coff_symbol_generic *S = nullptr, - CommonChunk *C = nullptr); - DefinedImportData *addImportData(StringRef N, ImportFile *F); - DefinedImportThunk *addImportThunk(StringRef Name, DefinedImportData *S, - uint16_t Machine); - - void reportDuplicate(Symbol *Existing, InputFile *NewFile); - - // A list of chunks which to be added to .rdata. - std::vector LocalImportChunks; - - // Iterates symbols in non-determinstic hash table order. - template void forEachSymbol(T Callback) { - for (auto &Pair : SymMap) - Callback(Pair.second); - } - -private: - std::pair insert(StringRef Name); - StringRef findByPrefix(StringRef Prefix); - - llvm::DenseMap SymMap; - std::unique_ptr LTO; -}; - -extern SymbolTable *Symtab; - -} // namespace coff -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Writer.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Writer.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Writer.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Writer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,971 +0,0 @@ -//===- Writer.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Writer.h" -#include "Config.h" -#include "DLL.h" -#include "InputFiles.h" -#include "MapFile.h" -#include "PDB.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/Parallel.h" -#include "llvm/Support/RandomNumberGenerator.h" -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::COFF; -using namespace llvm::object; -using namespace llvm::support; -using namespace llvm::support::endian; -using namespace lld; -using namespace lld::coff; - -static const int SectorSize = 512; -static const int DOSStubSize = 64; -static const int NumberfOfDataDirectory = 16; - -namespace { - -class DebugDirectoryChunk : public Chunk { -public: - DebugDirectoryChunk(const std::vector &R) : Records(R) {} - - size_t getSize() const override { - return Records.size() * sizeof(debug_directory); - } - - void writeTo(uint8_t *B) const override { - auto *D = reinterpret_cast(B + OutputSectionOff); - - for (const Chunk *Record : Records) { - D->Characteristics = 0; - D->TimeDateStamp = 0; - D->MajorVersion = 0; - D->MinorVersion = 0; - D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW; - D->SizeOfData = Record->getSize(); - D->AddressOfRawData = Record->getRVA(); - OutputSection *OS = Record->getOutputSection(); - uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); - D->PointerToRawData = Offs; - - ++D; - } - } - -private: - const std::vector &Records; -}; - -class CVDebugRecordChunk : public Chunk { -public: - CVDebugRecordChunk() { - PDBAbsPath = Config->PDBPath; - if (!PDBAbsPath.empty()) - llvm::sys::fs::make_absolute(PDBAbsPath); - } - - size_t getSize() const override { - return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1; - } - - void writeTo(uint8_t *B) const override { - // Save off the DebugInfo entry to backfill the file signature (build id) - // in Writer::writeBuildId - BuildId = reinterpret_cast(B + OutputSectionOff); - - // variable sized field (PDB Path) - char *P = reinterpret_cast(B + OutputSectionOff + sizeof(*BuildId)); - if (!PDBAbsPath.empty()) - memcpy(P, PDBAbsPath.data(), PDBAbsPath.size()); - P[PDBAbsPath.size()] = '\0'; - } - - SmallString<128> PDBAbsPath; - mutable codeview::DebugInfo *BuildId = nullptr; -}; - -// The writer writes a SymbolTable result to a file. -class Writer { -public: - Writer() : Buffer(errorHandler().OutputBuffer) {} - void run(); - -private: - void createSections(); - void createMiscChunks(); - void createImportTables(); - void createExportTable(); - void assignAddresses(); - void removeEmptySections(); - void createSymbolAndStringTable(); - void openFile(StringRef OutputPath); - template void writeHeader(); - void createSEHTable(OutputSection *RData); - void setSectionPermissions(); - void writeSections(); - void writeBuildId(); - void sortExceptionTable(); - - llvm::Optional createSymbol(Defined *D); - size_t addEntryToStringTable(StringRef Str); - - OutputSection *findSection(StringRef Name); - OutputSection *createSection(StringRef Name); - void addBaserels(OutputSection *Dest); - void addBaserelBlocks(OutputSection *Dest, std::vector &V); - - uint32_t getSizeOfInitializedData(); - std::map> binImports(); - - std::unique_ptr &Buffer; - std::vector OutputSections; - std::vector Strtab; - std::vector OutputSymtab; - IdataContents Idata; - DelayLoadContents DelayIdata; - EdataContents Edata; - SEHTableChunk *SEHTable = nullptr; - - Chunk *DebugDirectory = nullptr; - std::vector DebugRecords; - CVDebugRecordChunk *BuildId = nullptr; - Optional PreviousBuildId; - ArrayRef SectionTable; - - uint64_t FileSize; - uint32_t PointerToSymbolTable = 0; - uint64_t SizeOfImage; - uint64_t SizeOfHeaders; -}; -} // anonymous namespace - -namespace lld { -namespace coff { - -void writeResult() { Writer().run(); } - -void OutputSection::setRVA(uint64_t RVA) { - Header.VirtualAddress = RVA; - for (Chunk *C : Chunks) - C->setRVA(C->getRVA() + RVA); -} - -void OutputSection::setFileOffset(uint64_t Off) { - // If a section has no actual data (i.e. BSS section), we want to - // set 0 to its PointerToRawData. Otherwise the output is rejected - // by the loader. - if (Header.SizeOfRawData == 0) - return; - Header.PointerToRawData = Off; -} - -void OutputSection::addChunk(Chunk *C) { - Chunks.push_back(C); - C->setOutputSection(this); - uint64_t Off = Header.VirtualSize; - Off = alignTo(Off, C->Alignment); - C->setRVA(Off); - C->OutputSectionOff = Off; - Off += C->getSize(); - if (Off > UINT32_MAX) - error("section larger than 4 GiB: " + Name); - Header.VirtualSize = Off; - if (C->hasData()) - Header.SizeOfRawData = alignTo(Off, SectorSize); -} - -void OutputSection::addPermissions(uint32_t C) { - Header.Characteristics |= C & PermMask; -} - -void OutputSection::setPermissions(uint32_t C) { - Header.Characteristics = C & PermMask; -} - -// Write the section header to a given buffer. -void OutputSection::writeHeaderTo(uint8_t *Buf) { - auto *Hdr = reinterpret_cast(Buf); - *Hdr = Header; - if (StringTableOff) { - // If name is too long, write offset into the string table as a name. - sprintf(Hdr->Name, "/%d", StringTableOff); - } else { - assert(!Config->Debug || Name.size() <= COFF::NameSize || - (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); - strncpy(Hdr->Name, Name.data(), - std::min(Name.size(), (size_t)COFF::NameSize)); - } -} - -} // namespace coff -} // namespace lld - -// PDBs are matched against executables using a build id which consists of three -// components: -// 1. A 16-bit GUID -// 2. An age -// 3. A time stamp. -// -// Debuggers and symbol servers match executables against debug info by checking -// each of these components of the EXE/DLL against the corresponding value in -// the PDB and failing a match if any of the components differ. In the case of -// symbol servers, symbols are cached in a folder that is a function of the -// GUID. As a result, in order to avoid symbol cache pollution where every -// incremental build copies a new PDB to the symbol cache, we must try to re-use -// the existing GUID if one exists, but bump the age. This way the match will -// fail, so the symbol cache knows to use the new PDB, but the GUID matches, so -// it overwrites the existing item in the symbol cache rather than making a new -// one. -static Optional loadExistingBuildId(StringRef Path) { - // We don't need to incrementally update a previous build id if we're not - // writing codeview debug info. - if (!Config->Debug) - return None; - - auto ExpectedBinary = llvm::object::createBinary(Path); - if (!ExpectedBinary) { - consumeError(ExpectedBinary.takeError()); - return None; - } - - auto Binary = std::move(*ExpectedBinary); - if (!Binary.getBinary()->isCOFF()) - return None; - - std::error_code EC; - COFFObjectFile File(Binary.getBinary()->getMemoryBufferRef(), EC); - if (EC) - return None; - - // If the machine of the binary we're outputting doesn't match the machine - // of the existing binary, don't try to re-use the build id. - if (File.is64() != Config->is64() || File.getMachine() != Config->Machine) - return None; - - for (const auto &DebugDir : File.debug_directories()) { - if (DebugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) - continue; - - const codeview::DebugInfo *ExistingDI = nullptr; - StringRef PDBFileName; - if (auto EC = File.getDebugPDBInfo(ExistingDI, PDBFileName)) { - (void)EC; - return None; - } - // We only support writing PDBs in v70 format. So if this is not a build - // id that we recognize / support, ignore it. - if (ExistingDI->Signature.CVSignature != OMF::Signature::PDB70) - return None; - return *ExistingDI; - } - return None; -} - -// The main function of the writer. -void Writer::run() { - createSections(); - createMiscChunks(); - createImportTables(); - createExportTable(); - if (Config->Relocatable) - createSection(".reloc"); - assignAddresses(); - removeEmptySections(); - setSectionPermissions(); - createSymbolAndStringTable(); - - // We must do this before opening the output file, as it depends on being able - // to read the contents of the existing output file. - PreviousBuildId = loadExistingBuildId(Config->OutputFile); - openFile(Config->OutputFile); - if (Config->is64()) { - writeHeader(); - } else { - writeHeader(); - } - writeSections(); - sortExceptionTable(); - writeBuildId(); - - if (!Config->PDBPath.empty() && Config->Debug) { - - assert(BuildId); - createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId); - } - - writeMapFile(OutputSections); - - if (auto E = Buffer->commit()) - fatal("failed to write the output file: " + toString(std::move(E))); -} - -static StringRef getOutputSection(StringRef Name) { - StringRef S = Name.split('$').first; - - // Treat a later period as a separator for MinGW, for sections like - // ".ctors.01234". - S = S.substr(0, S.find('.', 1)); - - auto It = Config->Merge.find(S); - if (It == Config->Merge.end()) - return S; - return It->second; -} - -// Create output section objects and add them to OutputSections. -void Writer::createSections() { - // First, bin chunks by name. - std::map> Map; - for (Chunk *C : Symtab->getChunks()) { - auto *SC = dyn_cast(C); - if (SC && !SC->isLive()) { - if (Config->Verbose) - SC->printDiscardedMessage(); - continue; - } - Map[C->getSectionName()].push_back(C); - } - - // Then create an OutputSection for each section. - // '$' and all following characters in input section names are - // discarded when determining output section. So, .text$foo - // contributes to .text, for example. See PE/COFF spec 3.2. - SmallDenseMap Sections; - for (auto Pair : Map) { - StringRef Name = getOutputSection(Pair.first); - OutputSection *&Sec = Sections[Name]; - if (!Sec) { - Sec = make(Name); - OutputSections.push_back(Sec); - } - std::vector &Chunks = Pair.second; - for (Chunk *C : Chunks) { - Sec->addChunk(C); - Sec->addPermissions(C->getPermissions()); - } - } -} - -void Writer::createMiscChunks() { - OutputSection *RData = createSection(".rdata"); - - // Create thunks for locally-dllimported symbols. - if (!Symtab->LocalImportChunks.empty()) { - for (Chunk *C : Symtab->LocalImportChunks) - RData->addChunk(C); - } - - // Create Debug Information Chunks - if (Config->Debug) { - DebugDirectory = make(DebugRecords); - - // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We - // output a PDB no matter what, and this chunk provides the only means of - // allowing a debugger to match a PDB and an executable. So we need it even - // if we're ultimately not going to write CodeView data to the PDB. - auto *CVChunk = make(); - BuildId = CVChunk; - DebugRecords.push_back(CVChunk); - - RData->addChunk(DebugDirectory); - for (Chunk *C : DebugRecords) - RData->addChunk(C); - } - - createSEHTable(RData); -} - -// Create .idata section for the DLL-imported symbol table. -// The format of this section is inherently Windows-specific. -// IdataContents class abstracted away the details for us, -// so we just let it create chunks and add them to the section. -void Writer::createImportTables() { - if (ImportFile::Instances.empty()) - return; - - // Initialize DLLOrder so that import entries are ordered in - // the same order as in the command line. (That affects DLL - // initialization order, and this ordering is MSVC-compatible.) - for (ImportFile *File : ImportFile::Instances) { - if (!File->Live) - continue; - - std::string DLL = StringRef(File->DLLName).lower(); - if (Config->DLLOrder.count(DLL) == 0) - Config->DLLOrder[DLL] = Config->DLLOrder.size(); - } - - OutputSection *Text = createSection(".text"); - for (ImportFile *File : ImportFile::Instances) { - if (!File->Live) - continue; - - if (DefinedImportThunk *Thunk = File->ThunkSym) - Text->addChunk(Thunk->getChunk()); - - if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { - if (!File->ThunkSym) - fatal("cannot delay-load " + toString(File) + - " due to import of data: " + toString(*File->ImpSym)); - DelayIdata.add(File->ImpSym); - } else { - Idata.add(File->ImpSym); - } - } - - if (!Idata.empty()) { - OutputSection *Sec = createSection(".idata"); - for (Chunk *C : Idata.getChunks()) - Sec->addChunk(C); - } - - if (!DelayIdata.empty()) { - Defined *Helper = cast(Config->DelayLoadHelper); - DelayIdata.create(Helper); - OutputSection *Sec = createSection(".didat"); - for (Chunk *C : DelayIdata.getChunks()) - Sec->addChunk(C); - Sec = createSection(".data"); - for (Chunk *C : DelayIdata.getDataChunks()) - Sec->addChunk(C); - Sec = createSection(".text"); - for (Chunk *C : DelayIdata.getCodeChunks()) - Sec->addChunk(C); - } -} - -void Writer::createExportTable() { - if (Config->Exports.empty()) - return; - OutputSection *Sec = createSection(".edata"); - for (Chunk *C : Edata.Chunks) - Sec->addChunk(C); -} - -// The Windows loader doesn't seem to like empty sections, -// so we remove them if any. -void Writer::removeEmptySections() { - auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; - OutputSections.erase( - std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), - OutputSections.end()); - uint32_t Idx = 1; - for (OutputSection *Sec : OutputSections) - Sec->SectionIndex = Idx++; -} - -size_t Writer::addEntryToStringTable(StringRef Str) { - assert(Str.size() > COFF::NameSize); - size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field - Strtab.insert(Strtab.end(), Str.begin(), Str.end()); - Strtab.push_back('\0'); - return OffsetOfEntry; -} - -Optional Writer::createSymbol(Defined *Def) { - // Relative symbols are unrepresentable in a COFF symbol table. - if (isa(Def)) - return None; - - // Don't write dead symbols or symbols in codeview sections to the symbol - // table. - if (!Def->isLive()) - return None; - if (auto *D = dyn_cast(Def)) - if (D->getChunk()->isCodeView()) - return None; - - coff_symbol16 Sym; - StringRef Name = Def->getName(); - if (Name.size() > COFF::NameSize) { - Sym.Name.Offset.Zeroes = 0; - Sym.Name.Offset.Offset = addEntryToStringTable(Name); - } else { - memset(Sym.Name.ShortName, 0, COFF::NameSize); - memcpy(Sym.Name.ShortName, Name.data(), Name.size()); - } - - if (auto *D = dyn_cast(Def)) { - COFFSymbolRef Ref = D->getCOFFSymbol(); - Sym.Type = Ref.getType(); - Sym.StorageClass = Ref.getStorageClass(); - } else { - Sym.Type = IMAGE_SYM_TYPE_NULL; - Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; - } - Sym.NumberOfAuxSymbols = 0; - - switch (Def->kind()) { - case Symbol::DefinedAbsoluteKind: - Sym.Value = Def->getRVA(); - Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; - break; - default: { - uint64_t RVA = Def->getRVA(); - OutputSection *Sec = nullptr; - for (OutputSection *S : OutputSections) { - if (S->getRVA() > RVA) - break; - Sec = S; - } - Sym.Value = RVA - Sec->getRVA(); - Sym.SectionNumber = Sec->SectionIndex; - break; - } - } - return Sym; -} - -void Writer::createSymbolAndStringTable() { - // Name field in the section table is 8 byte long. Longer names need - // to be written to the string table. First, construct string table. - for (OutputSection *Sec : OutputSections) { - StringRef Name = Sec->getName(); - if (Name.size() <= COFF::NameSize) - continue; - // If a section isn't discardable (i.e. will be mapped at runtime), - // prefer a truncated section name over a long section name in - // the string table that is unavailable at runtime. This is different from - // what link.exe does, but finding ".eh_fram" instead of "/4" is useful - // to libunwind. - if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0) - continue; - Sec->setStringTableOff(addEntryToStringTable(Name)); - } - - if (Config->DebugDwarf) { - for (ObjFile *File : ObjFile::Instances) { - for (Symbol *B : File->getSymbols()) { - auto *D = dyn_cast_or_null(B); - if (!D || D->WrittenToSymtab) - continue; - D->WrittenToSymtab = true; - - if (Optional Sym = createSymbol(D)) - OutputSymtab.push_back(*Sym); - } - } - } - - if (OutputSymtab.empty() && Strtab.empty()) - return; - - OutputSection *LastSection = OutputSections.back(); - // We position the symbol table to be adjacent to the end of the last section. - uint64_t FileOff = LastSection->getFileOff() + - alignTo(LastSection->getRawSize(), SectorSize); - PointerToSymbolTable = FileOff; - FileOff += OutputSymtab.size() * sizeof(coff_symbol16); - FileOff += 4 + Strtab.size(); - FileSize = alignTo(FileOff, SectorSize); -} - -// Visits all sections to assign incremental, non-overlapping RVAs and -// file offsets. -void Writer::assignAddresses() { - SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + - sizeof(data_directory) * NumberfOfDataDirectory + - sizeof(coff_section) * OutputSections.size(); - SizeOfHeaders += - Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); - SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); - uint64_t RVA = 0x1000; // The first page is kept unmapped. - FileSize = SizeOfHeaders; - // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because - // the loader cannot handle holes. - std::stable_partition( - OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { - return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; - }); - for (OutputSection *Sec : OutputSections) { - if (Sec->getName() == ".reloc") - addBaserels(Sec); - Sec->setRVA(RVA); - Sec->setFileOffset(FileSize); - RVA += alignTo(Sec->getVirtualSize(), PageSize); - FileSize += alignTo(Sec->getRawSize(), SectorSize); - } - SizeOfImage = alignTo(RVA, PageSize); -} - -template void Writer::writeHeader() { - // Write DOS stub - uint8_t *Buf = Buffer->getBufferStart(); - auto *DOS = reinterpret_cast(Buf); - Buf += DOSStubSize; - DOS->Magic[0] = 'M'; - DOS->Magic[1] = 'Z'; - DOS->AddressOfRelocationTable = sizeof(dos_header); - DOS->AddressOfNewExeHeader = DOSStubSize; - - // Write PE magic - memcpy(Buf, PEMagic, sizeof(PEMagic)); - Buf += sizeof(PEMagic); - - // Write COFF header - auto *COFF = reinterpret_cast(Buf); - Buf += sizeof(*COFF); - COFF->Machine = Config->Machine; - COFF->NumberOfSections = OutputSections.size(); - COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; - if (Config->LargeAddressAware) - COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - if (!Config->is64()) - COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; - if (Config->DLL) - COFF->Characteristics |= IMAGE_FILE_DLL; - if (!Config->Relocatable) - COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; - COFF->SizeOfOptionalHeader = - sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; - - // Write PE header - auto *PE = reinterpret_cast(Buf); - Buf += sizeof(*PE); - PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; - - // If {Major,Minor}LinkerVersion is left at 0.0, then for some - // reason signing the resulting PE file with Authenticode produces a - // signature that fails to validate on Windows 7 (but is OK on 10). - // Set it to 14.0, which is what VS2015 outputs, and which avoids - // that problem. - PE->MajorLinkerVersion = 14; - PE->MinorLinkerVersion = 0; - - PE->ImageBase = Config->ImageBase; - PE->SectionAlignment = PageSize; - PE->FileAlignment = SectorSize; - PE->MajorImageVersion = Config->MajorImageVersion; - PE->MinorImageVersion = Config->MinorImageVersion; - PE->MajorOperatingSystemVersion = Config->MajorOSVersion; - PE->MinorOperatingSystemVersion = Config->MinorOSVersion; - PE->MajorSubsystemVersion = Config->MajorOSVersion; - PE->MinorSubsystemVersion = Config->MinorOSVersion; - PE->Subsystem = Config->Subsystem; - PE->SizeOfImage = SizeOfImage; - PE->SizeOfHeaders = SizeOfHeaders; - if (!Config->NoEntry) { - Defined *Entry = cast(Config->Entry); - PE->AddressOfEntryPoint = Entry->getRVA(); - // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT) - PE->AddressOfEntryPoint |= 1; - } - PE->SizeOfStackReserve = Config->StackReserve; - PE->SizeOfStackCommit = Config->StackCommit; - PE->SizeOfHeapReserve = Config->HeapReserve; - PE->SizeOfHeapCommit = Config->HeapCommit; - if (Config->AppContainer) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; - if (Config->DynamicBase) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; - if (Config->HighEntropyVA) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; - if (!Config->AllowBind) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; - if (Config->NxCompat) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; - if (!Config->AllowIsolation) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; - if (Config->Machine == I386 && !SEHTable && - !Symtab->findUnderscore("_load_config_used")) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; - if (Config->TerminalServerAware) - PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; - PE->NumberOfRvaAndSize = NumberfOfDataDirectory; - if (OutputSection *Text = findSection(".text")) { - PE->BaseOfCode = Text->getRVA(); - PE->SizeOfCode = Text->getRawSize(); - } - PE->SizeOfInitializedData = getSizeOfInitializedData(); - - // Write data directory - auto *Dir = reinterpret_cast(Buf); - Buf += sizeof(*Dir) * NumberfOfDataDirectory; - if (OutputSection *Sec = findSection(".edata")) { - Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); - } - if (!Idata.empty()) { - Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); - Dir[IMPORT_TABLE].Size = Idata.getDirSize(); - Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); - Dir[IAT].Size = Idata.getIATSize(); - } - if (OutputSection *Sec = findSection(".rsrc")) { - Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); - } - if (OutputSection *Sec = findSection(".pdata")) { - Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); - } - if (OutputSection *Sec = findSection(".reloc")) { - Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); - } - if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { - if (Defined *B = dyn_cast(Sym)) { - Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); - Dir[TLS_TABLE].Size = Config->is64() - ? sizeof(object::coff_tls_directory64) - : sizeof(object::coff_tls_directory32); - } - } - if (Config->Debug) { - Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); - Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); - } - if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { - if (auto *B = dyn_cast(Sym)) { - SectionChunk *SC = B->getChunk(); - assert(B->getRVA() >= SC->getRVA()); - uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); - if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize()) - fatal("_load_config_used is malformed"); - - ArrayRef SecContents = SC->getContents(); - uint32_t LoadConfigSize = - *reinterpret_cast(&SecContents[OffsetInChunk]); - if (OffsetInChunk + LoadConfigSize > SC->getSize()) - fatal("_load_config_used is too large"); - Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); - Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; - } - } - if (!DelayIdata.empty()) { - Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = - DelayIdata.getDirRVA(); - Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); - } - - // Write section table - for (OutputSection *Sec : OutputSections) { - Sec->writeHeaderTo(Buf); - Buf += sizeof(coff_section); - } - SectionTable = ArrayRef( - Buf - OutputSections.size() * sizeof(coff_section), Buf); - - if (OutputSymtab.empty() && Strtab.empty()) - return; - - COFF->PointerToSymbolTable = PointerToSymbolTable; - uint32_t NumberOfSymbols = OutputSymtab.size(); - COFF->NumberOfSymbols = NumberOfSymbols; - auto *SymbolTable = reinterpret_cast( - Buffer->getBufferStart() + COFF->PointerToSymbolTable); - for (size_t I = 0; I != NumberOfSymbols; ++I) - SymbolTable[I] = OutputSymtab[I]; - // Create the string table, it follows immediately after the symbol table. - // The first 4 bytes is length including itself. - Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); - write32le(Buf, Strtab.size() + 4); - if (!Strtab.empty()) - memcpy(Buf + 4, Strtab.data(), Strtab.size()); -} - -void Writer::openFile(StringRef Path) { - Buffer = CHECK( - FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), - "failed to open " + Path); -} - -void Writer::createSEHTable(OutputSection *RData) { - // Create SEH table. x86-only. - if (Config->Machine != I386) - return; - - std::set Handlers; - - for (ObjFile *File : ObjFile::Instances) { - if (!File->SEHCompat) - return; - for (uint32_t I : File->SXData) - if (Symbol *B = File->getSymbol(I)) - if (B->isLive()) - Handlers.insert(cast(B)); - } - - if (Handlers.empty()) - return; - - SEHTable = make(Handlers); - RData->addChunk(SEHTable); - - // Replace the absolute table symbol with a synthetic symbol pointing to the - // SEHTable chunk so that we can emit base relocations for it and resolve - // section relative relocations. - Symbol *T = Symtab->find("___safe_se_handler_table"); - Symbol *C = Symtab->find("___safe_se_handler_count"); - replaceSymbol(T, T->getName(), SEHTable); - cast(C)->setVA(SEHTable->getSize() / 4); -} - -// Handles /section options to allow users to overwrite -// section attributes. -void Writer::setSectionPermissions() { - for (auto &P : Config->Section) { - StringRef Name = P.first; - uint32_t Perm = P.second; - if (auto *Sec = findSection(Name)) - Sec->setPermissions(Perm); - } -} - -// Write section contents to a mmap'ed file. -void Writer::writeSections() { - // Record the section index that should be used when resolving a section - // relocation against an absolute symbol. - DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; - - uint8_t *Buf = Buffer->getBufferStart(); - for (OutputSection *Sec : OutputSections) { - uint8_t *SecBuf = Buf + Sec->getFileOff(); - // Fill gaps between functions in .text with INT3 instructions - // instead of leaving as NUL bytes (which can be interpreted as - // ADD instructions). - if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) - memset(SecBuf, 0xCC, Sec->getRawSize()); - for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), - [&](Chunk *C) { C->writeTo(SecBuf); }); - } -} - -void Writer::writeBuildId() { - // If we're not writing a build id (e.g. because /debug is not specified), - // then just return; - if (!Config->Debug) - return; - - assert(BuildId && "BuildId is not set!"); - - if (PreviousBuildId.hasValue()) { - *BuildId->BuildId = *PreviousBuildId; - BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - return; - } - - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); -} - -// Sort .pdata section contents according to PE/COFF spec 5.5. -void Writer::sortExceptionTable() { - OutputSection *Sec = findSection(".pdata"); - if (!Sec) - return; - // We assume .pdata contains function table entries only. - uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); - uint8_t *End = Begin + Sec->getVirtualSize(); - if (Config->Machine == AMD64) { - struct Entry { ulittle32_t Begin, End, Unwind; }; - sort(parallel::par, (Entry *)Begin, (Entry *)End, - [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); - return; - } - if (Config->Machine == ARMNT || Config->Machine == ARM64) { - struct Entry { ulittle32_t Begin, Unwind; }; - sort(parallel::par, (Entry *)Begin, (Entry *)End, - [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); - return; - } - errs() << "warning: don't know how to handle .pdata.\n"; -} - -OutputSection *Writer::findSection(StringRef Name) { - for (OutputSection *Sec : OutputSections) - if (Sec->getName() == Name) - return Sec; - return nullptr; -} - -uint32_t Writer::getSizeOfInitializedData() { - uint32_t Res = 0; - for (OutputSection *S : OutputSections) - if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) - Res += S->getRawSize(); - return Res; -} - -// Returns an existing section or create a new one if not found. -OutputSection *Writer::createSection(StringRef Name) { - if (auto *Sec = findSection(Name)) - return Sec; - const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; - const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; - const auto CODE = IMAGE_SCN_CNT_CODE; - const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; - const auto R = IMAGE_SCN_MEM_READ; - const auto W = IMAGE_SCN_MEM_WRITE; - const auto X = IMAGE_SCN_MEM_EXECUTE; - uint32_t Perms = StringSwitch(Name) - .Case(".bss", BSS | R | W) - .Case(".data", DATA | R | W) - .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R) - .Case(".reloc", DATA | DISCARDABLE | R) - .Case(".text", CODE | R | X) - .Default(0); - if (!Perms) - llvm_unreachable("unknown section name"); - auto Sec = make(Name); - Sec->addPermissions(Perms); - OutputSections.push_back(Sec); - return Sec; -} - -// Dest is .reloc section. Add contents to that section. -void Writer::addBaserels(OutputSection *Dest) { - std::vector V; - for (OutputSection *Sec : OutputSections) { - if (Sec == Dest) - continue; - // Collect all locations for base relocations. - for (Chunk *C : Sec->getChunks()) - C->getBaserels(&V); - // Add the addresses to .reloc section. - if (!V.empty()) - addBaserelBlocks(Dest, V); - V.clear(); - } -} - -// Add addresses to .reloc section. Note that addresses are grouped by page. -void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { - const uint32_t Mask = ~uint32_t(PageSize - 1); - uint32_t Page = V[0].RVA & Mask; - size_t I = 0, J = 1; - for (size_t E = V.size(); J < E; ++J) { - uint32_t P = V[J].RVA & Mask; - if (P == Page) - continue; - Dest->addChunk(make(Page, &V[I], &V[0] + J)); - I = J; - Page = P; - } - if (I == J) - return; - Dest->addChunk(make(Page, &V[I], &V[0] + J)); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Writer.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Writer.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/COFF/Writer.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/COFF/Writer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -//===- Writer.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_WRITER_H -#define LLD_COFF_WRITER_H - -#include "Chunks.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/COFF.h" -#include -#include - -namespace lld { -namespace coff { -static const int PageSize = 4096; - -void writeResult(); - -// OutputSection represents a section in an output file. It's a -// container of chunks. OutputSection and Chunk are 1:N relationship. -// Chunks cannot belong to more than one OutputSections. The writer -// creates multiple OutputSections and assign them unique, -// non-overlapping file offsets and RVAs. -class OutputSection { -public: - OutputSection(llvm::StringRef N) : Name(N), Header({}) {} - void setRVA(uint64_t); - void setFileOffset(uint64_t); - void addChunk(Chunk *C); - llvm::StringRef getName() { return Name; } - ArrayRef getChunks() { return Chunks; } - void addPermissions(uint32_t C); - void setPermissions(uint32_t C); - uint32_t getPermissions() { return Header.Characteristics & PermMask; } - uint32_t getCharacteristics() { return Header.Characteristics; } - uint64_t getRVA() { return Header.VirtualAddress; } - uint64_t getFileOff() { return Header.PointerToRawData; } - void writeHeaderTo(uint8_t *Buf); - - // Returns the size of this section in an executable memory image. - // This may be smaller than the raw size (the raw size is multiple - // of disk sector size, so there may be padding at end), or may be - // larger (if that's the case, the loader reserves spaces after end - // of raw data). - uint64_t getVirtualSize() { return Header.VirtualSize; } - - // Returns the size of the section in the output file. - uint64_t getRawSize() { return Header.SizeOfRawData; } - - // Set offset into the string table storing this section name. - // Used only when the name is longer than 8 bytes. - void setStringTableOff(uint32_t V) { StringTableOff = V; } - - // N.B. The section index is one based. - uint32_t SectionIndex = 0; - -private: - llvm::StringRef Name; - llvm::object::coff_section Header; - uint32_t StringTableOff = 0; - std::vector Chunks; -}; - -} -} - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Args.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Args.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Args.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Args.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -//===- Args.cpp -----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Args.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Option/ArgList.h" - -using namespace llvm; -using namespace lld; - -int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) { - int V = Default; - if (auto *Arg = Args.getLastArg(Key)) { - StringRef S = Arg->getValue(); - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); - } - return V; -} - -std::vector lld::args::getStrings(opt::InputArgList &Args, int Id) { - std::vector V; - for (auto *Arg : Args.filtered(Id)) - V.push_back(Arg->getValue()); - return V; -} - -uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id, - StringRef Key, uint64_t Default) { - for (auto *Arg : Args.filtered(Id)) { - std::pair KV = StringRef(Arg->getValue()).split('='); - if (KV.first == Key) { - uint64_t Result = Default; - if (!to_integer(KV.second, Result)) - error("invalid " + Key + ": " + KV.second); - return Result; - } - } - return Default; -} - -std::vector lld::args::getLines(MemoryBufferRef MB) { - SmallVector Arr; - MB.getBuffer().split(Arr, '\n'); - - std::vector Ret; - for (StringRef S : Arr) { - S = S.trim(); - if (!S.empty() && S[0] != '#') - Ret.push_back(S); - } - return Ret; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/CMakeLists.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/CMakeLists.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/CMakeLists.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -if(NOT LLD_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - -add_lld_library(lldCommon - Args.cpp - ErrorHandler.cpp - Memory.cpp - Reproduce.cpp - Strings.cpp - TargetOptionsCommandFlags.cpp - Threads.cpp - Version.cpp - - ADDITIONAL_HEADER_DIRS - ${LLD_INCLUDE_DIR}/lld/Common - - LINK_COMPONENTS - Codegen - Core - Demangle - MC - Option - Support - Target - - LINK_LIBS - ${LLVM_PTHREAD_LIB} - - DEPENDS - ${tablegen_deps} - ) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/ErrorHandler.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/ErrorHandler.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/ErrorHandler.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/ErrorHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -//===- ErrorHandler.cpp ---------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/ErrorHandler.h" - -#include "lld/Common/Threads.h" - -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/raw_ostream.h" -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#endif - -using namespace llvm; -using namespace lld; - -// The functions defined in this file can be called from multiple threads, -// but outs() or errs() are not thread-safe. We protect them using a mutex. -static std::mutex Mu; - -// Prints "\n" or does nothing, depending on Msg contents of -// the previous call of this function. -static void newline(raw_ostream *ErrorOS, const Twine &Msg) { - // True if the previous error message contained "\n". - // We want to separate multi-line error messages with a newline. - static bool Flag; - - if (Flag) - *ErrorOS << "\n"; - Flag = StringRef(Msg.str()).contains('\n'); -} - -ErrorHandler &lld::errorHandler() { - static ErrorHandler Handler; - return Handler; -} - -void lld::exitLld(int Val) { - // Delete the output buffer so that any tempory file is deleted. - errorHandler().OutputBuffer.reset(); - - // Dealloc/destroy ManagedStatic variables before calling - // _exit(). In a non-LTO build, this is a nop. In an LTO - // build allows us to get the output of -time-passes. - llvm_shutdown(); - - outs().flush(); - errs().flush(); - _exit(Val); -} - -void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << LogName << ": "; - if (ColorDiagnostics) { - ErrorOS->changeColor(C, true); - *ErrorOS << S; - ErrorOS->resetColor(); - } else { - *ErrorOS << S; - } -} - -void ErrorHandler::log(const Twine &Msg) { - if (Verbose) { - std::lock_guard Lock(Mu); - *ErrorOS << LogName << ": " << Msg << "\n"; - } -} - -void ErrorHandler::message(const Twine &Msg) { - std::lock_guard Lock(Mu); - outs() << Msg << "\n"; - outs().flush(); -} - -void ErrorHandler::warn(const Twine &Msg) { - if (FatalWarnings) { - error(Msg); - return; - } - - std::lock_guard Lock(Mu); - newline(ErrorOS, Msg); - print("warning: ", raw_ostream::MAGENTA); - *ErrorOS << Msg << "\n"; -} - -void ErrorHandler::error(const Twine &Msg) { - std::lock_guard Lock(Mu); - newline(ErrorOS, Msg); - - if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << Msg << "\n"; - } else if (ErrorCount == ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << ErrorLimitExceededMsg << "\n"; - if (ExitEarly) - exitLld(1); - } - - ++ErrorCount; -} - -void ErrorHandler::fatal(const Twine &Msg) { - error(Msg); - exitLld(1); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Memory.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Memory.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Memory.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Memory.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -//===- Memory.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Memory.h" - -using namespace llvm; -using namespace lld; - -BumpPtrAllocator lld::BAlloc; -StringSaver lld::Saver{BAlloc}; -std::vector lld::SpecificAllocBase::Instances; - -void lld::freeArena() { - for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances) - Alloc->reset(); - BAlloc.Reset(); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Reproduce.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Reproduce.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Reproduce.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Reproduce.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -//===- Reproduce.cpp - Utilities for creating reproducers -----------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Reproduce.h" -#include "llvm/Option/Arg.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -using namespace lld; -using namespace llvm; -using namespace llvm::sys; - -// Makes a given pathname an absolute path first, and then remove -// beginning /. For example, "../foo.o" is converted to "home/john/foo.o", -// assuming that the current directory is "/home/john/bar". -// Returned string is a forward slash separated path even on Windows to avoid -// a mess with backslash-as-escape and backslash-as-path-separator. -std::string lld::relativeToRoot(StringRef Path) { - SmallString<128> Abs = Path; - if (fs::make_absolute(Abs)) - return Path; - path::remove_dots(Abs, /*remove_dot_dot=*/true); - - // This is Windows specific. root_name() returns a drive letter - // (e.g. "c:") or a UNC name (//net). We want to keep it as part - // of the result. - SmallString<128> Res; - StringRef Root = path::root_name(Abs); - if (Root.endswith(":")) - Res = Root.drop_back(); - else if (Root.startswith("//")) - Res = Root.substr(2); - - path::append(Res, path::relative_path(Abs)); - return path::convert_to_slash(Res); -} - -// Quote a given string if it contains a space character. -std::string lld::quote(StringRef S) { - if (S.contains(' ')) - return ("\"" + S + "\"").str(); - return S; -} - -std::string lld::rewritePath(StringRef S) { - if (fs::exists(S)) - return relativeToRoot(S); - return S; -} - -std::string lld::toString(const opt::Arg &Arg) { - std::string K = Arg.getSpelling(); - if (Arg.getNumValues() == 0) - return K; - std::string V = quote(Arg.getValue()); - if (Arg.getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) - return K + V; - return K + " " + V; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Strings.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Strings.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Strings.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Strings.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Strings.h" -#include "llvm/Demangle/Demangle.h" - -using namespace llvm; -using namespace lld; - -// Returns the demangled C++ symbol name for Name. -Optional lld::demangleItanium(StringRef Name) { - // itaniumDemangle can be used to demangle strings other than symbol - // names which do not necessarily start with "_Z". Name can be - // either a C or C++ symbol. Don't call itaniumDemangle if the name - // does not look like a C++ symbol name to avoid getting unexpected - // result for a C symbol that happens to match a mangled type name. - if (!Name.startswith("_Z")) - return None; - - char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); - if (!Buf) - return None; - std::string S(Buf); - free(Buf); - return S; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/TargetOptionsCommandFlags.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/TargetOptionsCommandFlags.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/TargetOptionsCommandFlags.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/TargetOptionsCommandFlags.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file exists as a place for global variables defined in LLVM's -// CodeGen/CommandFlags.def. By putting the resulting object file in -// an archive and linking with it, the definitions will automatically be -// included when needed and skipped when already present. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/TargetOptionsCommandFlags.h" - -#include "llvm/CodeGen/CommandFlags.def" -#include "llvm/Target/TargetOptions.h" - -// Define an externally visible version of -// InitTargetOptionsFromCodeGenFlags, so that its functionality can be -// used without having to include llvm/CodeGen/CommandFlags.def, which -// would lead to multiple definitions of the command line flags. -llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { - return ::InitTargetOptionsFromCodeGenFlags(); -} - -llvm::Optional lld::GetCodeModelFromCMModel() { - return getCodeModel(); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Threads.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Threads.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Threads.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Threads.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -//===- Threads.cpp --------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Threads.h" - -bool lld::ThreadsEnabled = true; diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Version.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Version.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/Common/Version.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/Common/Version.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -//===- lib/Common/Version.cpp - LLD Version Number ---------------*- C++-=====// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines several version-related utility functions for LLD. -// -//===----------------------------------------------------------------------===// - -#include "lld/Common/Version.h" - -using namespace llvm; - -// Returns an SVN repository path, which is usually "trunk". -static std::string getRepositoryPath() { - StringRef S = LLD_REPOSITORY_STRING; - size_t Pos = S.find("lld/"); - if (Pos != StringRef::npos) - return S.substr(Pos + 4); - return S; -} - -// Returns an SVN repository name, e.g., " (trunk 284614)" -// or an empty string if no repository info is available. -static std::string getRepository() { - std::string Repo = getRepositoryPath(); - std::string Rev = LLD_REVISION_STRING; - - if (Repo.empty() && Rev.empty()) - return ""; - if (!Repo.empty() && !Rev.empty()) - return " (" + Repo + " " + Rev + ")"; - return " (" + Repo + Rev + ")"; -} - -// Returns a version string, e.g., "LLD 4.0 (lld/trunk 284614)". -std::string lld::getLLDVersion() { - return "LLD " + std::string(LLD_VERSION_STRING) + getRepository(); -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/AtomLLD.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/AtomLLD.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/AtomLLD.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/AtomLLD.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -ATOM-based lld -============== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -ATOM-based lld is a new set of modular code for creating linker tools. -Currently it supports Mach-O. - -* End-User Features: - - * Compatible with existing linker options - * Reads standard Object Files - * Writes standard Executable Files - * Remove clang's reliance on "the system linker" - * Uses the LLVM `"UIUC" BSD-Style license`__. - -* Applications: - - * Modular design - * Support cross linking - * Easy to add new CPU support - * Can be built as static tool or library - -* Design and Implementation: - - * Extensive unit tests - * Internal linker model can be dumped/read to textual format - * Additional linking features can be plugged in as "passes" - * OS specific and CPU specific code factored out - -Why a new linker? ------------------ - -The fact that clang relies on whatever linker tool you happen to have installed -means that clang has been very conservative adopting features which require a -recent linker. - -In the same way that the MC layer of LLVM has removed clang's reliance on the -system assembler tool, the lld project will remove clang's reliance on the -system linker tool. - - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - design - getting_started - development - open_projects - sphinx_intro - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`search` - -__ http://llvm.org/docs/DeveloperPolicy.html#license diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/CMakeLists.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/CMakeLists.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/CMakeLists.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -if (LLVM_ENABLE_SPHINX) - include(AddSphinxTarget) - if (SPHINX_FOUND) - if (${SPHINX_OUTPUT_HTML}) - add_sphinx_target(html lld) - endif() - endif() -endif() diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/conf.py rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/conf.py --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/conf.py 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/conf.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# -# lld documentation build configuration file. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os -from datetime import date - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'lld' -copyright = u'2011-%d, LLVM Project' % date.today().year - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short version. -version = '6' -# The full version, including alpha/beta/rc tags. -release = '6' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -today_fmt = '%Y-%m-%d' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -show_authors = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'friendly' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'llvm-theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ["."] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# If given, this must be the name of an image file (path relative to the -# configuration directory) that is the favicon of the docs. Modern browsers use -# this as icon for tabs, windows and bookmarks. It should be a Windows-style -# icon file (.ico), which is 16x16 or 32x32 pixels large. Default: None. The -# image file will be copied to the _static directory of the output HTML, but -# only if the file does not already exist there. -html_favicon = '_static/favicon.ico' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = {'index': 'indexsidebar.html'} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {'index': 'index.html'} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'llddoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('contents', 'lld.tex', u'lld Documentation', - u'LLVM project', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('contents', 'lld', u'lld Documentation', - [u'LLVM project'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('contents', 'lld', u'lld Documentation', - u'LLVM project', 'lld', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - - -# FIXME: Define intersphinx configration. -intersphinx_mapping = {} - - -# -- Options for extensions ---------------------------------------------------- - -# Enable this if you want TODOs to show up in the generated documentation. -todo_include_todos = True diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/design.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/design.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/design.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/design.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,421 +0,0 @@ -.. _design: - -Linker Design -============= - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -Introduction ------------- - -lld is a new generation of linker. It is not "section" based like traditional -linkers which mostly just interlace sections from multiple object files into the -output file. Instead, lld is based on "Atoms". Traditional section based -linking work well for simple linking, but their model makes advanced linking -features difficult to implement. Features like dead code stripping, reordering -functions for locality, and C++ coalescing require the linker to work at a finer -grain. - -An atom is an indivisible chunk of code or data. An atom has a set of -attributes, such as: name, scope, content-type, alignment, etc. An atom also -has a list of References. A Reference contains: a kind, an optional offset, an -optional addend, and an optional target atom. - -The Atom model allows the linker to use standard graph theory models for linking -data structures. Each atom is a node, and each Reference is an edge. The -feature of dead code stripping is implemented by following edges to mark all -live atoms, and then delete the non-live atoms. - - -Atom Model ----------- - -An atom is an indivisible chunk of code or data. Typically each user written -function or global variable is an atom. In addition, the compiler may emit -other atoms, such as for literal c-strings or floating point constants, or for -runtime data structures like dwarf unwind info or pointers to initializers. - -A simple "hello world" object file would be modeled like this: - -.. image:: hello.png - -There are three atoms: main, a proxy for printf, and an anonymous atom -containing the c-string literal "hello world". The Atom "main" has two -references. One is the call site for the call to printf, and the other is a -reference for the instruction that loads the address of the c-string literal. - -There are only four different types of atoms: - - * DefinedAtom - 95% of all atoms. This is a chunk of code or data - - * UndefinedAtom - This is a place holder in object files for a reference to some atom - outside the translation unit.During core linking it is usually replaced - by (coalesced into) another Atom. - - * SharedLibraryAtom - If a required symbol name turns out to be defined in a dynamic shared - library (and not some object file). A SharedLibraryAtom is the - placeholder Atom used to represent that fact. - - It is similar to an UndefinedAtom, but it also tracks information - about the associated shared library. - - * AbsoluteAtom - This is for embedded support where some stuff is implemented in ROM at - some fixed address. This atom has no content. It is just an address - that the Writer needs to fix up any references to point to. - - -File Model ----------- - -The linker views the input files as basically containers of Atoms and -References, and just a few attributes of their own. The linker works with three -kinds of files: object files, static libraries, and dynamic shared libraries. -Each kind of file has reader object which presents the file in the model -expected by the linker. - -Object File -~~~~~~~~~~~ - -An object file is just a container of atoms. When linking an object file, a -reader is instantiated which parses the object file and instantiates a set of -atoms representing all content in the .o file. The linker adds all those atoms -to a master graph. - -Static Library (Archive) -~~~~~~~~~~~~~~~~~~~~~~~~ - -This is the traditional unix static archive which is just a collection of object -files with a "table of contents". When linking with a static library, by default -nothing is added to the master graph of atoms. Instead, if after merging all -atoms from object files into a master graph, if any "undefined" atoms are left -remaining in the master graph, the linker reads the table of contents for each -static library to see if any have the needed definitions. If so, the set of -atoms from the specified object file in the static library is added to the -master graph of atoms. - -Dynamic Library (Shared Object) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Dynamic libraries are different than object files and static libraries in that -they don't directly add any content. Their purpose is to check at build time -that the remaining undefined references can be resolved at runtime, and provide -a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way -this is modeled in the linker is that a dynamic library contributes no atoms to -the initial graph of atoms. Instead, (like static libraries) if there are -"undefined" atoms in the master graph of all atoms, then each dynamic library is -checked to see if exports the required symbol. If so, a "shared library" atom is -instantiated by the by the reader which the linker uses to replace the -"undefined" atom. - -Linking Steps -------------- - -Through the use of abstract Atoms, the core of linking is architecture -independent and file format independent. All command line parsing is factored -out into a separate "options" abstraction which enables the linker to be driven -with different command line sets. - -The overall steps in linking are: - - #. Command line processing - - #. Parsing input files - - #. Resolving - - #. Passes/Optimizations - - #. Generate output file - -The Resolving and Passes steps are done purely on the master graph of atoms, so -they have no notion of file formats such as mach-o or ELF. - - -Input Files -~~~~~~~~~~~ - -Existing developer tools using different file formats for object files. -A goal of lld is to be file format independent. This is done -through a plug-in model for reading object files. The lld::Reader is the base -class for all object file readers. A Reader follows the factory method pattern. -A Reader instantiates an lld::File object (which is a graph of Atoms) from a -given object file (on disk or in-memory). - -Every Reader subclass defines its own "options" class (for instance the mach-o -Reader defines the class ReaderOptionsMachO). This options class is the -one-and-only way to control how the Reader operates when parsing an input file -into an Atom graph. For instance, you may want the Reader to only accept -certain architectures. The options class can be instantiated from command -line options, or it can be subclassed and the ivars programmatically set. - -Resolving -~~~~~~~~~ - -The resolving step takes all the atoms' graphs from each object file and -combines them into one master object graph. Unfortunately, it is not as simple -as appending the atom list from each file into one big list. There are many -cases where atoms need to be coalesced. That is, two or more atoms need to be -coalesced into one atom. This is necessary to support: C language "tentative -definitions", C++ weak symbols for templates and inlines defined in headers, -replacing undefined atoms with actual definition atoms, and for merging copies -of constants like c-strings and floating point constants. - -The linker support coalescing by-name and by-content. By-name is used for -tentative definitions and weak symbols. By-content is used for constant data -that can be merged. - -The resolving process maintains some global linking "state", including a "symbol -table" which is a map from llvm::StringRef to lld::Atom*. With these data -structures, the linker iterates all atoms in all input files. For each atom, it -checks if the atom is named and has a global or hidden scope. If so, the atom -is added to the symbol table map. If there already is a matching atom in that -table, that means the current atom needs to be coalesced with the found atom, or -it is a multiple definition error. - -When all initial input file atoms have been processed by the resolver, a scan is -made to see if there are any undefined atoms in the graph. If there are, the -linker scans all libraries (both static and dynamic) looking for definitions to -replace the undefined atoms. It is an error if any undefined atoms are left -remaining. - -Dead code stripping (if requested) is done at the end of resolving. The linker -does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main -executable) and follows each references and marks each Atom that it visits as -"live". When done, all atoms not marked "live" are removed. - -The result of the Resolving phase is the creation of an lld::File object. The -goal is that the lld::File model is **the** internal representation -throughout the linker. The file readers parse (mach-o, ELF, COFF) into an -lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce -their file kind, and every Pass only operates on an lld::File. This is not only -a simpler, consistent model, but it enables the state of the linker to be dumped -at any point in the link for testing purposes. - - -Passes -~~~~~~ - -The Passes step is an open ended set of routines that each get a change to -modify or enhance the current lld::File object. Some example Passes are: - - * stub (PLT) generation - - * GOT instantiation - - * order_file optimization - - * branch island generation - - * branch shim generation - - * Objective-C optimizations (Darwin specific) - - * TLV instantiation (Darwin specific) - - * DTrace probe processing (Darwin specific) - - * compact unwind encoding (Darwin specific) - - -Some of these passes are specific to Darwin's runtime environments. But many of -the passes are applicable to any OS (such as generating branch island for out of -range branch instructions). - -The general structure of a pass is to iterate through the atoms in the current -lld::File object, inspecting each atom and doing something. For instance, the -stub pass, looks for call sites to shared library atoms (e.g. call to printf). -It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for -each proxy atom needed, and these new atoms are added to the current lld::File -object. Next, all the noted call sites to shared library atoms have their -References altered to point to the stub atom instead of the shared library atom. - - -Generate Output File -~~~~~~~~~~~~~~~~~~~~ - -Once the passes are done, the output file writer is given current lld::File -object. The writer's job is to create the executable content file wrapper and -place the content of the atoms into it. - -lld uses a plug-in model for writing output files. All concrete writers (e.g. -ELF, mach-o, etc) are subclasses of the lld::Writer class. - -Unlike the Reader class which has just one method to instantiate an lld::File, -the Writer class has multiple methods. The crucial method is to generate the -output file, but there are also methods which allow the Writer to contribute -Atoms to the resolver and specify passes to run. - -An example of contributing -atoms is that if the Writer knows a main executable is being linked and such -an executable requires a specially named entry point (e.g. "_main"), the Writer -can add an UndefinedAtom with that special name to the resolver. This will -cause the resolver to issue an error if that symbol is not defined. - -Sometimes a Writer supports lazily created symbols, such as names for the start -of sections. To support this, the Writer can create a File object which vends -no initial atoms, but does lazily supply atoms by name as needed. - -Every Writer subclass defines its own "options" class (for instance the mach-o -Writer defines the class WriterOptionsMachO). This options class is the -one-and-only way to control how the Writer operates when producing an output -file from an Atom graph. For instance, you may want the Writer to optimize -the output for certain OS versions, or strip local symbols, etc. The options -class can be instantiated from command line options, or it can be subclassed -and the ivars programmatically set. - - -lld::File representations -------------------------- - -Just as LLVM has three representations of its IR model, lld has two -representations of its File/Atom/Reference model: - - * In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File). - - * textual (in YAML) - - -Textual representations in YAML -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In designing a textual format we want something easy for humans to read and easy -for the linker to parse. Since an atom has lots of attributes most of which are -usually just the default, we should define default values for every attribute so -that those can be omitted from the text representation. Here is the atoms for a -simple hello world program expressed in YAML:: - - target-triple: x86_64-apple-darwin11 - - atoms: - - name: _main - scope: global - type: code - content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00, - 00, 00, 31, c0, 5d, c3 ] - fixups: - - offset: 07 - kind: pcrel32 - target: 2 - - offset: 0E - kind: call32 - target: _fprintf - - - type: c-string - content: [ 73, 5A, 00 ] - - ... - -The biggest use for the textual format will be writing test cases. Writing test -cases in C is problematic because the compiler may vary its output over time for -its own optimization reasons which my inadvertently disable or break the linker -feature trying to be tested. By writing test cases in the linkers own textual -format, we can exactly specify every attribute of every atom and thus target -specific linker logic. - -The textual/YAML format follows the ReaderWriter patterns used in lld. The lld -library comes with the classes: ReaderYAML and WriterYAML. - - -Testing -------- - -The lld project contains a test suite which is being built up as new code is -added to lld. All new lld functionality should have a tests added to the test -suite. The test suite is `lit `_ driven. Each -test is a text file with comments telling lit how to run the test and check the -result To facilitate testing, the lld project builds a tool called lld-core. -This tool reads a YAML file (default from stdin), parses it into one or more -lld::File objects in memory and then feeds those lld::File objects to the -resolver phase. - - -Resolver testing -~~~~~~~~~~~~~~~~ - -Basic testing is the "core linking" or resolving phase. That is where the -linker merges object files. All test cases are written in YAML. One feature of -YAML is that it allows multiple "documents" to be encoding in one YAML stream. -That means one text file can appear to the linker as multiple .o files - the -normal case for the linker. - -Here is a simple example of a core linking test case. It checks that an -undefined atom from one file will be replaced by a definition from another -file:: - - # RUN: lld-core %s | FileCheck %s - - # - # Test that undefined atoms are replaced with defined atoms. - # - - --- - atoms: - - name: foo - definition: undefined - --- - atoms: - - name: foo - scope: global - type: code - ... - - # CHECK: name: foo - # CHECK: scope: global - # CHECK: type: code - # CHECK-NOT: name: foo - # CHECK: ... - - -Passes testing -~~~~~~~~~~~~~~ - -Since Passes just operate on an lld::File object, the lld-core tool has the -option to run a particular pass (after resolving). Thus, you can write a YAML -test case with carefully crafted input to exercise areas of a Pass and the check -the resulting lld::File object as represented in YAML. - - -Design Issues -------------- - -There are a number of open issues in the design of lld. The plan is to wait and -make these design decisions when we need to. - - -Debug Info -~~~~~~~~~~ - -Currently, the lld model says nothing about debug info. But the most popular -debug format is DWARF and there is some impedance mismatch with the lld model -and DWARF. In lld there are just Atoms and only Atoms that need to be in a -special section at runtime have an associated section. Also, Atoms do not have -addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go -into specially named sections and the DWARF references function code by address. - -CPU and OS specific functionality -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Currently, lld has an abstract "Platform" that deals with any CPU or OS specific -differences in linking. We just keep adding virtual methods to the base -Platform class as we find linking areas that might need customization. At some -point we'll need to structure this better. - - -File Attributes -~~~~~~~~~~~~~~~ - -Currently, lld::File just has a path and a way to iterate its atoms. We will -need to add more attributes on a File. For example, some equivalent to the -target triple. There is also a number of cached or computed attributes that -could make various Passes more efficient. For instance, on Darwin there are a -number of Objective-C optimizations that can be done by a Pass. But it would -improve the plain C case if the Objective-C optimization Pass did not have to -scan all atoms looking for any Objective-C data structures. This could be done -if the lld::File object had an attribute that said if the file had any -Objective-C data in it. The Resolving phase would then be required to "merge" -that attribute as object files are added. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/development.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/development.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/development.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/development.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -.. _development: - -Development -=========== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -lld is developed as part of the `LLVM `_ project. - -Creating a Reader ------------------ - -See the :ref:`Creating a Reader ` guide. - - -Modifying the Driver --------------------- - -See :doc:`Driver`. - - -Debugging ---------- - -You can run lld with ``-mllvm -debug`` command line options to enable debugging -printouts. If you want to enable debug information for some specific pass, you -can run it with ``-mllvm '-debug-only='``, where pass is a name used in -the ``DEBUG_WITH_TYPE()`` macro. - - - -Documentation -------------- - -The project documentation is written in reStructuredText and generated using the -`Sphinx `_ documentation generator. For more -information on writing documentation for the project, see the -:ref:`sphinx_intro`. - -.. toctree:: - :hidden: - - Readers - Driver diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/Driver.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/Driver.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/Driver.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/Driver.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -====== -Driver -====== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -.. contents:: - :local: - -Introduction -============ - -This document describes the lld driver. The purpose of this document is to -describe both the motivation and design goals for the driver, as well as details -of the internal implementation. - -Overview -======== - -The lld driver is designed to support a number of different command line -interfaces. The main interfaces we plan to support are binutils' ld, Apple's -ld, and Microsoft's link.exe. - -Flavors -------- - -Each of these different interfaces is referred to as a flavor. There is also an -extra flavor "core" which is used to exercise the core functionality of the -linker it the test suite. - -* gnu -* darwin -* link -* core - -Selecting a Flavor -^^^^^^^^^^^^^^^^^^ - -There are two different ways to tell lld which flavor to be. They are checked in -order, so the second overrides the first. The first is to symlink :program:`lld` -as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify -it as the first command line argument using ``-flavor``:: - - $ lld -flavor gnu - -There is a shortcut for ``-flavor core`` as ``-core``. - - -Adding an Option to an existing Flavor -====================================== - -#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`. - -#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method - for the option. - -#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file: - `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter - for corresponding to the option. - -#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option. - - -Adding a Flavor -=============== - -#. Add an entry for the flavor in :file:`include/lld/Common/Driver.h` to - :cpp:class:`lld::UniversalDriver::Flavor`. - -#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to - :cpp:func:`lld::Driver::strToFlavor` and - :cpp:func:`lld::UniversalDriver::link`. - This allows the flavor to be selected via symlink and `-flavor`. - -#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that - describes the options. If the options are a superset of another driver, that - driver's td file can simply be included. The :file:`{flavor}Options.td` file - must also be added to :file:`lib/Driver/CMakeLists.txt`. - -#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver` - in :file:`lib/Driver/{flavor}Driver.cpp`. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/getting_started.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/getting_started.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/getting_started.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/getting_started.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,106 +0,0 @@ -.. _getting_started: - -Getting Started: Building and Running lld -========================================= - -This page gives you the shortest path to checking out and building lld. If you -run into problems, please file bugs in the `LLVM Bugzilla`__ - -__ http://llvm.org/bugs/ - -Building lld ------------- - -On Unix-like Systems -~~~~~~~~~~~~~~~~~~~~ - -1. Get the required tools. - - * `CMake 2.8`_\+. - * make (or any build system CMake supports). - * `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required). - - * If using Clang, you will also need `libc++`_. - * `Python 2.4`_\+ (not 3.x) for running tests. - -.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html -.. _Clang 3.1: http://clang.llvm.org/ -.. _libc++: http://libcxx.llvm.org/ -.. _Python 2.4: http://python.org/download/ - -2. Check out LLVM:: - - $ cd path/to/llvm-project - $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm - -3. Check out lld:: - - $ cd llvm/tools - $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld - - * lld can also be checked out to ``path/to/llvm-project`` and built as an external - project. - -4. Build LLVM and lld:: - - $ cd path/to/llvm-build/llvm (out of source build required) - $ cmake -G "Unix Makefiles" path/to/llvm-project/llvm - $ make - - * If you want to build with clang and it is not the default compiler or - it is installed in an alternate location, you'll need to tell the cmake tool - the location of the C and C++ compiler via CMAKE_C_COMPILER and - CMAKE_CXX_COMPILER. For example:: - - $ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ... - -5. Test:: - - $ make check-lld - -Using Visual Studio -~~~~~~~~~~~~~~~~~~~ - -#. Get the required tools. - - * `CMake 2.8`_\+. - * `Visual Studio 12 (2013) or later`_ (required for C++11 support) - * `Python 2.4`_\+ (not 3.x) for running tests. - -.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html -.. _Visual Studio 12 (2013) or later: http://www.microsoft.com/visualstudio/11/en-us -.. _Python 2.4: http://python.org/download/ - -#. Check out LLVM:: - - $ cd path/to/llvm-project - $ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm - -#. Check out lld:: - - $ cd llvm/tools - $ svn co http://llvm.org/svn/llvm-project/lld/trunk lld - - * lld can also be checked out to ``path/to/llvm-project`` and built as an external - project. - -#. Generate Visual Studio project files:: - - $ cd path/to/llvm-build/llvm (out of source build required) - $ cmake -G "Visual Studio 11" path/to/llvm-project/llvm - -#. Build - - * Open LLVM.sln in Visual Studio. - * Build the ``ALL_BUILD`` target. - -#. Test - - * Build the ``lld-test`` target. - -More Information -~~~~~~~~~~~~~~~~ - -For more information on using CMake see the `LLVM CMake guide`_. - -.. _LLVM CMake guide: http://llvm.org/docs/CMake.html Binary files /tmp/tmp_XJtJO/S9yKL18OTF/rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/hello.png and /tmp/tmp_XJtJO/so6ylqf6Ij/rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/hello.png differ diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/index.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/index.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/index.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/index.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,178 +0,0 @@ -LLD - The LLVM Linker -===================== - -LLD is a linker from the LLVM project. That is a drop-in replacement -for system linkers and runs much faster than them. It also provides -features that are useful for toolchain developers. - -The linker supports ELF (Unix), PE/COFF (Windows), Mach-O (macOS) and -WebAssembly in descending order of completeness. Internally, LLD consists of -several different linkers. The ELF port is the one that will be described in -this document. The PE/COFF port is almost complete except the lack of the -Windows debug info (PDB) support. The WebAssembly port is still a work in -progress (See :doc:`WebAssembly`). The Mach-O port is built based on a -different architecture than the others. For the details about Mach-O, please -read :doc:`AtomLLD`. - -Features --------- - -- LLD is a drop-in replacement for the GNU linkers. That accepts the - same command line arguments and linker scripts as GNU. - - We are currently working closely with the FreeBSD project to make - LLD default system linker in future versions of the operating - system, so we are serious about addressing compatibility issues. As - of February 2017, LLD is able to link the entire FreeBSD/amd64 base - system including the kernel. With a few work-in-progress patches it - can link approximately 95% of the ports collection on AMD64. For the - details, see `FreeBSD quarterly status report - `_. - -- LLD is very fast. When you link a large program on a multicore - machine, you can expect that LLD runs more than twice as fast as GNU - gold linker. Your milage may vary, though. - -- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64, - ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU. - Among these, x86-64 is the most well-supported target and have - reached production quality. AArch64 and MIPS seem decent too. x86 - should be OK but not well tested yet. ARM support is being developed - actively. - -- It is always a cross-linker, meaning that it always supports all the - above targets however it was built. In fact, we don't provide a - build-time option to enable/disable each target. This should make it - easy to use our linker as part of a cross-compile toolchain. - -- You can embed LLD to your program to eliminate dependency to - external linkers. All you have to do is to construct object files - and command line arguments just like you would do to invoke an - external linker and then call the linker's main function, - ``lld::elf::link``, from your code. - -- It is small. We are using LLVM libObject library to read from object - files, so it is not completely a fair comparison, but as of February - 2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold - consists of 198k lines of C++ code. - -- Link-time optimization (LTO) is supported by default. Essentially, - all you have to do to do LTO is to pass the ``-flto`` option to clang. - Then clang creates object files not in the native object file format - but in LLVM bitcode format. LLD reads bitcode object files, compile - them using LLVM and emit an output file. Because in this way LLD can - see the entire program, it can do the whole program optimization. - -- Some very old features for ancient Unix systems (pre-90s or even - before that) have been removed. Some default settings have been - tuned for the 21st century. For example, the stack is marked as - non-executable by default to tighten security. - -Performance ------------ - -This is a link time comparison on a 2-socket 20-core 40-thread Xeon -E5-2680 2.80 GHz machine with an SSD drive. We ran gold and lld with -or without multi-threading support. To disable multi-threading, we -added ``-no-threads`` to the command lines. - -============ =========== ============ ==================== ================== =============== ============= -Program Output size GNU ld GNU gold w/o threads GNU gold w/threads lld w/o threads lld w/threads -ffmpeg dbg 92 MiB 1.72s 1.16s 1.01s 0.60s 0.35s -mysqld dbg 154 MiB 8.50s 2.96s 2.68s 1.06s 0.68s -clang dbg 1.67 GiB 104.03s 34.18s 23.49s 14.82s 5.28s -chromium dbg 1.14 GiB 209.05s [1]_ 64.70s 60.82s 27.60s 16.70s -============ =========== ============ ==================== ================== =============== ============= - -As you can see, lld is significantly faster than GNU linkers. -Note that this is just a benchmark result of our environment. -Depending on number of available cores, available amount of memory or -disk latency/throughput, your results may vary. - -.. [1] Since GNU ld doesn't support the ``-icf=all`` and - ``-gdb-index`` options, we removed them from the command line - for GNU ld. GNU ld would have been slower than this if it had - these options. - -Build ------ - -If you have already checked out LLVM using SVN, you can check out LLD -under ``tools`` directory just like you probably did for clang. For the -details, see `Getting Started with the LLVM System -`_. - -If you haven't checkout out LLVM, the easiest way to build LLD is to -checkout the entire LLVM projects/sub-projects from a git mirror and -build that tree. You need `cmake` and of course a C++ compiler. - -.. code-block:: console - - $ git clone https://github.com/llvm-project/llvm-project-20170507 llvm-project - $ mkdir build - $ cd build - $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=lld -DCMAKE_INSTALL_PREFIX=/usr/local ../llvm-project/llvm - $ make install - -Using LLD ---------- - -LLD is installed as ``ld.lld``. On Unix, linkers are invoked by -compiler drivers, so you are not expected to use that command -directly. There are a few ways to tell compiler drivers to use ld.lld -instead of the default linker. - -The easiest way to do that is to overwrite the default linker. After -installing LLD to somewhere on your disk, you can create a symbolic -link by doing ``ln -s /path/to/ld.lld /usr/bin/ld`` so that -``/usr/bin/ld`` is resolved to LLD. - -If you don't want to change the system setting, you can use clang's -``-fuse-ld`` option. In this way, you want to set ``-fuse-ld=lld`` to -LDFLAGS when building your programs. - -LLD leaves its name and version number to a ``.comment`` section in an -output. If you are in doubt whether you are successfully using LLD or -not, run ``readelf --string-dump .comment `` and examine the -output. If the string "Linker: LLD" is included in the output, you are -using LLD. - -History -------- - -Here is a brief project history of the ELF and COFF ports. - -- May 2015: We decided to rewrite the COFF linker and did that. - Noticed that the new linker is much faster than the MSVC linker. - -- July 2015: The new ELF port was developed based on the COFF linker - architecture. - -- September 2015: The first patches to support MIPS and AArch64 landed. - -- October 2015: Succeeded to self-host the ELF port. We have noticed - that the linker was faster than the GNU linkers, but we weren't sure - at the time if we would be able to keep the gap as we would add more - features to the linker. - -- July 2016: Started working on improving the linker script support. - -- December 2016: Succeeded to build the entire FreeBSD base system - including the kernel. We had widen the performance gap against the - GNU linkers. - -Internals ---------- - -For the internals of the linker, please read :doc:`NewLLD`. It is a bit -outdated but the fundamental concepts remain valid. We'll update the -document soon. - -.. toctree:: - :maxdepth: 1 - - NewLLD - AtomLLD - WebAssembly - windows_support - ReleaseNotes diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/layout.html rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/layout.html --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/layout.html 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/layout.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -{# - sphinxdoc/layout.html - ~~~~~~~~~~~~~~~~~~~~~ - - Sphinx layout template for the sphinxdoc theme. - - :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{% extends "basic/layout.html" %} - -{% block relbar1 %} - -{{ super() }} -{% endblock %} - -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} Binary files /tmp/tmp_XJtJO/S9yKL18OTF/rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/contents.png and /tmp/tmp_XJtJO/so6ylqf6Ij/rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/contents.png differ diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/llvm.css rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/llvm.css --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/llvm.css 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/llvm.css 1970-01-01 00:00:00.000000000 +0000 @@ -1,345 +0,0 @@ -/* - * sphinxdoc.css_t - * ~~~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- sphinxdoc theme. Originally created by - * Armin Ronacher for Werkzeug. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 14px; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -div.logo { - background-color: white; - text-align: left; - padding: 10px 10px 15px 15px; -} - -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.related { - font-size: 1em; -} - -div.related ul { - background-image: url(navigation.png); - height: 2em; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; -} - -div.related ul li { - margin: 0; - padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; -} - -div.related ul li a:hover { - color: #3CA8E7; -} - -div.sphinxsidebarwrapper { - padding: 0; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - font-size: 1em; - text-align: left; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4 { - margin: 1em 0 0.5em 0; - font-size: 1em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar h3 a { - color: white; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - margin-left: 20px; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -/* -- body styles ----------------------------------------------------------- */ - -p { - margin: 0.8em 0 0.5em 0; -} - -a { - color: #CA7900; - text-decoration: none; -} - -a:hover { - color: #2491CF; -} - -div.body a { - text-decoration: underline; -} - -h1 { - margin: 0; - padding: 0.7em 0 0.3em 0; - font-size: 1.5em; - color: #11557C; -} - -h2 { - margin: 1.3em 0 0.2em 0; - font-size: 1.35em; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.2em; -} - -div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { - display: inline; -} - -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} - -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; -} - -tt.descname, tt.descclassname, tt.xref { - border: 0; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -a tt { - border: 0; - color: #CA7900; -} - -a tt:hover { - color: #2491CF; -} - -pre { - font-family: 'Consolas', 'Deja Vu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.015em; - line-height: 120%; - padding: 0.5em; - border: 1px solid #ccc; - background-color: #f8f8f8; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -td.linenos pre { - padding: 0.5em 0; -} - -div.quotebar { - background-color: #f8f8f8; - max-width: 250px; - float: right; - padding: 2px 7px; - border: 1px solid #ccc; -} - -div.topic { - background-color: #f8f8f8; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 1em 0; - border: 1px solid #86989B; - background-color: #f7f7f7; - padding: 0; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border-bottom: 1px solid #86989B; - font-weight: bold; - background-color: #AFC1C4; -} - -div.warning { - border: 1px solid #940000; -} - -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; -} - -.viewcode-back { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} Binary files /tmp/tmp_XJtJO/S9yKL18OTF/rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/logo.png and /tmp/tmp_XJtJO/so6ylqf6Ij/rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/logo.png differ Binary files /tmp/tmp_XJtJO/S9yKL18OTF/rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/navigation.png and /tmp/tmp_XJtJO/so6ylqf6Ij/rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/static/navigation.png differ diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/theme.conf rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/theme.conf --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/llvm-theme/theme.conf 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/llvm-theme/theme.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -[theme] -inherit = basic -stylesheet = llvm.css -pygments_style = friendly diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/make.bat rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/make.bat --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/make.bat 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/make.bat 1970-01-01 00:00:00.000000000 +0000 @@ -1,190 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/NewLLD.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/NewLLD.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/NewLLD.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/NewLLD.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,309 +0,0 @@ -The ELF, COFF and Wasm Linkers -============================== - -The ELF Linker as a Library ---------------------------- - -You can embed LLD to your program by linking against it and calling the linker's -entry point function lld::elf::link. - -The current policy is that it is your reponsibility to give trustworthy object -files. The function is guaranteed to return as long as you do not pass corrupted -or malicious object files. A corrupted file could cause a fatal error or SEGV. -That being said, you don't need to worry too much about it if you create object -files in the usual way and give them to the linker. It is naturally expected to -work, or otherwise it's a linker's bug. - -Design -====== - -We will describe the design of the linkers in the rest of the document. - -Key Concepts ------------- - -Linkers are fairly large pieces of software. -There are many design choices you have to make to create a complete linker. - -This is a list of design choices we've made for ELF and COFF LLD. -We believe that these high-level design choices achieved a right balance -between speed, simplicity and extensibility. - -* Implement as native linkers - - We implemented the linkers as native linkers for each file format. - - The linkers share the same design but share very little code. - Sharing code makes sense if the benefit is worth its cost. - In our case, the object formats are different enough that we thought the layer - to abstract the differences wouldn't be worth its complexity and run-time - cost. Elimination of the abstract layer has greatly simplified the - implementation. - -* Speed by design - - One of the most important things in archiving high performance is to - do less rather than do it efficiently. - Therefore, the high-level design matters more than local optimizations. - Since we are trying to create a high-performance linker, - it is very important to keep the design as efficient as possible. - - Broadly speaking, we do not do anything until we have to do it. - For example, we do not read section contents or relocations - until we need them to continue linking. - When we need to do some costly operation (such as looking up - a hash table for each symbol), we do it only once. - We obtain a handler (which is typically just a pointer to actual data) - on the first operation and use it throughout the process. - -* Efficient archive file handling - - LLD's handling of archive files (the files with ".a" file extension) is - different from the traditional Unix linkers and similar to Windows linkers. - We'll describe how the traditional Unix linker handles archive files, what the - problem is, and how LLD approached the problem. - - The traditional Unix linker maintains a set of undefined symbols during - linking. The linker visits each file in the order as they appeared in the - command line until the set becomes empty. What the linker would do depends on - file type. - - - If the linker visits an object file, the linker links object files to the - result, and undefined symbols in the object file are added to the set. - - - If the linker visits an archive file, it checks for the archive file's - symbol table and extracts all object files that have definitions for any - symbols in the set. - - This algorithm sometimes leads to a counter-intuitive behavior. If you give - archive files before object files, nothing will happen because when the linker - visits archives, there is no undefined symbols in the set. As a result, no - files are extracted from the first archive file, and the link is done at that - point because the set is empty after it visits one file. - - You can fix the problem by reordering the files, - but that cannot fix the issue of mutually-dependent archive files. - - Linking mutually-dependent archive files is tricky. You may specify the same - archive file multiple times to let the linker visit it more than once. Or, - you may use the special command line options, `--start-group` and - `--end-group`, to let the linker loop over the files between the options until - no new symbols are added to the set. - - Visiting the same archive files multiple makes the linker slower. - - Here is how LLD approaches the problem. Instead of memorizing only undefined - symbols, we program LLD so that it memorizes all symbols. When it sees an - undefined symbol that can be resolved by extracting an object file from an - archive file it previously visited, it immediately extracts the file and link - it. It is doable because LLD does not forget symbols it have seen in archive - files. - - We believe that the LLD's way is efficient and easy to justify. - - The semantics of LLD's archive handling is different from the traditional - Unix's. You can observe it if you carefully craft archive files to exploit - it. However, in reality, we don't know any program that cannot link with our - algorithm so far, so it's not going to cause trouble. - -Numbers You Want to Know ------------------------- - -To give you intuition about what kinds of data the linker is mainly working on, -I'll give you the list of objects and their numbers LLD has to read and process -in order to link a very large executable. In order to link Chrome with debug -info, which is roughly 2 GB in output size, LLD reads - -- 17,000 files, -- 1,800,000 sections, -- 6,300,000 symbols, and -- 13,000,000 relocations. - -LLD produces the 2 GB executable in 15 seconds. - -These numbers vary depending on your program, but in general, -you have a lot of relocations and symbols for each file. -If your program is written in C++, symbol names are likely to be -pretty long because of name mangling. - -It is important to not waste time on relocations and symbols. - -In the above case, the total amount of symbol strings is 450 MB, -and inserting all of them to a hash table takes 1.5 seconds. -Therefore, if you causally add a hash table lookup for each symbol, -it would slow down the linker by 10%. So, don't do that. - -On the other hand, you don't have to pursue efficiency -when handling files. - -Important Data Structures -------------------------- - -We will describe the key data structures in LLD in this section. The linker can -be understood as the interactions between them. Once you understand their -functions, the code of the linker should look obvious to you. - -* Symbol - - This class represents a symbol. - They are created for symbols in object files or archive files. - The linker creates linker-defined symbols as well. - - There are basically three types of Symbols: Defined, Undefined, or Lazy. - - - Defined symbols are for all symbols that are considered as "resolved", - including real defined symbols, COMDAT symbols, common symbols, - absolute symbols, linker-created symbols, etc. - - Undefined symbols represent undefined symbols, which need to be replaced by - Defined symbols by the resolver until the link is complete. - - Lazy symbols represent symbols we found in archive file headers - which can turn into Defined if we read archieve members. - - There's only one Symbol instance for each unique symbol name. This uniqueness - is guaranteed by the symbol table. As the resolver reads symbols from input - files, it replaces an existing Symbol with the "best" Symbol for its symbol - name using the placement new. - - The above mechanism allows you to use pointers to Symbols as a very cheap way - to access name resolution results. Assume for example that you have a pointer - to an undefined symbol before name resolution. If the symbol is resolved to a - defined symbol by the resolver, the pointer will "automatically" point to the - defined symbol, because the undefined symbol the pointer pointed to will have - been replaced by the defined symbol in-place. - -* SymbolTable - - SymbolTable is basically a hash table from strings to Symbols - with logic to resolve symbol conflicts. It resolves conflicts by symbol type. - - - If we add Defined and Undefined symbols, the symbol table will keep the - former. - - If we add Defined and Lazy symbols, it will keep the former. - - If we add Lazy and Undefined, it will keep the former, - but it will also trigger the Lazy symbol to load the archive member - to actually resolve the symbol. - -* Chunk (COFF specific) - - Chunk represents a chunk of data that will occupy space in an output. - Each regular section becomes a chunk. - Chunks created for common or BSS symbols are not backed by sections. - The linker may create chunks to append additional data to an output as well. - - Chunks know about their size, how to copy their data to mmap'ed outputs, - and how to apply relocations to them. - Specifically, section-based chunks know how to read relocation tables - and how to apply them. - -* InputSection (ELF specific) - - Since we have less synthesized data for ELF, we don't abstract slices of - input files as Chunks for ELF. Instead, we directly use the input section - as an internal data type. - - InputSection knows about their size and how to copy themselves to - mmap'ed outputs, just like COFF Chunks. - -* OutputSection - - OutputSection is a container of InputSections (ELF) or Chunks (COFF). - An InputSection or Chunk belongs to at most one OutputSection. - -There are mainly three actors in this linker. - -* InputFile - - InputFile is a superclass of file readers. - We have a different subclass for each input file type, - such as regular object file, archive file, etc. - They are responsible for creating and owning Symbols and InputSections/Chunks. - -* Writer - - The writer is responsible for writing file headers and InputSections/Chunks to - a file. It creates OutputSections, put all InputSections/Chunks into them, - assign unique, non-overlapping addresses and file offsets to them, and then - write them down to a file. - -* Driver - - The linking process is driven by the driver. The driver: - - - processes command line options, - - creates a symbol table, - - creates an InputFile for each input file and puts all symbols within into - the symbol table, - - checks if there's no remaining undefined symbols, - - creates a writer, - - and passes the symbol table to the writer to write the result to a file. - -Link-Time Optimization ----------------------- - -LTO is implemented by handling LLVM bitcode files as object files. -The linker resolves symbols in bitcode files normally. If all symbols -are successfully resolved, it then runs LLVM passes -with all bitcode files to convert them to one big regular ELF/COFF file. -Finally, the linker replaces bitcode symbols with ELF/COFF symbols, -so that they are linked as if they were in the native format from the beginning. - -The details are described in this document. -http://llvm.org/docs/LinkTimeOptimization.html - -Glossary --------- - -* RVA (COFF) - - Short for Relative Virtual Address. - - Windows executables or DLLs are not position-independent; they are - linked against a fixed address called an image base. RVAs are - offsets from an image base. - - Default image bases are 0x140000000 for executables and 0x18000000 - for DLLs. For example, when we are creating an executable, we assume - that the executable will be loaded at address 0x140000000 by the - loader, so we apply relocations accordingly. Result texts and data - will contain raw absolute addresses. - -* VA - - Short for Virtual Address. For COFF, it is equivalent to RVA + image base. - -* Base relocations (COFF) - - Relocation information for the loader. If the loader decides to map - an executable or a DLL to a different address than their image - bases, it fixes up binaries using information contained in the base - relocation table. A base relocation table consists of a list of - locations containing addresses. The loader adds a difference between - RVA and actual load address to all locations listed there. - - Note that this run-time relocation mechanism is much simpler than ELF. - There's no PLT or GOT. Images are relocated as a whole just - by shifting entire images in memory by some offsets. Although doing - this breaks text sharing, I think this mechanism is not actually bad - on today's computers. - -* ICF - - Short for Identical COMDAT Folding (COFF) or Identical Code Folding (ELF). - - ICF is an optimization to reduce output size by merging read-only sections - by not only their names but by their contents. If two read-only sections - happen to have the same metadata, actual contents and relocations, - they are merged by ICF. It is known as an effective technique, - and it usually reduces C++ program's size by a few percent or more. - - Note that this is not an entirely sound optimization. C/C++ require - different functions have different addresses. If a program depends on - that property, it would fail at runtime. - - On Windows, that's not really an issue because MSVC link.exe enabled - the optimization by default. As long as your program works - with the linker's default settings, your program should be safe with ICF. - - On Unix, your program is generally not guaranteed to be safe with ICF, - although large programs happen to work correctly. - LLD works fine with ICF for example. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/open_projects.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/open_projects.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/open_projects.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/open_projects.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -.. _open_projects: - -Open Projects -============= - -.. include:: ../include/lld/Core/TODO.txt - -Documentation TODOs -~~~~~~~~~~~~~~~~~~~ - -.. todolist:: diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/Readers.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/Readers.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/Readers.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/Readers.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -.. _Readers: - -Developing lld Readers -====================== - -Note: this document discuss Mach-O port of LLD. For ELF and COFF, -see :doc:`index`. - -Introduction ------------- - -The purpose of a "Reader" is to take an object file in a particular format -and create an `lld::File`:cpp:class: (which is a graph of Atoms) -representing the object file. A Reader inherits from -`lld::Reader`:cpp:class: which lives in -:file:`include/lld/Core/Reader.h` and -:file:`lib/Core/Reader.cpp`. - -The Reader infrastructure for an object format ``Foo`` requires the -following pieces in order to fit into lld: - -:file:`include/lld/ReaderWriter/ReaderFoo.h` - - .. cpp:class:: ReaderOptionsFoo : public ReaderOptions - - This Options class is the only way to configure how the Reader will - parse any file into an `lld::Reader`:cpp:class: object. This class - should be declared in the `lld`:cpp:class: namespace. - - .. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader) - - This factory function configures and create the Reader. This function - should be declared in the `lld`:cpp:class: namespace. - -:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp` - - .. cpp:class:: ReaderFoo : public Reader - - This is the concrete Reader class which can be called to parse - object files. It should be declared in an anonymous namespace or - if there is shared code with the `lld::WriterFoo`:cpp:class: you - can make a nested namespace (e.g. `lld::foo`:cpp:class:). - -You may have noticed that :cpp:class:`ReaderFoo` is not declared in the -``.h`` file. An important design aspect of lld is that all Readers are -created *only* through an object-format-specific -:cpp:func:`createReaderFoo` factory function. The creation of the Reader is -parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options -class is the one-and-only way to control how the Reader operates when -parsing an input file into an Atom graph. For instance, you may want the -Reader to only accept certain architectures. The options class can be -instantiated from command line options or be programmatically configured. - -Where to start --------------- - -The lld project already has a skeleton of source code for Readers for -``ELF``, ``PECOFF``, ``MachO``, and lld's native ``YAML`` graph format. -If your file format is a variant of one of those, you should modify the -existing Reader to support your variant. This is done by customizing the Options -class for the Reader and making appropriate changes to the ``.cpp`` file to -interpret those options and act accordingly. - -If your object file format is not a variant of any existing Reader, you'll need -to create a new Reader subclass with the organization described above. - -Readers are factories ---------------------- - -The linker will usually only instantiate your Reader once. That one Reader will -have its loadFile() method called many times with different input files. -To support multithreaded linking, the Reader may be parsing multiple input -files in parallel. Therefore, there should be no parsing state in you Reader -object. Any parsing state should be in ivars of your File subclass or in -some temporary object. - -The key method to implement in a reader is:: - - virtual error_code loadFile(LinkerInput &input, - std::vector> &result); - -It takes a memory buffer (which contains the contents of the object file -being read) and returns an instantiated lld::File object which is -a collection of Atoms. The result is a vector of File pointers (instead of -simple a File pointer) because some file formats allow multiple object -"files" to be encoded in one file system file. - - -Memory Ownership ----------------- - -Atoms are always owned by their File object. During core linking when Atoms -are coalesced or stripped away, core linking does not delete them. -Core linking just removes those unused Atoms from its internal list. -The destructor of a File object is responsible for deleting all Atoms it -owns, and if ownership of the MemoryBuffer was passed to it, the File -destructor needs to delete that too. - -Making Atoms ------------- - -The internal model of lld is purely Atom based. But most object files do not -have an explicit concept of Atoms, instead most have "sections". The way -to think of this is that a section is just a list of Atoms with common -attributes. - -The first step in parsing section-based object files is to cleave each -section into a list of Atoms. The technique may vary by section type. For -code sections (e.g. .text), there are usually symbols at the start of each -function. Those symbol addresses are the points at which the section is -cleaved into discrete Atoms. Some file formats (like ELF) also include the -length of each symbol in the symbol table. Otherwise, the length of each -Atom is calculated to run to the start of the next symbol or the end of the -section. - -Other sections types can be implicitly cleaved. For instance c-string literals -or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at -the content of the section. It is important to cleave sections into Atoms -to remove false dependencies. For instance the .eh_frame section often -has no symbols, but contains "pointers" to the functions for which it -has unwind info. If the .eh_frame section was not cleaved (but left as one -big Atom), there would always be a reference (from the eh_frame Atom) to -each function. So the linker would be unable to coalesce or dead stripped -away the function atoms. - -The lld Atom model also requires that a reference to an undefined symbol be -modeled as a Reference to an UndefinedAtom. So the Reader also needs to -create an UndefinedAtom for each undefined symbol in the object file. - -Once all Atoms have been created, the second step is to create References -(recall that Atoms are "nodes" and References are "edges"). Most References -are created by looking at the "relocation records" in the object file. If -a function contains a call to "malloc", there is usually a relocation record -specifying the address in the section and the symbol table index. Your -Reader will need to convert the address to an Atom and offset and the symbol -table index into a target Atom. If "malloc" is not defined in the object file, -the target Atom of the Reference will be an UndefinedAtom. - - -Performance ------------ -Once you have the above working to parse an object file into Atoms and -References, you'll want to look at performance. Some techniques that can -help performance are: - -* Use llvm::BumpPtrAllocator or pre-allocate one big vector and then - just have each atom point to its subrange of References in that vector. - This can be faster that allocating each Reference as separate object. -* Pre-scan the symbol table and determine how many atoms are in each section - then allocate space for all the Atom objects at once. -* Don't copy symbol names or section content to each Atom, instead use - StringRef and ArrayRef in each Atom to point to its name and content in the - MemoryBuffer. - - -Testing -------- - -We are still working on infrastructure to test Readers. The issue is that -you don't want to check in binary files to the test suite. And the tools -for creating your object file from assembly source may not be available on -every OS. - -We are investigating a way to use YAML to describe the section, symbols, -and content of a file. Then have some code which will write out an object -file from that YAML description. - -Once that is in place, you can write test cases that contain section/symbols -YAML and is run through the linker to produce Atom/References based YAML which -is then run through FileCheck to verify the Atoms and References are as -expected. - - - diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/README.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/README.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/README.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/README.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -lld Documentation -================= - -The lld documentation is written using the Sphinx documentation generator. It is -currently tested with Sphinx 1.1.3. - -We currently use the 'nature' theme and a Beaker inspired structure. - -To rebuild documents into html: - - [/lld/docs]> make html - diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/ReleaseNotes.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/ReleaseNotes.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/ReleaseNotes.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/ReleaseNotes.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -======================= -LLD 6.0.0 Release Notes -======================= - -.. contents:: - :local: - -Introduction -============ - -This document contains the release notes for the LLD linker, release 6.0.0. -Here we describe the status of LLD, including major improvements -from the previous release. All LLD releases may be downloaded -from the `LLVM releases web site `_. - -Non-comprehensive list of changes in this release -================================================= - -ELF Improvements ----------------- - -* MIPS port now generates all output dynamic relocations - using Elf_Rel format only. - -* Added handling of the R_MIPS_26 relocation in case of N32 / N64 ABIs - and generating proper PLT entries. - -* lld can patch Aarch64 errata 843419. - -* lld can generate thunks for out of range thunks. - -* ARM PLT entries automatically use short or long variants. - -* Lots of bug fixes. Should be able to handle almost all linker and version scripts. - -* Faster gdb index creation. - -* Tar files created by --reproduce now work even in the presence of absolute paths. - -* lld defaults to --hash-style=both. - -* ICF now deduplicates .eh_frame entries. - -* LLD supports the Android relocation packing format. - -* Debug info is used in more cases when reporting errors. - -* LLD can produce x86/x86_64 PLTs that use retpolines. - -COFF Improvements ------------------ - -* A GNU ld style frontend for the COFF linker has been added for MinGW. - In MinGW environments, the linker is invoked with GNU ld style parameters; - which LLD previously only supported when used as an ELF linker. When - a PE/COFF target is chosen, those parameters are rewritten into the - lld-link style parameters and the COFF linker is invoked instead. - -* Initial support for the ARM64 architecture has been added. - -* New ``--version`` flag. - -* Significantly improved support for writing PDB Files. - -* New ``--rsp-quoting`` flag, like ``clang-cl``. - -* ``/manifestuac:no`` no longer incorrectly disables ``/manifestdependency:``. - -* Only write ``.manifest`` files if ``/manifest`` is passed. - -MachO Improvements ------------------- - -* Item 1. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/sphinx_intro.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/sphinx_intro.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/sphinx_intro.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/sphinx_intro.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -.. _sphinx_intro: - -Sphinx Introduction for LLVM Developers -======================================= - -This document is intended as a short and simple introduction to the Sphinx -documentation generation system for LLVM developers. - -Quickstart ----------- - -To get started writing documentation, you will need to: - - 1. Have the Sphinx tools :ref:`installed `. - - 2. Understand how to :ref:`build the documentation - `. - - 3. Start :ref:`writing documentation `! - -.. _installing_sphinx: - -Installing Sphinx -~~~~~~~~~~~~~~~~~ - -You should be able to install Sphinx using the standard Python package -installation tool ``easy_install``, as follows:: - - $ sudo easy_install sphinx - Searching for sphinx - Reading http://pypi.python.org/simple/sphinx/ - Reading http://sphinx.pocoo.org/ - Best match: Sphinx 1.1.3 - ... more lines here .. - -If you do not have root access (or otherwise want to avoid installing Sphinx in -system directories) see the section on :ref:`installing_sphinx_in_a_venv` . - -If you do not have the ``easy_install`` tool on your system, you should be able -to install it using: - - Linux - Use your distribution's standard package management tool to install it, - i.e., ``apt-get install easy_install`` or ``yum install easy_install``. - - Mac OS X - All modern Mac OS X systems come with ``easy_install`` as part of the base - system. - - Windows - See the `setuptools `_ package web - page for instructions. - - -.. _building_the_documentation: - -Building the documentation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In order to build the documentation need to add ``-DLLVM_ENABLE_SPHINX=ON`` to -your ``cmake`` command. Once you do this you can build the docs using -``docs-lld-html`` build (``ninja`` or ``make``) target. - -That build target will invoke ``sphinx-build`` with the appropriate options for -the project, and generate the HTML documentation in a ``tools/lld/docs/html`` -subdirectory. - -.. _writing_documentation: - -Writing documentation -~~~~~~~~~~~~~~~~~~~~~ - -The documentation itself is written in the reStructuredText (ReST) format, and -Sphinx defines additional tags to support features like cross-referencing. - -The ReST format itself is organized around documents mostly being readable -plaintext documents. You should generally be able to write new documentation -easily just by following the style of the existing documentation. - -If you want to understand the formatting of the documents more, the best place -to start is Sphinx's own `ReST Primer `_. - - -Learning More -------------- - -If you want to learn more about the Sphinx system, the best place to start is -the Sphinx documentation itself, available `here -`_. - - -.. _installing_sphinx_in_a_venv: - -Installing Sphinx in a Virtual Environment ------------------------------------------- - -Most Python developers prefer to work with tools inside a *virtualenv* (virtual -environment) instance, which functions as an application sandbox. This avoids -polluting your system installation with different packages used by various -projects (and ensures that dependencies for different packages don't conflict -with one another). Of course, you need to first have the virtualenv software -itself which generally would be installed at the system level:: - - $ sudo easy_install virtualenv - -but after that you no longer need to install additional packages in the system -directories. - -Once you have the *virtualenv* tool itself installed, you can create a -virtualenv for Sphinx using:: - - $ virtualenv ~/my-sphinx-install - New python executable in /Users/dummy/my-sphinx-install/bin/python - Installing setuptools............done. - Installing pip...............done. - - $ ~/my-sphinx-install/bin/easy_install sphinx - ... install messages here ... - -and from now on you can "activate" the *virtualenv* using:: - - $ source ~/my-sphinx-install/bin/activate - -which will change your PATH to ensure the sphinx-build tool from inside the -virtual environment will be used. See the `virtualenv website -`_ for more information on using -virtual environments. Binary files /tmp/tmp_XJtJO/S9yKL18OTF/rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/_static/favicon.ico and /tmp/tmp_XJtJO/so6ylqf6Ij/rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/_static/favicon.ico differ diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/_templates/indexsidebar.html rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/_templates/indexsidebar.html --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/_templates/indexsidebar.html 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/_templates/indexsidebar.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -

Bugs

- -

lld bugs should be reported at the - LLVM Bugzilla.

diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/_templates/layout.html rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/_templates/layout.html --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/_templates/layout.html 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/_templates/layout.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -{% extends "!layout.html" %} - -{% block extrahead %} - -{% endblock %} - -{% block rootrellink %} -
  • lld Home | 
  • -{% endblock %} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/WebAssembly.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/WebAssembly.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/WebAssembly.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/WebAssembly.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -WebAssembly lld port -==================== - -Note: The WebAssembly port is still a work in progress and is be lacking -certain features. - -The WebAssembly version of lld takes WebAssembly binaries as inputs and produces -a WebAssembly binary as its output. For the most part this port tried to mimic -the behaviour of traditional ELF linkers and specifically the ELF lld port. -Where possible that command line flags and the semantics should be the same. - - -Object file format ------------------- - -The format the input object files that lld expects is specified as part of the -the WebAssembly tool conventions -https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md. - -This is object format that the llvm will produce when run with the -``wasm32-unknown-unknown-wasm`` target. To build llvm with WebAssembly support -currently requires enabling the experimental backed using -``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``. - - -Missing features ----------------- - -There are several key features that are not yet implement in the WebAssembly -ports: - -- COMDAT support. This means that support for C++ is still very limited. -- Function stripping. Currently there is no support for ``--gc-sections`` so - functions and data from a given object will linked as a unit. -- Section start/end symbols. The synthetic symbols that mark the start and - of data regions are not yet created in the output file. diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/windows_support.rst rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/windows_support.rst --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/docs/windows_support.rst 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/docs/windows_support.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -.. raw:: html - - - -.. role:: none -.. role:: partial -.. role:: good - -=============== -Windows support -=============== - -LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with -``-flavor link``, the driver for Windows operating system is used to parse -command line options, and it drives further linking processes. LLD accepts -almost all command line options that the linker shipped with Microsoft Visual -C++ (link.exe) supports. - -The current status is that LLD can link itself on Windows x86/x64 -using Visual C++ 2013 as the compiler. - -Development status -================== - -Driver - :good:`Mostly done`. Some exotic command line options that are not usually - used for application develompent, such as ``/DRIVER``, are not supported. - -Linking against DLL - :good:`Done`. LLD can read import libraries needed to link against DLL. Both - export-by-name and export-by-ordinal are supported. - -Linking against static library - :good:`Done`. The format of static library (.lib) on Windows is actually the - same as on Unix (.a). LLD can read it. - -Creating DLL - :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported - functions can be specified either via command line (``/EXPORT``) or via - module-definition file (.def). Both export-by-name and export-by-ordinal are - supported. - -Windows resource files support - :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF - file using LLVM's Object library. - -Safe Structured Exception Handler (SEH) - :good:`Done` for both x86 and x64. - -Module-definition file - :partial:`Partially done`. LLD currently recognizes these directives: - ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. - -Debug info - :none:`No progress has been made`. Microsoft linker can interpret the CodeGen - debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't - support neither. - - -Building LLD -============ - -Using Visual Studio IDE/MSBuild -------------------------------- - -1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), -#. run ``cmake -G "Visual Studio 12" `` from VS command prompt, -#. open LLVM.sln with Visual Studio, and -#. build ``lld`` target in ``lld executables`` folder - -Alternatively, you can use msbuild if you don't like to work in an IDE:: - - msbuild LLVM.sln /m /target:"lld executables\lld" - -MSBuild.exe had been shipped as a component of the .NET framework, but since -2013 it's part of Visual Studio. You can find it at "C:\\Program Files -(x86)\\msbuild". - -You can build LLD as a 64 bit application. To do that, open VS2013 x64 command -prompt and run cmake for "Visual Studio 12 Win64" target. - -Using Ninja ------------ - -1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), -#. run ``cmake -G ninja `` from VS command prompt, -#. run ``ninja lld`` diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,649 +0,0 @@ -//===- AArch64ErrataFix.cpp -----------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// This file implements Section Patching for the purpose of working around -// errata in CPUs. The general principle is that an erratum sequence of one or -// more instructions is detected in the instruction stream, one of the -// instructions in the sequence is replaced with a branch to a patch sequence -// of replacement instructions. At the end of the replacement sequence the -// patch branches back to the instruction stream. - -// This technique is only suitable for fixing an erratum when: -// - There is a set of necessary conditions required to trigger the erratum that -// can be detected at static link time. -// - There is a set of replacement instructions that can be used to remove at -// least one of the necessary conditions that trigger the erratum. -// - We can overwrite an instruction in the erratum sequence with a branch to -// the replacement sequence. -// - We can place the replacement sequence within range of the branch. - -// FIXME: -// - The implementation here only supports one patch, the AArch64 Cortex-53 -// errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core. -// To keep the initial version simple there is no support for multiple -// architectures or selection of different patches. -//===----------------------------------------------------------------------===// - -#include "AArch64ErrataFix.h" -#include "Config.h" -#include "LinkerScript.h" -#include "OutputSections.h" -#include "Relocations.h" -#include "Strings.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "lld/Common/Memory.h" - -#include "llvm/Support/Endian.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; -using namespace llvm::ELF; -using namespace llvm::object; -using namespace llvm::support; -using namespace llvm::support::endian; - -using namespace lld; -using namespace lld::elf; - -// Helper functions to identify instructions and conditions needed to trigger -// the Cortex-A53-843419 erratum. - -// ADRP -// | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) | -static bool isADRP(uint32_t Instr) { - return (Instr & 0x9f000000) == 0x90000000; -} - -// Load and store bit patterns from ARMv8-A ARM ARM. -// Instructions appear in order of appearance starting from table in -// C4.1.3 Loads and Stores. - -// All loads and stores have 1 (at bit postion 27), (0 at bit position 25). -// | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | -static bool isLoadStoreClass(uint32_t Instr) { - return (Instr & 0x0a000000) == 0x08000000; -} - -// LDN/STN multiple no offset -// | 0 Q 00 | 1100 | 0 L 00 | 0000 | opcode (4) | size (2) | Rn (5) | Rt (5) | -// LDN/STN multiple post-indexed -// | 0 Q 00 | 1100 | 1 L 0 | Rm (5)| opcode (4) | size (2) | Rn (5) | Rt (5) | -// L == 0 for stores. - -// Utility routine to decode opcode field of LDN/STN multiple structure -// instructions to find the ST1 instructions. -// opcode == 0010 ST1 4 registers. -// opcode == 0110 ST1 3 registers. -// opcode == 0111 ST1 1 register. -// opcode == 1010 ST1 2 registers. -static bool isST1MultipleOpcode(uint32_t Instr) { - return (Instr & 0x0000f000) == 0x00002000 || - (Instr & 0x0000f000) == 0x00006000 || - (Instr & 0x0000f000) == 0x00007000 || - (Instr & 0x0000f000) == 0x0000a000; -} - -static bool isST1Multiple(uint32_t Instr) { - return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr); -} - -// Writes to Rn (writeback). -static bool isST1MultiplePost(uint32_t Instr) { - return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr); -} - -// LDN/STN single no offset -// | 0 Q 00 | 1101 | 0 L R 0 | 0000 | opc (3) S | size (2) | Rn (5) | Rt (5)| -// LDN/STN single post-indexed -// | 0 Q 00 | 1101 | 1 L R | Rm (5) | opc (3) S | size (2) | Rn (5) | Rt (5)| -// L == 0 for stores - -// Utility routine to decode opcode field of LDN/STN single structure -// instructions to find the ST1 instructions. -// R == 0 for ST1 and ST3, R == 1 for ST2 and ST4. -// opcode == 000 ST1 8-bit. -// opcode == 010 ST1 16-bit. -// opcode == 100 ST1 32 or 64-bit (Size determines which). -static bool isST1SingleOpcode(uint32_t Instr) { - return (Instr & 0x0040e000) == 0x00000000 || - (Instr & 0x0040e000) == 0x00004000 || - (Instr & 0x0040e000) == 0x00008000; -} - -static bool isST1Single(uint32_t Instr) { - return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr); -} - -// Writes to Rn (writeback). -static bool isST1SinglePost(uint32_t Instr) { - return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr); -} - -static bool isST1(uint32_t Instr) { - return isST1Multiple(Instr) || isST1MultiplePost(Instr) || - isST1Single(Instr) || isST1SinglePost(Instr); -} - -// Load/store exclusive -// | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) | -// L == 0 for Stores. -static bool isLoadStoreExclusive(uint32_t Instr) { - return (Instr & 0x3f000000) == 0x08000000; -} - -static bool isLoadExclusive(uint32_t Instr) { - return (Instr & 0x3f400000) == 0x08400000; -} - -// Load register literal -// | opc (2) 01 | 1 V 00 | imm19 | Rt (5) | -static bool isLoadLiteral(uint32_t Instr) { - return (Instr & 0x3b000000) == 0x18000000; -} - -// Load/store no-allocate pair -// (offset) -// | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | -// L == 0 for stores. -// Never writes to register -static bool isSTNP(uint32_t Instr) { - return (Instr & 0x3bc00000) == 0x28000000; -} - -// Load/store register pair -// (post-indexed) -// | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | -// L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP -// Writes to Rn. -static bool isSTPPost(uint32_t Instr) { - return (Instr & 0x3bc00000) == 0x28800000; -} - -// (offset) -// | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | -static bool isSTPOffset(uint32_t Instr) { - return (Instr & 0x3bc00000) == 0x29000000; -} - -// (pre-index) -// | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | -// Writes to Rn. -static bool isSTPPre(uint32_t Instr) { - return (Instr & 0x3bc00000) == 0x29800000; -} - -static bool isSTP(uint32_t Instr) { - return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr); -} - -// Load/store register (unscaled immediate) -// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) | -// V == 0 for Scalar, V == 1 for Simd/FP. -static bool isLoadStoreUnscaled(uint32_t Instr) { - return (Instr & 0x3b000c00) == 0x38000000; -} - -// Load/store register (immediate post-indexed) -// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) | -static bool isLoadStoreImmediatePost(uint32_t Instr) { - return (Instr & 0x3b200c00) == 0x38000400; -} - -// Load/store register (unprivileged) -// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) | -static bool isLoadStoreUnpriv(uint32_t Instr) { - return (Instr & 0x3b200c00) == 0x38000800; -} - -// Load/store register (immediate pre-indexed) -// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) | -static bool isLoadStoreImmediatePre(uint32_t Instr) { - return (Instr & 0x3b200c00) == 0x38000c00; -} - -// Load/store register (register offset) -// | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt | -static bool isLoadStoreRegisterOff(uint32_t Instr) { - return (Instr & 0x3b200c00) == 0x38200800; -} - -// Load/store register (unsigned immediate) -// | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) | -static bool isLoadStoreRegisterUnsigned(uint32_t Instr) { - return (Instr & 0x3b000000) == 0x39000000; -} - -// Rt is always in bit position 0 - 4. -static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); } - -// Rn is always in bit position 5 - 9. -static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } - -// C4.1.2 Branches, Exception Generating and System instructions -// | op0 (3) 1 | 01 op1 (4) | x (22) | -// op0 == 010 101 op1 == 0xxx Conditional Branch. -// op0 == 110 101 op1 == 1xxx Unconditional Branch Register. -// op0 == x00 101 op1 == xxxx Unconditional Branch immediate. -// op0 == x01 101 op1 == 0xxx Compare and branch immediate. -// op0 == x01 101 op1 == 1xxx Test and branch immediate. -static bool isBranch(uint32_t Instr) { - return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch. - ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. - ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. - ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch. -} - -static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) { - return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) || - isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) || - isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr); -} - -// Note that this function refers to v8.0 only and does not include the -// additional load and store instructions added for in later revisions of -// the architecture such as the Atomic memory operations introduced -// in v8.1. -static bool isV8NonStructureLoad(uint32_t Instr) { - if (isLoadExclusive(Instr)) - return true; - if (isLoadLiteral(Instr)) - return true; - else if (isV8SingleRegisterNonStructureLoadStore(Instr)) { - // For Load and Store single register, Loads are derived from a - // combination of the Size, V and Opc fields. - uint32_t Size = (Instr >> 30) & 0xff; - uint32_t V = (Instr >> 26) & 0x1; - uint32_t Opc = (Instr >> 22) & 0x3; - // For the load and store instructions that we are decoding. - // Opc == 0 are all stores. - // Opc == 1 with a couple of exceptions are loads. The exceptions are: - // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and - // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch. - return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) && - !(Size == 3 && V == 0 && Opc == 2); - } - return false; -} - -// The following decode instructions are only complete up to the instructions -// needed for errata 843419. - -// Instruction with writeback updates the index register after the load/store. -static bool hasWriteback(uint32_t Instr) { - return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) || - isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) || - isST1MultiplePost(Instr); -} - -// For the load and store class of instructions, a load can write to the -// destination register, a load and a store can write to the base register when -// the instruction has writeback. -static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { - return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) || - (hasWriteback(Instr) && getRn(Instr) == Reg); -} - -// Scanner for Cortex-A53 errata 843419 -// Full details are available in the Cortex A53 MPCore revision 0 Software -// Developers Errata Notice (ARM-EPM-048406). -// -// The instruction sequence that triggers the erratum is common in compiled -// AArch64 code, however it is sensitive to the offset of the sequence within -// a 4k page. This means that by scanning and fixing the patch after we have -// assigned addresses we only need to disassemble and fix instances of the -// sequence in the range of affected offsets. -// -// In summary the erratum conditions are a series of 4 instructions: -// 1.) An ADRP instruction that writes to register Rn with low 12 bits of -// address of instruction either 0xff8 or 0xffc. -// 2.) A load or store instruction that can be: -// - A single register load or store, of either integer or vector registers. -// - An STP or STNP, of either integer or vector registers. -// - An Advanced SIMD ST1 store instruction. -// - Must not write to Rn, but may optionally read from it. -// 3.) An optional instruction that is not a branch and does not write to Rn. -// 4.) A load or store from the Load/store register (unsigned immediate) class -// that uses Rn as the base address register. -// -// Note that we do not attempt to scan for Sequence 2 as described in the -// Software Developers Errata Notice as this has been assessed to be extremely -// unlikely to occur in compiled code. This matches gold and ld.bfd behavior. - -// Return true if the Instruction sequence Adrp, Instr2, and Instr4 match -// the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.), -// and 4.) in the Scanner for Cortex-A53 errata comment above. -static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, - uint32_t Instr4) { - if (!isADRP(Instr1)) - return false; - - uint32_t Rn = getRt(Instr1); - return isLoadStoreClass(Instr2) && - (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) || - isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) || - isSTNP(Instr2) || isST1(Instr2)) && - !doesLoadStoreWriteToReg(Instr2, Rn) && - isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn; -} - -// Scan the instruction sequence starting at Offset Off from the base of -// InputSection IS. We update Off in this function rather than in the caller as -// we can skip ahead much further into the section when we know how many -// instructions we've scanned. -// Return the offset of the load or store instruction in IS that we want to -// patch or 0 if no patch required. -static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, - uint64_t Limit) { - uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff; - - // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. - uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; - if (InitialPageOff < 0xff8) - Off += 0xff8 - InitialPageOff; - - bool OptionalAllowed = Limit - Off > 12; - if (Off >= Limit || Limit - Off < 12) { - // Need at least 3 4-byte sized instructions to trigger erratum. - Off = Limit; - return 0; - } - - uint64_t PatchOff = 0; - const uint8_t *Buf = IS->Data.begin(); - const ulittle32_t *InstBuf = reinterpret_cast(Buf + Off); - uint32_t Instr1 = *InstBuf++; - uint32_t Instr2 = *InstBuf++; - uint32_t Instr3 = *InstBuf++; - if (is843419ErratumSequence(Instr1, Instr2, Instr3)) { - PatchOff = Off + 8; - } else if (OptionalAllowed && !isBranch(Instr3)) { - uint32_t Instr4 = *InstBuf++; - if (is843419ErratumSequence(Instr1, Instr2, Instr4)) - PatchOff = Off + 12; - } - if (((ISAddr + Off) & 0xfff) == 0xff8) - Off += 4; - else - Off += 0xffc; - return PatchOff; -} - -class lld::elf::Patch843419Section : public SyntheticSection { -public: - Patch843419Section(InputSection *P, uint64_t Off); - - void writeTo(uint8_t *Buf) override; - - size_t getSize() const override { return 8; } - - uint64_t getLDSTAddr() const; - - // The Section we are patching. - const InputSection *Patchee; - // The offset of the instruction in the Patchee section we are patching. - uint64_t PatcheeOffset; - // A label for the start of the Patch that we can use as a relocation target. - Symbol *PatchSym; -}; - -lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, - ".text.patch"), - Patchee(P), PatcheeOffset(Off) { - this->Parent = P->getParent(); - PatchSym = addSyntheticLocal( - Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, - getSize(), *this); - addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); -} - -uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { - return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset; -} - -void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { - // Copy the instruction that we will be replacing with a branch in the - // Patchee Section. - write32le(Buf, read32le(Patchee->Data.begin() + PatcheeOffset)); - - // Apply any relocation transferred from the original PatcheeSection. - // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc - // also adds OutSecOff so we need to subtract to avoid double counting. - this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize()); - - // Return address is the next instruction after the one we have just copied. - uint64_t S = getLDSTAddr() + 4; - uint64_t P = PatchSym->getVA() + 4; - Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P); -} - -void AArch64Err843419Patcher::init() { - // The AArch64 ABI permits data in executable sections. We must avoid scanning - // this data as if it were instructions to avoid false matches. We use the - // mapping symbols in the InputObjects to identify this data, caching the - // results in SectionMap so we don't have to recalculate it each pass. - - // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe - // half open intervals [Symbol Value, Next Symbol Value) of code and data - // within sections. If there is no next symbol then the half open interval is - // [Symbol Value, End of section). The type, code or data, is determined by - // the mapping symbol name, $x for code, $d for data. - auto IsCodeMapSymbol = [](const Symbol *B) { - return B->getName() == "$x" || B->getName().startswith("$x."); - }; - auto IsDataMapSymbol = [](const Symbol *B) { - return B->getName() == "$d" || B->getName().startswith("$d."); - }; - - // Collect mapping symbols for every executable InputSection. - for (InputFile *File : ObjectFiles) { - auto *F = cast>(File); - for (Symbol *B : F->getLocalSymbols()) { - auto *Def = dyn_cast(B); - if (!Def) - continue; - if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def)) - continue; - if (auto *Sec = dyn_cast(Def->Section)) - if (Sec->Flags & SHF_EXECINSTR) - SectionMap[Sec].push_back(Def); - } - } - // For each InputSection make sure the mapping symbols are in sorted in - // ascending order and free from consecutive runs of mapping symbols with - // the same type. For example we must remove the redundant $d.1 from $x.0 - // $d.0 $d.1 $x.1. - for (auto &KV : SectionMap) { - std::vector &MapSyms = KV.second; - if (MapSyms.size() <= 1) - continue; - std::stable_sort( - MapSyms.begin(), MapSyms.end(), - [](const Defined *A, const Defined *B) { return A->Value < B->Value; }); - MapSyms.erase( - std::unique(MapSyms.begin(), MapSyms.end(), - [=](const Defined *A, const Defined *B) { - return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) || - (IsDataMapSymbol(A) && IsDataMapSymbol(B)); - }), - MapSyms.end()); - } - Initialized = true; -} - -// Insert the PatchSections we have created back into the -// InputSectionDescription. As inserting patches alters the addresses of -// InputSections that follow them, we try and place the patches after all the -// executable sections, although we may need to insert them earlier if the -// InputSectionDescription is larger than the maximum branch range. -void AArch64Err843419Patcher::insertPatches( - InputSectionDescription &ISD, std::vector &Patches) { - uint64_t ISLimit; - uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; - uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; - - // Set the OutSecOff of patches to the place where we want to insert them. - // We use a similar strategy to Thunk placement. Place patches roughly - // every multiple of maximum branch range. - auto PatchIt = Patches.begin(); - auto PatchEnd = Patches.end(); - for (const InputSection *IS : ISD.Sections) { - ISLimit = IS->OutSecOff + IS->getSize(); - if (ISLimit > PatchUpperBound) { - while (PatchIt != PatchEnd) { - if ((*PatchIt)->getLDSTAddr() >= PrevISLimit) - break; - (*PatchIt)->OutSecOff = PrevISLimit; - ++PatchIt; - } - PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; - } - PrevISLimit = ISLimit; - } - for (; PatchIt != PatchEnd; ++PatchIt) { - (*PatchIt)->OutSecOff = ISLimit; - } - - // merge all patch sections. We use the OutSecOff assigned above to - // determine the insertion point. This is ok as we only merge into an - // InputSectionDescription once per pass, and at the end of the pass - // assignAddresses() will recalculate all the OutSecOff values. - std::vector Tmp; - Tmp.reserve(ISD.Sections.size() + Patches.size()); - auto MergeCmp = [](const InputSection *A, const InputSection *B) { - if (A->OutSecOff < B->OutSecOff) - return true; - if (A->OutSecOff == B->OutSecOff && isa(A) && - !isa(B)) - return true; - return false; - }; - std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(), - Patches.end(), std::back_inserter(Tmp), MergeCmp); - ISD.Sections = std::move(Tmp); -} - -// Given an erratum sequence that starts at address AdrpAddr, with an -// instruction that we need to patch at PatcheeOffset from the start of -// InputSection IS, create a Patch843419 Section and add it to the -// Patches that we need to insert. -static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, - InputSection *IS, - std::vector &Patches) { - // There may be a relocation at the same offset that we are patching. There - // are three cases that we need to consider. - // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this - // instance of the erratum on a previous patch and altered the relocation. We - // have nothing more to do. - // Case 2: A load/store register (unsigned immediate) class relocation. There - // are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and - // they are both absolute. We need to add the same relocation to the patch, - // and replace the relocation with a R_AARCH_JUMP26 branch relocation. - // Case 3: No relocation. We must create a new R_AARCH64_JUMP26 branch - // relocation at the offset. - auto RelIt = std::find_if( - IS->Relocations.begin(), IS->Relocations.end(), - [=](const Relocation &R) { return R.Offset == PatcheeOffset; }); - if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26) - return; - - if (Config->Verbose) - message("detected cortex-a53-843419 erratum sequence starting at " + - utohexstr(AdrpAddr) + " in unpatched output."); - - auto *PS = make(IS, PatcheeOffset); - Patches.push_back(PS); - - auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) { - return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym}; - }; - - if (RelIt != IS->Relocations.end()) { - PS->Relocations.push_back( - {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym}); - *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym); - } else - IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym)); -} - -// Scan all the instructions in InputSectionDescription, for each instance of -// the erratum sequence create a Patch843419Section. We return the list of -// Patch843419Sections that need to be applied to ISD. -std::vector -AArch64Err843419Patcher::patchInputSectionDescription( - InputSectionDescription &ISD) { - std::vector Patches; - for (InputSection *IS : ISD.Sections) { - // LLD doesn't use the erratum sequence in SyntheticSections. - if (isa(IS)) - continue; - // Use SectionMap to make sure we only scan code and not inline data. - // We have already sorted MapSyms in ascending order and removed consecutive - // mapping symbols of the same type. Our range of executable instructions to - // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value, - // section size). - std::vector &MapSyms = SectionMap[IS]; - - auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) { - return MS->getName().startswith("$x"); - }); - - while (CodeSym != MapSyms.end()) { - auto DataSym = std::next(CodeSym); - uint64_t Off = (*CodeSym)->Value; - uint64_t Limit = - (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value; - - while (Off < Limit) { - uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off; - if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) - implementPatch(StartAddr, PatcheeOffset, IS, Patches); - } - if (DataSym == MapSyms.end()) - break; - CodeSym = std::next(DataSym); - } - } - return Patches; -} - -// For each InputSectionDescription make one pass over the executable sections -// looking for the erratum sequence; creating a synthetic Patch843419Section -// for each instance found. We insert these synthetic patch sections after the -// executable code in each InputSectionDescription. -// -// PreConditions: -// The Output and Input Sections have had their final addresses assigned. -// -// PostConditions: -// Returns true if at least one patch was added. The addresses of the -// Ouptut and Input Sections may have been changed. -// Returns false if no patches were required and no changes were made. -bool AArch64Err843419Patcher::createFixes() { - if (Initialized == false) - init(); - - bool AddressesChanged = false; - for (OutputSection *OS : OutputSections) { - if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) - continue; - for (BaseCommand *BC : OS->SectionCommands) - if (auto *ISD = dyn_cast(BC)) { - std::vector Patches = - patchInputSectionDescription(*ISD); - if (!Patches.empty()) { - insertPatches(*ISD, Patches); - AddressesChanged = true; - } - } - } - return AddressesChanged; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/AArch64ErrataFix.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -//===- AArch64ErrataFix.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_AARCH64ERRATAFIX_H -#define LLD_ELF_AARCH64ERRATAFIX_H - -#include "lld/Common/LLVM.h" - -#include -#include - -namespace lld { -namespace elf { - -class Defined; -class InputSection; -struct InputSectionDescription; -class OutputSection; -class Patch843419Section; - -class AArch64Err843419Patcher { -public: - // return true if Patches have been added to the OutputSections. - bool createFixes(); - -private: - std::vector - patchInputSectionDescription(InputSectionDescription &ISD); - - void insertPatches(InputSectionDescription &ISD, - std::vector &Patches); - - void init(); - - // A cache of the mapping symbols defined by the InputSecion sorted in order - // of ascending value with redundant symbols removed. These describe - // the ranges of code and data in an executable InputSection. - std::map> SectionMap; - - bool Initialized = false; -}; - -} // namespace elf -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AArch64.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AArch64.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AArch64.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AArch64.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,426 +0,0 @@ -//===- AArch64.cpp --------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "Thunks.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -// Page(Expr) is the page address of the expression Expr, defined -// as (Expr & ~0xFFF). (This applies even if the machine page size -// supported by the platform has a different value.) -uint64_t elf::getAArch64Page(uint64_t Expr) { - return Expr & ~static_cast(0xFFF); -} - -namespace { -class AArch64 final : public TargetInfo { -public: - AArch64(); - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const override; - bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; - bool usesOnlyLowPageBits(RelType Type) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr Expr) const override; - void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -AArch64::AArch64() { - CopyRel = R_AARCH64_COPY; - RelativeRel = R_AARCH64_RELATIVE; - IRelativeRel = R_AARCH64_IRELATIVE; - GotRel = R_AARCH64_GLOB_DAT; - PltRel = R_AARCH64_JUMP_SLOT; - TlsDescRel = R_AARCH64_TLSDESC; - TlsGotRel = R_AARCH64_TLS_TPREL64; - GotEntrySize = 8; - GotPltEntrySize = 8; - PltEntrySize = 16; - PltHeaderSize = 32; - DefaultMaxPageSize = 65536; - - // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant - // 1 of the tls structures and the tcb size is 16. - TcbSize = 16; - NeedsThunks = true; - - // See comment in Arch/ARM.cpp for a more detailed explanation of - // ThunkSectionSpacing. For AArch64 the only branches we are permitted to - // Thunk have a range of +/- 128 MiB - ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000; -} - -RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_AARCH64_TLSDESC_ADR_PAGE21: - return R_TLSDESC_PAGE; - case R_AARCH64_TLSDESC_LD64_LO12: - case R_AARCH64_TLSDESC_ADD_LO12: - return R_TLSDESC; - case R_AARCH64_TLSDESC_CALL: - return R_TLSDESC_CALL; - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - return R_TLS; - case R_AARCH64_CALL26: - case R_AARCH64_CONDBR19: - case R_AARCH64_JUMP26: - case R_AARCH64_TSTBR14: - return R_PLT_PC; - case R_AARCH64_PREL16: - case R_AARCH64_PREL32: - case R_AARCH64_PREL64: - case R_AARCH64_ADR_PREL_LO21: - case R_AARCH64_LD_PREL_LO19: - return R_PC; - case R_AARCH64_ADR_PREL_PG_HI21: - return R_PAGE_PC; - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - return R_GOT; - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - return R_GOT_PAGE_PC; - case R_AARCH64_NONE: - return R_NONE; - default: - return R_ABS; - } -} - -RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr Expr) const { - if (Expr == R_RELAX_TLS_GD_TO_IE) { - if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) - return R_RELAX_TLS_GD_TO_IE_PAGE_PC; - return R_RELAX_TLS_GD_TO_IE_ABS; - } - return Expr; -} - -bool AArch64::usesOnlyLowPageBits(RelType Type) const { - switch (Type) { - default: - return false; - case R_AARCH64_ADD_ABS_LO12_NC: - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_LDST128_ABS_LO12_NC: - case R_AARCH64_LDST16_ABS_LO12_NC: - case R_AARCH64_LDST32_ABS_LO12_NC: - case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12: - case R_AARCH64_TLSDESC_LD64_LO12: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - return true; - } -} - -bool AArch64::isPicRel(RelType Type) const { - return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; -} - -void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { - write64le(Buf, InX::Plt->getVA()); -} - -void AArch64::writePltHeader(uint8_t *Buf) const { - const uint8_t PltData[] = { - 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! - 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) - 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] - 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) - 0x20, 0x02, 0x1f, 0xd6, // br x17 - 0x1f, 0x20, 0x03, 0xd5, // nop - 0x1f, 0x20, 0x03, 0xd5, // nop - 0x1f, 0x20, 0x03, 0xd5 // nop - }; - memcpy(Buf, PltData, sizeof(PltData)); - - uint64_t Got = InX::GotPlt->getVA(); - uint64_t Plt = InX::Plt->getVA(); - relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); - relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); - relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); -} - -void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Inst[] = { - 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) - 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] - 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) - 0x20, 0x02, 0x1f, 0xd6 // br x17 - }; - memcpy(Buf, Inst, sizeof(Inst)); - - relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, - getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); - relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); - relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); -} - -bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const { - // ELF for the ARM 64-bit architecture, section Call and Jump relocations - // only permits range extension thunks for R_AARCH64_CALL26 and - // R_AARCH64_JUMP26 relocation types. - if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) - return false; - uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); - return !inBranchRange(Type, BranchAddr, Dst); -} - -bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { - if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) - return true; - // The AArch64 call and unconditional branch instructions have a range of - // +/- 128 MiB. - uint64_t Range = 128 * 1024 * 1024; - if (Dst > Src) { - // Immediate of branch is signed. - Range -= 4; - return Dst - Src <= Range; - } - return Src - Dst <= Range; -} - -static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; - uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); -} - -// Return the bits [Start, End] from Val shifted Start bits. -// For instance, getBits(0xF0, 4, 8) returns 0xF. -static uint64_t getBits(uint64_t Val, int Start, int End) { - uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; - return (Val >> Start) & Mask; -} - -static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } - -// Update the immediate field in a AARCH64 ldr, str, and add instruction. -static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { - or32le(L, (Imm & 0xFFF) << 10); -} - -void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_AARCH64_ABS16: - case R_AARCH64_PREL16: - checkIntUInt<16>(Loc, Val, Type); - write16le(Loc, Val); - break; - case R_AARCH64_ABS32: - case R_AARCH64_PREL32: - checkIntUInt<32>(Loc, Val, Type); - write32le(Loc, Val); - break; - case R_AARCH64_ABS64: - case R_AARCH64_GLOB_DAT: - case R_AARCH64_PREL64: - write64le(Loc, Val); - break; - case R_AARCH64_ADD_ABS_LO12_NC: - or32AArch64Imm(Loc, Val); - break; - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_ADR_PREL_PG_HI21: - case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: - case R_AARCH64_TLSDESC_ADR_PAGE21: - checkInt<33>(Loc, Val, Type); - write32AArch64Addr(Loc, Val >> 12); - break; - case R_AARCH64_ADR_PREL_LO21: - checkInt<21>(Loc, Val, Type); - write32AArch64Addr(Loc, Val); - break; - case R_AARCH64_JUMP26: - // Normally we would just write the bits of the immediate field, however - // when patching instructions for the cpu errata fix -fix-cortex-a53-843419 - // we want to replace a non-branch instruction with a branch immediate - // instruction. By writing all the bits of the instruction including the - // opcode and the immediate (0 001 | 01 imm26) we can do this - // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of - // the instruction we want to patch. - write32le(Loc, 0x14000000); - LLVM_FALLTHROUGH; - case R_AARCH64_CALL26: - checkInt<28>(Loc, Val, Type); - or32le(Loc, (Val & 0x0FFFFFFC) >> 2); - break; - case R_AARCH64_CONDBR19: - case R_AARCH64_LD_PREL_LO19: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); - or32le(Loc, (Val & 0x1FFFFC) << 3); - break; - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12: - checkAlignment<8>(Loc, Val, Type); - or32le(Loc, (Val & 0xFF8) << 7); - break; - case R_AARCH64_LDST8_ABS_LO12_NC: - or32AArch64Imm(Loc, getBits(Val, 0, 11)); - break; - case R_AARCH64_LDST16_ABS_LO12_NC: - checkAlignment<2>(Loc, Val, Type); - or32AArch64Imm(Loc, getBits(Val, 1, 11)); - break; - case R_AARCH64_LDST32_ABS_LO12_NC: - checkAlignment<4>(Loc, Val, Type); - or32AArch64Imm(Loc, getBits(Val, 2, 11)); - break; - case R_AARCH64_LDST64_ABS_LO12_NC: - checkAlignment<8>(Loc, Val, Type); - or32AArch64Imm(Loc, getBits(Val, 3, 11)); - break; - case R_AARCH64_LDST128_ABS_LO12_NC: - checkAlignment<16>(Loc, Val, Type); - or32AArch64Imm(Loc, getBits(Val, 4, 11)); - break; - case R_AARCH64_MOVW_UABS_G0_NC: - or32le(Loc, (Val & 0xFFFF) << 5); - break; - case R_AARCH64_MOVW_UABS_G1_NC: - or32le(Loc, (Val & 0xFFFF0000) >> 11); - break; - case R_AARCH64_MOVW_UABS_G2_NC: - or32le(Loc, (Val & 0xFFFF00000000) >> 27); - break; - case R_AARCH64_MOVW_UABS_G3: - or32le(Loc, (Val & 0xFFFF000000000000) >> 43); - break; - case R_AARCH64_TSTBR14: - checkInt<16>(Loc, Val, Type); - or32le(Loc, (Val & 0xFFFC) << 3); - break; - case R_AARCH64_TLSLE_ADD_TPREL_HI12: - checkInt<24>(Loc, Val, Type); - or32AArch64Imm(Loc, Val >> 12); - break; - case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12: - or32AArch64Imm(Loc, Val); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // TLSDESC Global-Dynamic relocation are in the form: - // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] - // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] - // .tlsdesccall [R_AARCH64_TLSDESC_CALL] - // blr x1 - // And it can optimized to: - // movz x0, #0x0, lsl #16 - // movk x0, #0x10 - // nop - // nop - checkUInt<32>(Loc, Val, Type); - - switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12: - case R_AARCH64_TLSDESC_CALL: - write32le(Loc, 0xd503201f); // nop - return; - case R_AARCH64_TLSDESC_ADR_PAGE21: - write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz - return; - case R_AARCH64_TLSDESC_LD64_LO12: - write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk - return; - default: - llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); - } -} - -void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // TLSDESC Global-Dynamic relocation are in the form: - // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] - // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] - // .tlsdesccall [R_AARCH64_TLSDESC_CALL] - // blr x1 - // And it can optimized to: - // adrp x0, :gottprel:v - // ldr x0, [x0, :gottprel_lo12:v] - // nop - // nop - - switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12: - case R_AARCH64_TLSDESC_CALL: - write32le(Loc, 0xd503201f); // nop - break; - case R_AARCH64_TLSDESC_ADR_PAGE21: - write32le(Loc, 0x90000000); // adrp - relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); - break; - case R_AARCH64_TLSDESC_LD64_LO12: - write32le(Loc, 0xf9400000); // ldr - relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); - break; - default: - llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); - } -} - -void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - checkUInt<32>(Loc, Val, Type); - - if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { - // Generate MOVZ. - uint32_t RegNo = read32le(Loc) & 0x1f; - write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); - return; - } - if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { - // Generate MOVK. - uint32_t RegNo = read32le(Loc) & 0x1f; - write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); - return; - } - llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); -} - -TargetInfo *elf::getAArch64TargetInfo() { - static AArch64 Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AMDGPU.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AMDGPU.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AMDGPU.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AMDGPU.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -//===- AMDGPU.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class AMDGPU final : public TargetInfo { -public: - AMDGPU(); - uint32_t calcEFlags() const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; -}; -} // namespace - -AMDGPU::AMDGPU() { - RelativeRel = R_AMDGPU_RELATIVE64; - GotRel = R_AMDGPU_ABS64; - GotEntrySize = 8; -} - -static uint32_t getEFlags(InputFile *File) { - return cast>(File)->getObj().getHeader()->e_flags; -} - -uint32_t AMDGPU::calcEFlags() const { - assert(!ObjectFiles.empty()); - uint32_t Ret = getEFlags(ObjectFiles[0]); - - // Verify that all input files have the same e_flags. - for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) { - if (Ret == getEFlags(F)) - continue; - error("incompatible e_flags: " + toString(F)); - return 0; - } - return Ret; -} - -void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_AMDGPU_ABS32: - case R_AMDGPU_GOTPCREL: - case R_AMDGPU_GOTPCREL32_LO: - case R_AMDGPU_REL32: - case R_AMDGPU_REL32_LO: - write32le(Loc, Val); - break; - case R_AMDGPU_ABS64: - write64le(Loc, Val); - break; - case R_AMDGPU_GOTPCREL32_HI: - case R_AMDGPU_REL32_HI: - write32le(Loc, Val >> 32); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_AMDGPU_ABS32: - case R_AMDGPU_ABS64: - return R_ABS; - case R_AMDGPU_REL32: - case R_AMDGPU_REL32_LO: - case R_AMDGPU_REL32_HI: - return R_PC; - case R_AMDGPU_GOTPCREL: - case R_AMDGPU_GOTPCREL32_LO: - case R_AMDGPU_GOTPCREL32_HI: - return R_GOT_PC; - default: - return R_INVALID; - } -} - -TargetInfo *elf::getAMDGPUTargetInfo() { - static AMDGPU Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/ARM.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/ARM.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/ARM.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/ARM.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,583 +0,0 @@ -//===- ARM.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "Thunks.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class ARM final : public TargetInfo { -public: - ARM(); - uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; - RelType getDynRel(RelType Type) const override; - int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - void addPltSymbols(InputSection &IS, uint64_t Off) const override; - void addPltHeaderSymbols(InputSection &ISD) const override; - bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const override; - bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -ARM::ARM() { - CopyRel = R_ARM_COPY; - RelativeRel = R_ARM_RELATIVE; - IRelativeRel = R_ARM_IRELATIVE; - GotRel = R_ARM_GLOB_DAT; - PltRel = R_ARM_JUMP_SLOT; - TlsGotRel = R_ARM_TLS_TPOFF32; - TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; - TlsOffsetRel = R_ARM_TLS_DTPOFF32; - GotEntrySize = 4; - GotPltEntrySize = 4; - PltEntrySize = 16; - PltHeaderSize = 32; - TrapInstr = 0xd4d4d4d4; - // ARM uses Variant 1 TLS - TcbSize = 8; - NeedsThunks = true; - - // The placing of pre-created ThunkSections is controlled by the - // ThunkSectionSpacing parameter. The aim is to place the - // ThunkSection such that all branches from the InputSections prior to the - // ThunkSection can reach a Thunk placed at the end of the ThunkSection. - // Graphically: - // | up to ThunkSectionSpacing .text input sections | - // | ThunkSection | - // | up to ThunkSectionSpacing .text input sections | - // | ThunkSection | - - // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to - // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W - // ARM B, BL, BLX range +/- 32MiB - // Thumb B.W, BL, BLX range +/- 16MiB - // Thumb B.W range +/- 1MiB - // If a branch cannot reach a pre-created ThunkSection a new one will be - // created so we can handle the rare cases of a Thumb 2 conditional branch. - // We intentionally use a lower size for ThunkSectionSpacing than the maximum - // branch range so the end of the ThunkSection is more likely to be within - // range of the branch instruction that is furthest away. The value we shorten - // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 - // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to - // one of the Thunks going out of range. - - // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and - // J2 bits to be used to extend the branch range. On earlier Architectures - // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If - // support for the earlier encodings is added then when they are used the - // ThunkSectionSpacing will need lowering. - ThunkSectionSpacing = 0x1000000 - 0x30000; -} - -uint32_t ARM::calcEFlags() const { - // We don't currently use any features incompatible with EF_ARM_EABI_VER5, - // but we don't have any firm guarantees of conformance. Linux AArch64 - // kernels (as of 2016) require an EABI version to be set. - return EF_ARM_EABI_VER5; -} - -RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_ARM_THM_JUMP11: - return R_PC; - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_PREL31: - case R_ARM_THM_JUMP19: - case R_ARM_THM_JUMP24: - case R_ARM_THM_CALL: - return R_PLT_PC; - case R_ARM_GOTOFF32: - // (S + A) - GOT_ORG - return R_GOTREL; - case R_ARM_GOT_BREL: - // GOT(S) + A - GOT_ORG - return R_GOT_OFF; - case R_ARM_GOT_PREL: - case R_ARM_TLS_IE32: - // GOT(S) + A - P - return R_GOT_PC; - case R_ARM_SBREL32: - return R_ARM_SBREL; - case R_ARM_TARGET1: - return Config->Target1Rel ? R_PC : R_ABS; - case R_ARM_TARGET2: - if (Config->Target2 == Target2Policy::Rel) - return R_PC; - if (Config->Target2 == Target2Policy::Abs) - return R_ABS; - return R_GOT_PC; - case R_ARM_TLS_GD32: - return R_TLSGD_PC; - case R_ARM_TLS_LDM32: - return R_TLSLD_PC; - case R_ARM_BASE_PREL: - // B(S) + A - P - // FIXME: currently B(S) assumed to be .got, this may not hold for all - // platforms. - return R_GOTONLY_PC; - case R_ARM_MOVW_PREL_NC: - case R_ARM_MOVT_PREL: - case R_ARM_REL32: - case R_ARM_THM_MOVW_PREL_NC: - case R_ARM_THM_MOVT_PREL: - return R_PC; - case R_ARM_NONE: - return R_NONE; - case R_ARM_TLS_LE32: - return R_TLS; - default: - return R_ABS; - } -} - -bool ARM::isPicRel(RelType Type) const { - return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || - (Type == R_ARM_ABS32); -} - -RelType ARM::getDynRel(RelType Type) const { - if (Type == R_ARM_TARGET1 && !Config->Target1Rel) - return R_ARM_ABS32; - if (Type == R_ARM_ABS32) - return Type; - // Keep it going with a dummy value so that we can find more reloc errors. - return R_ARM_ABS32; -} - -void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { - write32le(Buf, InX::Plt->getVA()); -} - -void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { - // An ARM entry is the address of the ifunc resolver function. - write32le(Buf, S.getVA()); -} - -// Long form PLT Header that does not have any restrictions on the displacement -// of the .plt from the .plt.got. -static void writePltHeaderLong(uint8_t *Buf) { - const uint8_t PltData[] = { - 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! - 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 - 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr - 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] - 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 - 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary - 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary - 0xd4, 0xd4, 0xd4, 0xd4}; - memcpy(Buf, PltData, sizeof(PltData)); - uint64_t GotPlt = InX::GotPlt->getVA(); - uint64_t L1 = InX::Plt->getVA() + 8; - write32le(Buf + 16, GotPlt - L1 - 8); -} - -// The default PLT header requires the .plt.got to be within 128 Mb of the -// .plt in the positive direction. -void ARM::writePltHeader(uint8_t *Buf) const { - // Use a similar sequence to that in writePlt(), the difference is the calling - // conventions mean we use lr instead of ip. The PLT entry is responsible for - // saving lr on the stack, the dynamic loader is responsible for reloading - // it. - const uint32_t PltData[] = { - 0xe52de004, // L1: str lr, [sp,#-4]! - 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) - 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) - 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) - }; - - uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4; - if (!llvm::isUInt<27>(Offset)) { - // We cannot encode the Offset, use the long form. - writePltHeaderLong(Buf); - return; - } - write32le(Buf + 0, PltData[0]); - write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); - write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); - write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); - write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary - write32le(Buf + 20, TrapInstr); - write32le(Buf + 24, TrapInstr); - write32le(Buf + 28, TrapInstr); -} - -void ARM::addPltHeaderSymbols(InputSection &IS) const { - addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); - addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); -} - -// Long form PLT entries that do not have any restrictions on the displacement -// of the .plt from the .plt.got. -static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) { - const uint8_t PltData[] = { - 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 - 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc - 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] - 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 - }; - memcpy(Buf, PltData, sizeof(PltData)); - uint64_t L1 = PltEntryAddr + 4; - write32le(Buf + 12, GotPltEntryAddr - L1 - 8); -} - -// The default PLT entries require the .plt.got to be within 128 Mb of the -// .plt in the positive direction. -void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - // The PLT entry is similar to the example given in Appendix A of ELF for - // the Arm Architecture. Instead of using the Group Relocations to find the - // optimal rotation for the 8-bit immediate used in the add instructions we - // hard code the most compact rotations for simplicity. This saves a load - // instruction over the long plt sequences. - const uint32_t PltData[] = { - 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 - 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 - 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 - }; - - uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; - if (!llvm::isUInt<27>(Offset)) { - // We cannot encode the Offset, use the long form. - writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); - return; - } - write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); - write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); - write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); - write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary -} - -void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { - addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); - addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); -} - -bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const { - // If S is an undefined weak symbol and does not have a PLT entry then it - // will be resolved as a branch to the next instruction. - if (S.isUndefWeak() && !S.isInPlt()) - return false; - // A state change from ARM to Thumb and vice versa must go through an - // interworking thunk if the relocation type is not R_ARM_CALL or - // R_ARM_THM_CALL. - switch (Type) { - case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_JUMP24: - // Source is ARM, all PLT entries are ARM so no interworking required. - // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). - if (Expr == R_PC && ((S.getVA() & 1) == 1)) - return true; - LLVM_FALLTHROUGH; - case R_ARM_CALL: { - uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); - return !inBranchRange(Type, BranchAddr, Dst); - } - case R_ARM_THM_JUMP19: - case R_ARM_THM_JUMP24: - // Source is Thumb, all PLT entries are ARM so interworking is required. - // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). - if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) - return true; - LLVM_FALLTHROUGH; - case R_ARM_THM_CALL: { - uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); - return !inBranchRange(Type, BranchAddr, Dst); - } - } - return false; -} - -bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { - uint64_t Range; - uint64_t InstrSize; - - switch (Type) { - case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_JUMP24: - case R_ARM_CALL: - Range = 0x2000000; - InstrSize = 4; - break; - case R_ARM_THM_JUMP19: - Range = 0x100000; - InstrSize = 2; - break; - case R_ARM_THM_JUMP24: - case R_ARM_THM_CALL: - Range = 0x1000000; - InstrSize = 2; - break; - default: - return true; - } - // PC at Src is 2 instructions ahead, immediate of branch is signed - if (Src > Dst) - Range -= 2 * InstrSize; - else - Range += InstrSize; - - if ((Dst & 0x1) == 0) - // Destination is ARM, if ARM caller then Src is already 4-byte aligned. - // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure - // destination will be 4 byte aligned. - Src &= ~0x3; - else - // Bit 0 == 1 denotes Thumb state, it is not part of the range - Dst &= ~0x1; - - uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; - return Distance <= Range; -} - -void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_ARM_ABS32: - case R_ARM_BASE_PREL: - case R_ARM_GLOB_DAT: - case R_ARM_GOTOFF32: - case R_ARM_GOT_BREL: - case R_ARM_GOT_PREL: - case R_ARM_REL32: - case R_ARM_RELATIVE: - case R_ARM_SBREL32: - case R_ARM_TARGET1: - case R_ARM_TARGET2: - case R_ARM_TLS_GD32: - case R_ARM_TLS_IE32: - case R_ARM_TLS_LDM32: - case R_ARM_TLS_LDO32: - case R_ARM_TLS_LE32: - case R_ARM_TLS_TPOFF32: - case R_ARM_TLS_DTPOFF32: - write32le(Loc, Val); - break; - case R_ARM_TLS_DTPMOD32: - write32le(Loc, 1); - break; - case R_ARM_PREL31: - checkInt<31>(Loc, Val, Type); - write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); - break; - case R_ARM_CALL: - // R_ARM_CALL is used for BL and BLX instructions, depending on the - // value of bit 0 of Val, we must select a BL or BLX instruction - if (Val & 1) { - // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. - // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' - checkInt<26>(Loc, Val, Type); - write32le(Loc, 0xfa000000 | // opcode - ((Val & 2) << 23) | // H - ((Val >> 2) & 0x00ffffff)); // imm24 - break; - } - if ((read32le(Loc) & 0xfe000000) == 0xfa000000) - // BLX (always unconditional) instruction to an ARM Target, select an - // unconditional BL. - write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); - // fall through as BL encoding is shared with B - LLVM_FALLTHROUGH; - case R_ARM_JUMP24: - case R_ARM_PC24: - case R_ARM_PLT32: - checkInt<26>(Loc, Val, Type); - write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); - break; - case R_ARM_THM_JUMP11: - checkInt<12>(Loc, Val, Type); - write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); - break; - case R_ARM_THM_JUMP19: - // Encoding T3: Val = S:J2:J1:imm6:imm11:0 - checkInt<21>(Loc, Val, Type); - write16le(Loc, - (read16le(Loc) & 0xfbc0) | // opcode cond - ((Val >> 10) & 0x0400) | // S - ((Val >> 12) & 0x003f)); // imm6 - write16le(Loc + 2, - 0x8000 | // opcode - ((Val >> 8) & 0x0800) | // J2 - ((Val >> 5) & 0x2000) | // J1 - ((Val >> 1) & 0x07ff)); // imm11 - break; - case R_ARM_THM_CALL: - // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the - // value of bit 0 of Val, we must select a BL or BLX instruction - if ((Val & 1) == 0) { - // Ensure BLX destination is 4-byte aligned. As BLX instruction may - // only be two byte aligned. This must be done before overflow check - Val = alignTo(Val, 4); - } - // Bit 12 is 0 for BLX, 1 for BL - write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); - // Fall through as rest of encoding is the same as B.W - LLVM_FALLTHROUGH; - case R_ARM_THM_JUMP24: - // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 - // FIXME: Use of I1 and I2 require v6T2ops - checkInt<25>(Loc, Val, Type); - write16le(Loc, - 0xf000 | // opcode - ((Val >> 14) & 0x0400) | // S - ((Val >> 12) & 0x03ff)); // imm10 - write16le(Loc + 2, - (read16le(Loc + 2) & 0xd000) | // opcode - (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 - (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 - ((Val >> 1) & 0x07ff)); // imm11 - break; - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVW_PREL_NC: - write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | - (Val & 0x0fff)); - break; - case R_ARM_MOVT_ABS: - case R_ARM_MOVT_PREL: - checkInt<32>(Loc, Val, Type); - write32le(Loc, (read32le(Loc) & ~0x000f0fff) | - (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); - break; - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVT_PREL: - // Encoding T1: A = imm4:i:imm3:imm8 - checkInt<32>(Loc, Val, Type); - write16le(Loc, - 0xf2c0 | // opcode - ((Val >> 17) & 0x0400) | // i - ((Val >> 28) & 0x000f)); // imm4 - write16le(Loc + 2, - (read16le(Loc + 2) & 0x8f00) | // opcode - ((Val >> 12) & 0x7000) | // imm3 - ((Val >> 16) & 0x00ff)); // imm8 - break; - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVW_PREL_NC: - // Encoding T3: A = imm4:i:imm3:imm8 - write16le(Loc, - 0xf240 | // opcode - ((Val >> 1) & 0x0400) | // i - ((Val >> 12) & 0x000f)); // imm4 - write16le(Loc + 2, - (read16le(Loc + 2) & 0x8f00) | // opcode - ((Val << 4) & 0x7000) | // imm3 - (Val & 0x00ff)); // imm8 - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { - switch (Type) { - default: - return 0; - case R_ARM_ABS32: - case R_ARM_BASE_PREL: - case R_ARM_GOTOFF32: - case R_ARM_GOT_BREL: - case R_ARM_GOT_PREL: - case R_ARM_REL32: - case R_ARM_TARGET1: - case R_ARM_TARGET2: - case R_ARM_TLS_GD32: - case R_ARM_TLS_LDM32: - case R_ARM_TLS_LDO32: - case R_ARM_TLS_IE32: - case R_ARM_TLS_LE32: - return SignExtend64<32>(read32le(Buf)); - case R_ARM_PREL31: - return SignExtend64<31>(read32le(Buf)); - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PC24: - case R_ARM_PLT32: - return SignExtend64<26>(read32le(Buf) << 2); - case R_ARM_THM_JUMP11: - return SignExtend64<12>(read16le(Buf) << 1); - case R_ARM_THM_JUMP19: { - // Encoding T3: A = S:J2:J1:imm10:imm6:0 - uint16_t Hi = read16le(Buf); - uint16_t Lo = read16le(Buf + 2); - return SignExtend64<20>(((Hi & 0x0400) << 10) | // S - ((Lo & 0x0800) << 8) | // J2 - ((Lo & 0x2000) << 5) | // J1 - ((Hi & 0x003f) << 12) | // imm6 - ((Lo & 0x07ff) << 1)); // imm11:0 - } - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: { - // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 - // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) - // FIXME: I1 and I2 require v6T2ops - uint16_t Hi = read16le(Buf); - uint16_t Lo = read16le(Buf + 2); - return SignExtend64<24>(((Hi & 0x0400) << 14) | // S - (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 - (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 - ((Hi & 0x003ff) << 12) | // imm0 - ((Lo & 0x007ff) << 1)); // imm11:0 - } - // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and - // MOVT is in the range -32768 <= A < 32768 - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_PREL_NC: - case R_ARM_MOVT_PREL: { - uint64_t Val = read32le(Buf) & 0x000f0fff; - return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); - } - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_PREL_NC: - case R_ARM_THM_MOVT_PREL: { - // Encoding T3: A = imm4:i:imm3:imm8 - uint16_t Hi = read16le(Buf); - uint16_t Lo = read16le(Buf + 2); - return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 - ((Hi & 0x0400) << 1) | // i - ((Lo & 0x7000) >> 4) | // imm3 - (Lo & 0x00ff)); // imm8 - } - } -} - -TargetInfo *elf::getARMTargetInfo() { - static ARM Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AVR.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AVR.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/AVR.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/AVR.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -//===- AVR.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// AVR is a Harvard-architecture 8-bit micrcontroller designed for small -// baremetal programs. All AVR-family processors have 32 8-bit registers. -// The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest -// one supports up to 2^24 data address space and 2^22 code address space. -// -// Since it is a baremetal programming, there's usually no loader to load -// ELF files on AVRs. You are expected to link your program against address -// 0 and pull out a .text section from the result using objcopy, so that you -// can write the linked code to on-chip flush memory. You can do that with -// the following commands: -// -// ld.lld -Ttext=0 -o foo foo.o -// objcopy -O binary --only-section=.text foo output.bin -// -// Note that the current AVR support is very preliminary so you can't -// link any useful program yet, though. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class AVR final : public TargetInfo { -public: - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -RelExpr AVR::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - return R_ABS; -} - -void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_AVR_CALL: { - uint16_t Hi = Val >> 17; - uint16_t Lo = Val >> 1; - write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); - write16le(Loc + 2, Lo); - break; - } - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); - } -} - -TargetInfo *elf::getAVRTargetInfo() { - static AVR Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/MipsArchTree.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/MipsArchTree.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/MipsArchTree.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/MipsArchTree.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,383 +0,0 @@ -//===- MipsArchTree.cpp --------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// -// -// This file contains a helper function for the Writer. -// -//===---------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "SymbolTable.h" -#include "Writer.h" - -#include "lld/Common/ErrorHandler.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/MipsABIFlags.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::ELF; - -using namespace lld; -using namespace lld::elf; - -namespace { -struct ArchTreeEdge { - uint32_t Child; - uint32_t Parent; -}; - -struct FileFlags { - InputFile *File; - uint32_t Flags; -}; -} // namespace - -static StringRef getAbiName(uint32_t Flags) { - switch (Flags) { - case 0: - return "n64"; - case EF_MIPS_ABI2: - return "n32"; - case EF_MIPS_ABI_O32: - return "o32"; - case EF_MIPS_ABI_O64: - return "o64"; - case EF_MIPS_ABI_EABI32: - return "eabi32"; - case EF_MIPS_ABI_EABI64: - return "eabi64"; - default: - return "unknown"; - } -} - -static StringRef getNanName(bool IsNan2008) { - return IsNan2008 ? "2008" : "legacy"; -} - -static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } - -static void checkFlags(ArrayRef Files) { - uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - bool Nan = Files[0].Flags & EF_MIPS_NAN2008; - bool Fp = Files[0].Flags & EF_MIPS_FP64; - - for (const FileFlags &F : Files.slice(1)) { - uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - if (ABI != ABI2) - error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + toString(F.File)); - - bool Nan2 = F.Flags & EF_MIPS_NAN2008; - if (Nan != Nan2) - error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + toString(F.File)); - - bool Fp2 = F.Flags & EF_MIPS_FP64; - if (Fp != Fp2) - error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + toString(F.File)); - } -} - -static uint32_t getMiscFlags(ArrayRef Files) { - uint32_t Ret = 0; - for (const FileFlags &F : Files) - Ret |= F.Flags & - (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | - EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); - return Ret; -} - -static uint32_t getPicFlags(ArrayRef Files) { - // Check PIC/non-PIC compatibility. - bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) { - bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - if (IsPic && !IsPic2) - warn("linking abicalls code " + toString(Files[0].File) + - " with non-abicalls file: " + toString(F.File)); - if (!IsPic && IsPic2) - warn("linking non-abicalls code " + toString(Files[0].File) + - " with abicalls file: " + toString(F.File)); - } - - // Compute the result PIC/non-PIC flag. - uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) - Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - - // PIC code is inherently CPIC and may not set CPIC flag explicitly. - if (Ret & EF_MIPS_PIC) - Ret |= EF_MIPS_CPIC; - return Ret; -} - -static ArchTreeEdge ArchTree[] = { - // MIPS32R6 and MIPS64R6 are not compatible with other extensions - // MIPS64R2 extensions. - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, - // MIPS64 extensions. - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, - // MIPS V extensions. - {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, - // R5000 extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, - // MIPS IV extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, - // VR4100 extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - // MIPS III extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, - // MIPS32 extensions. - {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, - // MIPS II extensions. - {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, - {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, - // MIPS I extensions. - {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, - {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, -}; - -static bool isArchMatched(uint32_t New, uint32_t Res) { - if (New == Res) - return true; - if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) - return true; - if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) - return true; - for (const auto &Edge : ArchTree) { - if (Res == Edge.Child) { - Res = Edge.Parent; - if (Res == New) - return true; - } - } - return false; -} - -static StringRef getMachName(uint32_t Flags) { - switch (Flags & EF_MIPS_MACH) { - case EF_MIPS_MACH_NONE: - return ""; - case EF_MIPS_MACH_3900: - return "r3900"; - case EF_MIPS_MACH_4010: - return "r4010"; - case EF_MIPS_MACH_4100: - return "r4100"; - case EF_MIPS_MACH_4650: - return "r4650"; - case EF_MIPS_MACH_4120: - return "r4120"; - case EF_MIPS_MACH_4111: - return "r4111"; - case EF_MIPS_MACH_5400: - return "vr5400"; - case EF_MIPS_MACH_5900: - return "vr5900"; - case EF_MIPS_MACH_5500: - return "vr5500"; - case EF_MIPS_MACH_9000: - return "rm9000"; - case EF_MIPS_MACH_LS2E: - return "loongson2e"; - case EF_MIPS_MACH_LS2F: - return "loongson2f"; - case EF_MIPS_MACH_LS3A: - return "loongson3a"; - case EF_MIPS_MACH_OCTEON: - return "octeon"; - case EF_MIPS_MACH_OCTEON2: - return "octeon2"; - case EF_MIPS_MACH_OCTEON3: - return "octeon3"; - case EF_MIPS_MACH_SB1: - return "sb1"; - case EF_MIPS_MACH_XLR: - return "xlr"; - default: - return "unknown machine"; - } -} - -static StringRef getArchName(uint32_t Flags) { - switch (Flags & EF_MIPS_ARCH) { - case EF_MIPS_ARCH_1: - return "mips1"; - case EF_MIPS_ARCH_2: - return "mips2"; - case EF_MIPS_ARCH_3: - return "mips3"; - case EF_MIPS_ARCH_4: - return "mips4"; - case EF_MIPS_ARCH_5: - return "mips5"; - case EF_MIPS_ARCH_32: - return "mips32"; - case EF_MIPS_ARCH_64: - return "mips64"; - case EF_MIPS_ARCH_32R2: - return "mips32r2"; - case EF_MIPS_ARCH_64R2: - return "mips64r2"; - case EF_MIPS_ARCH_32R6: - return "mips32r6"; - case EF_MIPS_ARCH_64R6: - return "mips64r6"; - default: - return "unknown arch"; - } -} - -static std::string getFullArchName(uint32_t Flags) { - StringRef Arch = getArchName(Flags); - StringRef Mach = getMachName(Flags); - if (Mach.empty()) - return Arch.str(); - return (Arch + " (" + Mach + ")").str(); -} - -// There are (arguably too) many MIPS ISAs out there. Their relationships -// can be represented as a forest. If all input files have ISAs which -// reachable by repeated proceeding from the single child to the parent, -// these input files are compatible. In that case we need to return "highest" -// ISA. If there are incompatible input files, we show an error. -// For example, mips1 is a "parent" of mips2 and such files are compatible. -// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 -// are incompatible because nor mips3 is a parent for misp32, nor mips32 -// is a parent for mips3. -static uint32_t getArchFlags(ArrayRef Files) { - uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - for (const FileFlags &F : Files.slice(1)) { - uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - // Check ISA compatibility. - if (isArchMatched(New, Ret)) - continue; - if (!isArchMatched(Ret, New)) { - error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " + - getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " + - getFullArchName(New)); - return 0; - } - Ret = New; - } - return Ret; -} - -template uint32_t elf::calcMipsEFlags() { - std::vector V; - for (InputFile *F : ObjectFiles) - V.push_back({F, cast>(F)->getObj().getHeader()->e_flags}); - if (V.empty()) - return 0; - checkFlags(V); - return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); -} - -static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { - if (FpA == FpB) - return 0; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) - return 1; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && - FpA == Mips::Val_GNU_MIPS_ABI_FP_64) - return 1; - if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) - return -1; - if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) - return 1; - return -1; -} - -static StringRef getMipsFpAbiName(uint8_t FpAbi) { - switch (FpAbi) { - case Mips::Val_GNU_MIPS_ABI_FP_ANY: - return "any"; - case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: - return "-mdouble-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: - return "-msingle-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SOFT: - return "-msoft-float"; - case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; - case Mips::Val_GNU_MIPS_ABI_FP_XX: - return "-mfpxx"; - case Mips::Val_GNU_MIPS_ABI_FP_64: - return "-mgp32 -mfp64"; - case Mips::Val_GNU_MIPS_ABI_FP_64A: - return "-mgp32 -mfp64 -mno-odd-spreg"; - default: - return "unknown"; - } -} - -uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, - StringRef FileName) { - if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) - return NewFlag; - if (compareMipsFpAbi(OldFlag, NewFlag) < 0) - error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + - "': " + FileName); - return OldFlag; -} - -template static bool isN32Abi(const InputFile *F) { - if (auto *EF = dyn_cast>(F)) - return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; - return false; -} - -bool elf::isMipsN32Abi(const InputFile *F) { - switch (Config->EKind) { - case ELF32LEKind: - return isN32Abi(F); - case ELF32BEKind: - return isN32Abi(F); - case ELF64LEKind: - return isN32Abi(F); - case ELF64BEKind: - return isN32Abi(F); - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; } - -bool elf::isMipsR6() { - uint32_t Arch = Config->EFlags & EF_MIPS_ARCH; - return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; -} - -template uint32_t elf::calcMipsEFlags(); -template uint32_t elf::calcMipsEFlags(); -template uint32_t elf::calcMipsEFlags(); -template uint32_t elf::calcMipsEFlags(); diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/Mips.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/Mips.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/Mips.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/Mips.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,682 +0,0 @@ -//===- MIPS.cpp -----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "OutputSections.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "Thunks.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -template class MIPS final : public TargetInfo { -public: - MIPS(); - uint32_t calcEFlags() const override; - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; - bool isPicRel(RelType Type) const override; - RelType getDynRel(RelType Type) const override; - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - bool usesOnlyLowPageBits(RelType Type) const override; -}; -} // namespace - -template MIPS::MIPS() { - GotPltHeaderEntriesNum = 2; - DefaultMaxPageSize = 65536; - GotEntrySize = sizeof(typename ELFT::uint); - GotPltEntrySize = sizeof(typename ELFT::uint); - PltEntrySize = 16; - PltHeaderSize = 32; - CopyRel = R_MIPS_COPY; - PltRel = R_MIPS_JUMP_SLOT; - NeedsThunks = true; - TrapInstr = 0xefefefef; - - if (ELFT::Is64Bits) { - RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; - TlsGotRel = R_MIPS_TLS_TPREL64; - TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; - TlsOffsetRel = R_MIPS_TLS_DTPREL64; - } else { - RelativeRel = R_MIPS_REL32; - TlsGotRel = R_MIPS_TLS_TPREL32; - TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; - TlsOffsetRel = R_MIPS_TLS_DTPREL32; - } -} - -template uint32_t MIPS::calcEFlags() const { - return calcMipsEFlags(); -} - -template -RelExpr MIPS::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - // See comment in the calculateMipsRelChain. - if (ELFT::Is64Bits || Config->MipsN32Abi) - Type &= 0xff; - - switch (Type) { - case R_MIPS_JALR: - case R_MICROMIPS_JALR: - return R_HINT; - case R_MIPS_GPREL16: - case R_MIPS_GPREL32: - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_GPREL7_S2: - return R_MIPS_GOTREL; - case R_MIPS_26: - case R_MICROMIPS_26_S1: - return R_PLT; - case R_MICROMIPS_PC26_S1: - return R_PLT_PC; - case R_MIPS_HI16: - case R_MIPS_LO16: - case R_MIPS_HIGHER: - case R_MIPS_HIGHEST: - case R_MICROMIPS_HI16: - case R_MICROMIPS_LO16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: - // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate - // offset between start of function and 'gp' value which by default - // equal to the start of .got section. In that case we consider these - // relocations as relative. - if (&S == ElfSym::MipsGpDisp) - return R_MIPS_GOT_GP_PC; - if (&S == ElfSym::MipsLocalGp) - return R_MIPS_GOT_GP; - LLVM_FALLTHROUGH; - case R_MIPS_32: - case R_MIPS_64: - case R_MIPS_GOT_OFST: - case R_MIPS_SUB: - case R_MIPS_TLS_DTPREL_HI16: - case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_DTPREL64: - case R_MIPS_TLS_TPREL_HI16: - case R_MIPS_TLS_TPREL_LO16: - case R_MIPS_TLS_TPREL32: - case R_MIPS_TLS_TPREL64: - case R_MICROMIPS_GOT_OFST: - case R_MICROMIPS_SUB: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_DTPREL_LO16: - case R_MICROMIPS_TLS_TPREL_HI16: - case R_MICROMIPS_TLS_TPREL_LO16: - return R_ABS; - case R_MIPS_PC32: - case R_MIPS_PC16: - case R_MIPS_PC19_S2: - case R_MIPS_PC21_S2: - case R_MIPS_PC26_S2: - case R_MIPS_PCHI16: - case R_MIPS_PCLO16: - case R_MICROMIPS_PC7_S1: - case R_MICROMIPS_PC10_S1: - case R_MICROMIPS_PC16_S1: - case R_MICROMIPS_PC18_S3: - case R_MICROMIPS_PC19_S2: - case R_MICROMIPS_PC23_S2: - case R_MICROMIPS_PC21_S1: - return R_PC; - case R_MIPS_GOT16: - case R_MICROMIPS_GOT16: - if (S.isLocal()) - return R_MIPS_GOT_LOCAL_PAGE; - LLVM_FALLTHROUGH; - case R_MIPS_CALL16: - case R_MIPS_GOT_DISP: - case R_MIPS_TLS_GOTTPREL: - case R_MICROMIPS_CALL16: - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_TLS_GOTTPREL: - return R_MIPS_GOT_OFF; - case R_MIPS_CALL_HI16: - case R_MIPS_CALL_LO16: - case R_MIPS_GOT_HI16: - case R_MIPS_GOT_LO16: - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_GOT_HI16: - case R_MICROMIPS_GOT_LO16: - return R_MIPS_GOT_OFF32; - case R_MIPS_GOT_PAGE: - case R_MICROMIPS_GOT_PAGE: - return R_MIPS_GOT_LOCAL_PAGE; - case R_MIPS_TLS_GD: - case R_MICROMIPS_TLS_GD: - return R_MIPS_TLSGD; - case R_MIPS_TLS_LDM: - case R_MICROMIPS_TLS_LDM: - return R_MIPS_TLSLD; - case R_MIPS_NONE: - return R_NONE; - default: - return R_INVALID; - } -} - -template bool MIPS::isPicRel(RelType Type) const { - return Type == R_MIPS_32 || Type == R_MIPS_64; -} - -template RelType MIPS::getDynRel(RelType Type) const { - return RelativeRel; -} - -template -void MIPS::writeGotPlt(uint8_t *Buf, const Symbol &) const { - uint64_t VA = InX::Plt->getVA(); - if (isMicroMips()) - VA |= 1; - write32(Buf, VA); -} - -template static uint32_t readShuffle(const uint8_t *Loc) { - // The major opcode of a microMIPS instruction needs to appear - // in the first 16-bit word (lowest address) for efficient hardware - // decode so that it knows if the instruction is 16-bit or 32-bit - // as early as possible. To do so, little-endian binaries keep 16-bit - // words in a big-endian order. That is why we have to swap these - // words to get a correct value. - uint32_t V = read32(Loc); - if (E == support::little) - return (V << 16) | (V >> 16); - return V; -} - -template -static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { - uint32_t Instr = read32(Loc); - uint32_t Mask = 0xffffffff >> (32 - BitsSize); - uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); - write32(Loc, Data); -} - -template -static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { - // See comments in readShuffle for purpose of this code. - uint16_t *Words = (uint16_t *)Loc; - if (E == support::little) - std::swap(Words[0], Words[1]); - - writeRelocation(Loc, V, BitsSize, Shift); - - if (E == support::little) - std::swap(Words[0], Words[1]); -} - -template -static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { - uint16_t Instr = read16(Loc); - uint16_t Mask = 0xffff >> (16 - BitsSize); - uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); - write16(Loc, Data); -} - -template void MIPS::writePltHeader(uint8_t *Buf) const { - const endianness E = ELFT::TargetEndianness; - if (isMicroMips()) { - uint64_t GotPlt = InX::GotPlt->getVA(); - uint64_t Plt = InX::Plt->getVA(); - // Overwrite trap instructions written by Writer::writeTrapInstr. - memset(Buf, 0, PltHeaderSize); - - write16(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . - write16(Buf + 4, 0xff23); // lw $25, 0($3) - write16(Buf + 8, 0x0535); // subu16 $2, $2, $3 - write16(Buf + 10, 0x2525); // srl16 $2, $2, 2 - write16(Buf + 12, 0x3302); // addiu $24, $2, -2 - write16(Buf + 14, 0xfffe); - write16(Buf + 16, 0x0dff); // move $15, $31 - if (isMipsR6()) { - write16(Buf + 18, 0x0f83); // move $28, $3 - write16(Buf + 20, 0x472b); // jalrc $25 - write16(Buf + 22, 0x0c00); // nop - relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt); - } else { - write16(Buf + 18, 0x45f9); // jalrc $25 - write16(Buf + 20, 0x0f83); // move $28, $3 - write16(Buf + 22, 0x0c00); // nop - relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt); - } - return; - } - - if (Config->MipsN32Abi) { - write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) - write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) - write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) - write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 - write32(Buf + 16, 0x03e07825); // move $15, $31 - write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 - } else if (ELFT::Is64Bits) { - write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) - write32(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) - write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) - write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 - write32(Buf + 16, 0x03e07825); // move $15, $31 - write32(Buf + 20, 0x0018c0c2); // srl $24, $24, 3 - } else { - write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) - write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) - write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) - write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 - write32(Buf + 16, 0x03e07825); // move $15, $31 - write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 - } - - write32(Buf + 24, 0x0320f809); // jalr $25 - write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 - - uint64_t GotPlt = InX::GotPlt->getVA(); - writeRelocation(Buf, GotPlt + 0x8000, 16, 16); - writeRelocation(Buf + 4, GotPlt, 16, 0); - writeRelocation(Buf + 8, GotPlt, 16, 0); -} - -template -void MIPS::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const endianness E = ELFT::TargetEndianness; - if (isMicroMips()) { - // Overwrite trap instructions written by Writer::writeTrapInstr. - memset(Buf, 0, PltEntrySize); - - if (isMipsR6()) { - write16(Buf, 0x7840); // addiupc $2, (GOTPLT) - . - write16(Buf + 4, 0xff22); // lw $25, 0($2) - write16(Buf + 8, 0x0f02); // move $24, $2 - write16(Buf + 10, 0x4723); // jrc $25 / jr16 $25 - relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr); - } else { - write16(Buf, 0x7900); // addiupc $2, (GOTPLT) - . - write16(Buf + 4, 0xff22); // lw $25, 0($2) - write16(Buf + 8, 0x4599); // jrc $25 / jr16 $25 - write16(Buf + 10, 0x0f02); // move $24, $2 - relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr); - } - return; - } - - write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) - write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) - write32(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25 - write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) - writeRelocation(Buf, GotPltEntryAddr + 0x8000, 16, 16); - writeRelocation(Buf + 4, GotPltEntryAddr, 16, 0); - writeRelocation(Buf + 12, GotPltEntryAddr, 16, 0); -} - -template -bool MIPS::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, - uint64_t BranchAddr, const Symbol &S) const { - // Any MIPS PIC code function is invoked with its address in register $t9. - // So if we have a branch instruction from non-PIC code to the PIC one - // we cannot make the jump directly and need to create a small stubs - // to save the target function address. - // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 && - Type != R_MICROMIPS_PC26_S1) - return false; - auto *F = dyn_cast_or_null>(File); - if (!F) - return false; - // If current file has PIC code, LA25 stub is not required. - if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) - return false; - auto *D = dyn_cast(&S); - // LA25 is required if target file has PIC code - // or target symbol is a PIC symbol. - return D && isMipsPIC(D); -} - -template -int64_t MIPS::getImplicitAddend(const uint8_t *Buf, RelType Type) const { - const endianness E = ELFT::TargetEndianness; - switch (Type) { - case R_MIPS_32: - case R_MIPS_GPREL32: - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_TPREL32: - return SignExtend64<32>(read32(Buf)); - case R_MIPS_26: - // FIXME (simon): If the relocation target symbol is not a PLT entry - // we should use another expression for calculation: - // ((A << 2) | (P & 0xf0000000)) >> 2 - return SignExtend64<28>(read32(Buf) << 2); - case R_MIPS_GOT16: - case R_MIPS_HI16: - case R_MIPS_PCHI16: - return SignExtend64<16>(read32(Buf)) << 16; - case R_MIPS_GPREL16: - case R_MIPS_LO16: - case R_MIPS_PCLO16: - case R_MIPS_TLS_DTPREL_HI16: - case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_TPREL_HI16: - case R_MIPS_TLS_TPREL_LO16: - return SignExtend64<16>(read32(Buf)); - case R_MICROMIPS_GOT16: - case R_MICROMIPS_HI16: - return SignExtend64<16>(readShuffle(Buf)) << 16; - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_LO16: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_DTPREL_LO16: - case R_MICROMIPS_TLS_TPREL_HI16: - case R_MICROMIPS_TLS_TPREL_LO16: - return SignExtend64<16>(readShuffle(Buf)); - case R_MICROMIPS_GPREL7_S2: - return SignExtend64<9>(readShuffle(Buf) << 2); - case R_MIPS_PC16: - return SignExtend64<18>(read32(Buf) << 2); - case R_MIPS_PC19_S2: - return SignExtend64<21>(read32(Buf) << 2); - case R_MIPS_PC21_S2: - return SignExtend64<23>(read32(Buf) << 2); - case R_MIPS_PC26_S2: - return SignExtend64<28>(read32(Buf) << 2); - case R_MIPS_PC32: - return SignExtend64<32>(read32(Buf)); - case R_MICROMIPS_26_S1: - return SignExtend64<27>(readShuffle(Buf) << 1); - case R_MICROMIPS_PC7_S1: - return SignExtend64<8>(read16(Buf) << 1); - case R_MICROMIPS_PC10_S1: - return SignExtend64<11>(read16(Buf) << 1); - case R_MICROMIPS_PC16_S1: - return SignExtend64<17>(readShuffle(Buf) << 1); - case R_MICROMIPS_PC18_S3: - return SignExtend64<21>(readShuffle(Buf) << 3); - case R_MICROMIPS_PC19_S2: - return SignExtend64<21>(readShuffle(Buf) << 2); - case R_MICROMIPS_PC21_S1: - return SignExtend64<22>(readShuffle(Buf) << 1); - case R_MICROMIPS_PC23_S2: - return SignExtend64<25>(readShuffle(Buf) << 2); - case R_MICROMIPS_PC26_S1: - return SignExtend64<27>(readShuffle(Buf) << 1); - default: - return 0; - } -} - -static std::pair -calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { - // MIPS N64 ABI packs multiple relocations into the single relocation - // record. In general, all up to three relocations can have arbitrary - // types. In fact, Clang and GCC uses only a few combinations. For now, - // we support two of them. That is allow to pass at least all LLVM - // test suite cases. - // / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 - // / R_MIPS_64 / R_MIPS_NONE - // The first relocation is a 'real' relocation which is calculated - // using the corresponding symbol's value. The second and the third - // relocations used to modify result of the first one: extend it to - // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation - // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf - RelType Type2 = (Type >> 8) & 0xff; - RelType Type3 = (Type >> 16) & 0xff; - if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) - return std::make_pair(Type, Val); - if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) - return std::make_pair(Type2, Val); - if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) - return std::make_pair(Type3, -Val); - if (Type2 == R_MICROMIPS_SUB && - (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16)) - return std::make_pair(Type3, -Val); - error(getErrorLocation(Loc) + "unsupported relocations combination " + - Twine(Type)); - return std::make_pair(Type & 0xff, Val); -} - -template -void MIPS::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - const endianness E = ELFT::TargetEndianness; - - // Thread pointer and DRP offsets from the start of TLS data area. - // https://www.linux-mips.org/wiki/NPTL - if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || - Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 || - Type == R_MICROMIPS_TLS_DTPREL_HI16 || - Type == R_MICROMIPS_TLS_DTPREL_LO16) { - Val -= 0x8000; - } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || - Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 || - Type == R_MICROMIPS_TLS_TPREL_HI16 || - Type == R_MICROMIPS_TLS_TPREL_LO16) { - Val -= 0x7000; - } - - if (ELFT::Is64Bits || Config->MipsN32Abi) - std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); - - switch (Type) { - case R_MIPS_32: - case R_MIPS_GPREL32: - case R_MIPS_TLS_DTPREL32: - case R_MIPS_TLS_TPREL32: - write32(Loc, Val); - break; - case R_MIPS_64: - case R_MIPS_TLS_DTPREL64: - case R_MIPS_TLS_TPREL64: - write64(Loc, Val); - break; - case R_MIPS_26: - writeRelocation(Loc, Val, 26, 2); - break; - case R_MIPS_GOT16: - // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode - // is updated addend (not a GOT index). In that case write high 16 bits - // to store a correct addend value. - if (Config->Relocatable) { - writeRelocation(Loc, Val + 0x8000, 16, 16); - } else { - checkInt<16>(Loc, Val, Type); - writeRelocation(Loc, Val, 16, 0); - } - break; - case R_MICROMIPS_GOT16: - if (Config->Relocatable) { - writeMicroRelocation32(Loc, Val + 0x8000, 16, 16); - } else { - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 0); - } - break; - case R_MIPS_CALL16: - case R_MIPS_GOT_DISP: - case R_MIPS_GOT_PAGE: - case R_MIPS_GPREL16: - case R_MIPS_TLS_GD: - case R_MIPS_TLS_GOTTPREL: - case R_MIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); - LLVM_FALLTHROUGH; - case R_MIPS_CALL_LO16: - case R_MIPS_GOT_LO16: - case R_MIPS_GOT_OFST: - case R_MIPS_LO16: - case R_MIPS_PCLO16: - case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_TPREL_LO16: - writeRelocation(Loc, Val, 16, 0); - break; - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_GOT_PAGE: - case R_MICROMIPS_GPREL16: - case R_MICROMIPS_TLS_GD: - case R_MICROMIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 0); - break; - case R_MICROMIPS_CALL16: - case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_GOT_OFST: - case R_MICROMIPS_LO16: - case R_MICROMIPS_TLS_DTPREL_LO16: - case R_MICROMIPS_TLS_GOTTPREL: - case R_MICROMIPS_TLS_TPREL_LO16: - writeMicroRelocation32(Loc, Val, 16, 0); - break; - case R_MICROMIPS_GPREL7_S2: - checkInt<7>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 7, 2); - break; - case R_MIPS_CALL_HI16: - case R_MIPS_GOT_HI16: - case R_MIPS_HI16: - case R_MIPS_PCHI16: - case R_MIPS_TLS_DTPREL_HI16: - case R_MIPS_TLS_TPREL_HI16: - writeRelocation(Loc, Val + 0x8000, 16, 16); - break; - case R_MICROMIPS_CALL_HI16: - case R_MICROMIPS_GOT_HI16: - case R_MICROMIPS_HI16: - case R_MICROMIPS_TLS_DTPREL_HI16: - case R_MICROMIPS_TLS_TPREL_HI16: - writeMicroRelocation32(Loc, Val + 0x8000, 16, 16); - break; - case R_MIPS_HIGHER: - writeRelocation(Loc, Val + 0x80008000, 16, 32); - break; - case R_MIPS_HIGHEST: - writeRelocation(Loc, Val + 0x800080008000, 16, 48); - break; - case R_MICROMIPS_HIGHER: - writeMicroRelocation32(Loc, Val + 0x80008000, 16, 32); - break; - case R_MICROMIPS_HIGHEST: - writeMicroRelocation32(Loc, Val + 0x800080008000, 16, 48); - break; - case R_MIPS_JALR: - case R_MICROMIPS_JALR: - // Ignore this optimization relocation for now - break; - case R_MIPS_PC16: - checkAlignment<4>(Loc, Val, Type); - checkInt<18>(Loc, Val, Type); - writeRelocation(Loc, Val, 16, 2); - break; - case R_MIPS_PC19_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); - writeRelocation(Loc, Val, 19, 2); - break; - case R_MIPS_PC21_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<23>(Loc, Val, Type); - writeRelocation(Loc, Val, 21, 2); - break; - case R_MIPS_PC26_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<28>(Loc, Val, Type); - writeRelocation(Loc, Val, 26, 2); - break; - case R_MIPS_PC32: - writeRelocation(Loc, Val, 32, 0); - break; - case R_MICROMIPS_26_S1: - case R_MICROMIPS_PC26_S1: - checkInt<27>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 26, 1); - break; - case R_MICROMIPS_PC7_S1: - checkInt<8>(Loc, Val, Type); - writeMicroRelocation16(Loc, Val, 7, 1); - break; - case R_MICROMIPS_PC10_S1: - checkInt<11>(Loc, Val, Type); - writeMicroRelocation16(Loc, Val, 10, 1); - break; - case R_MICROMIPS_PC16_S1: - checkInt<17>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 1); - break; - case R_MICROMIPS_PC18_S3: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 18, 3); - break; - case R_MICROMIPS_PC19_S2: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 19, 2); - break; - case R_MICROMIPS_PC21_S1: - checkInt<22>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 21, 1); - break; - case R_MICROMIPS_PC23_S2: - checkInt<25>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 23, 2); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -template bool MIPS::usesOnlyLowPageBits(RelType Type) const { - return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || - Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST; -} - -// Return true if the symbol is a PIC function. -template bool elf::isMipsPIC(const Defined *Sym) { - typedef typename ELFT::Ehdr Elf_Ehdr; - if (!Sym->Section || !Sym->isFunc()) - return false; - - auto *Sec = cast(Sym->Section); - const Elf_Ehdr *Hdr = Sec->template getFile()->getObj().getHeader(); - return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (Hdr->e_flags & EF_MIPS_PIC); -} - -template TargetInfo *elf::getMipsTargetInfo() { - static MIPS Target; - return &Target; -} - -template TargetInfo *elf::getMipsTargetInfo(); -template TargetInfo *elf::getMipsTargetInfo(); -template TargetInfo *elf::getMipsTargetInfo(); -template TargetInfo *elf::getMipsTargetInfo(); - -template bool elf::isMipsPIC(const Defined *); -template bool elf::isMipsPIC(const Defined *); -template bool elf::isMipsPIC(const Defined *); -template bool elf::isMipsPIC(const Defined *); diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC64.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC64.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC64.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC64.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,217 +0,0 @@ -//===- PPC64.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -static uint64_t PPC64TocOffset = 0x8000; - -uint64_t elf::getPPC64TocBase() { - // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The - // TOC starts where the first of these sections starts. We always create a - // .got when we see a relocation that uses it, so for us the start is always - // the .got. - uint64_t TocVA = InX::Got->getVA(); - - // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 - // thus permitting a full 64 Kbytes segment. Note that the glibc startup - // code (crt1.o) assumes that you can get from the TOC base to the - // start of the .toc section with only a single (signed) 16-bit relocation. - return TocVA + PPC64TocOffset; -} - -namespace { -class PPC64 final : public TargetInfo { -public: - PPC64(); - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -// Relocation masks following the #lo(value), #hi(value), #ha(value), -// #higher(value), #highera(value), #highest(value), and #highesta(value) -// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi -// document. -static uint16_t applyPPCLo(uint64_t V) { return V; } -static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } -static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } -static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } -static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } -static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } -static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } - -PPC64::PPC64() { - PltRel = GotRel = R_PPC64_GLOB_DAT; - RelativeRel = R_PPC64_RELATIVE; - GotEntrySize = 8; - GotPltEntrySize = 8; - PltEntrySize = 32; - PltHeaderSize = 0; - - // We need 64K pages (at least under glibc/Linux, the loader won't - // set different permissions on a finer granularity than that). - DefaultMaxPageSize = 65536; - - // The PPC64 ELF ABI v1 spec, says: - // - // It is normally desirable to put segments with different characteristics - // in separate 256 Mbyte portions of the address space, to give the - // operating system full paging flexibility in the 64-bit address space. - // - // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers - // use 0x10000000 as the starting address. - DefaultImageBase = 0x10000000; -} - -RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_PPC64_TOC16: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_LO_DS: - return R_GOTREL; - case R_PPC64_TOC: - return R_PPC_TOC; - case R_PPC64_REL24: - return R_PPC_PLT_OPD; - default: - return R_ABS; - } -} - -void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); - - // FIXME: What we should do, in theory, is get the offset of the function - // descriptor in the .opd section, and use that as the offset from %r2 (the - // TOC-base pointer). Instead, we have the GOT-entry offset, and that will - // be a pointer to the function descriptor in the .opd section. Using - // this scheme is simpler, but requires an extra indirection per PLT dispatch. - - write32be(Buf, 0xf8410028); // std %r2, 40(%r1) - write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha - write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) - write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) - write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 - write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) - write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) - write32be(Buf + 28, 0x4e800420); // bctr -} - -static std::pair toAddr16Rel(RelType Type, uint64_t Val) { - uint64_t V = Val - PPC64TocOffset; - switch (Type) { - case R_PPC64_TOC16: - return {R_PPC64_ADDR16, V}; - case R_PPC64_TOC16_DS: - return {R_PPC64_ADDR16_DS, V}; - case R_PPC64_TOC16_HA: - return {R_PPC64_ADDR16_HA, V}; - case R_PPC64_TOC16_HI: - return {R_PPC64_ADDR16_HI, V}; - case R_PPC64_TOC16_LO: - return {R_PPC64_ADDR16_LO, V}; - case R_PPC64_TOC16_LO_DS: - return {R_PPC64_ADDR16_LO_DS, V}; - default: - return {Type, Val}; - } -} - -void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - // For a TOC-relative relocation, proceed in terms of the corresponding - // ADDR16 relocation type. - std::tie(Type, Val) = toAddr16Rel(Type, Val); - - switch (Type) { - case R_PPC64_ADDR14: { - checkAlignment<4>(Loc, Val, Type); - // Preserve the AA/LK bits in the branch instruction - uint8_t AALK = Loc[3]; - write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); - break; - } - case R_PPC64_ADDR16: - checkInt<16>(Loc, Val, Type); - write16be(Loc, Val); - break; - case R_PPC64_ADDR16_DS: - checkInt<16>(Loc, Val, Type); - write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); - break; - case R_PPC64_ADDR16_HA: - case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(Val)); - break; - case R_PPC64_ADDR16_HI: - case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(Val)); - break; - case R_PPC64_ADDR16_HIGHER: - write16be(Loc, applyPPCHigher(Val)); - break; - case R_PPC64_ADDR16_HIGHERA: - write16be(Loc, applyPPCHighera(Val)); - break; - case R_PPC64_ADDR16_HIGHEST: - write16be(Loc, applyPPCHighest(Val)); - break; - case R_PPC64_ADDR16_HIGHESTA: - write16be(Loc, applyPPCHighesta(Val)); - break; - case R_PPC64_ADDR16_LO: - write16be(Loc, applyPPCLo(Val)); - break; - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_REL16_LO: - write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); - break; - case R_PPC64_ADDR32: - case R_PPC64_REL32: - checkInt<32>(Loc, Val, Type); - write32be(Loc, Val); - break; - case R_PPC64_ADDR64: - case R_PPC64_REL64: - case R_PPC64_TOC: - write64be(Loc, Val); - break; - case R_PPC64_REL24: { - uint32_t Mask = 0x03FFFFFC; - checkInt<24>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); - break; - } - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -TargetInfo *elf::getPPC64TargetInfo() { - static PPC64 Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/PPC.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -//===- PPC.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Symbols.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class PPC final : public TargetInfo { -public: - PPC() { GotBaseSymOff = 0x8000; } - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; -}; -} // namespace - -RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_PPC_REL24: - case R_PPC_REL32: - return R_PC; - case R_PPC_PLTREL24: - return R_PLT_PC; - default: - return R_ABS; - } -} - -void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_PPC_ADDR16_HA: - write16be(Loc, (Val + 0x8000) >> 16); - break; - case R_PPC_ADDR16_HI: - write16be(Loc, Val >> 16); - break; - case R_PPC_ADDR16_LO: - write16be(Loc, Val); - break; - case R_PPC_ADDR32: - case R_PPC_REL32: - write32be(Loc, Val); - break; - case R_PPC_PLTREL24: - case R_PPC_REL24: - write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -TargetInfo *elf::getPPCTargetInfo() { - static PPC Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/SPARCV9.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/SPARCV9.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/SPARCV9.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/SPARCV9.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -//===- SPARCV9.cpp --------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class SPARCV9 final : public TargetInfo { -public: - SPARCV9(); - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -SPARCV9::SPARCV9() { - CopyRel = R_SPARC_COPY; - GotRel = R_SPARC_GLOB_DAT; - PltRel = R_SPARC_JMP_SLOT; - RelativeRel = R_SPARC_RELATIVE; - GotEntrySize = 8; - PltEntrySize = 32; - PltHeaderSize = 4 * PltEntrySize; - - PageSize = 8192; - DefaultMaxPageSize = 0x100000; - DefaultImageBase = 0x100000; -} - -RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_SPARC_32: - case R_SPARC_UA32: - case R_SPARC_64: - case R_SPARC_UA64: - return R_ABS; - case R_SPARC_PC10: - case R_SPARC_PC22: - case R_SPARC_DISP32: - case R_SPARC_WDISP30: - return R_PC; - case R_SPARC_GOT10: - return R_GOT_OFF; - case R_SPARC_GOT22: - return R_GOT_OFF; - case R_SPARC_WPLT30: - return R_PLT_PC; - case R_SPARC_NONE: - return R_NONE; - default: - return R_INVALID; - } -} - -void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_SPARC_32: - case R_SPARC_UA32: - // V-word32 - checkUInt<32>(Loc, Val, Type); - write32be(Loc, Val); - break; - case R_SPARC_DISP32: - // V-disp32 - checkInt<32>(Loc, Val, Type); - write32be(Loc, Val); - break; - case R_SPARC_WDISP30: - case R_SPARC_WPLT30: - // V-disp30 - checkInt<32>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); - break; - case R_SPARC_22: - // V-imm22 - checkUInt<22>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); - break; - case R_SPARC_GOT22: - case R_SPARC_PC22: - // T-imm22 - write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); - break; - case R_SPARC_WDISP19: - // V-disp19 - checkInt<21>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); - break; - case R_SPARC_GOT10: - case R_SPARC_PC10: - // T-simm10 - write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); - break; - case R_SPARC_64: - case R_SPARC_UA64: - case R_SPARC_GLOB_DAT: - // V-xword64 - write64be(Loc, Val); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t PltData[] = { - 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 - 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 - 0x01, 0x00, 0x00, 0x00, // nop - 0x01, 0x00, 0x00, 0x00, // nop - 0x01, 0x00, 0x00, 0x00, // nop - 0x01, 0x00, 0x00, 0x00, // nop - 0x01, 0x00, 0x00, 0x00, // nop - 0x01, 0x00, 0x00, 0x00 // nop - }; - memcpy(Buf, PltData, sizeof(PltData)); - - uint64_t Off = PltHeaderSize + Index * PltEntrySize; - relocateOne(Buf, R_SPARC_22, Off); - relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); -} - -TargetInfo *elf::getSPARCV9TargetInfo() { - static SPARCV9 Target; - return &Target; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/X86_64.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/X86_64.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/X86_64.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/X86_64.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,584 +0,0 @@ -//===- X86_64.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -template class X86_64 : public TargetInfo { -public: - X86_64(); - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; - void writeGotPltHeader(uint8_t *Buf) const override; - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - - RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr Expr) const override; - void relaxGot(uint8_t *Loc, uint64_t Val) const override; - void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - -private: - void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, - uint8_t ModRm) const; -}; -} // namespace - -template X86_64::X86_64() { - GotBaseSymOff = -1; - CopyRel = R_X86_64_COPY; - GotRel = R_X86_64_GLOB_DAT; - PltRel = R_X86_64_JUMP_SLOT; - RelativeRel = R_X86_64_RELATIVE; - IRelativeRel = R_X86_64_IRELATIVE; - TlsGotRel = R_X86_64_TPOFF64; - TlsModuleIndexRel = R_X86_64_DTPMOD64; - TlsOffsetRel = R_X86_64_DTPOFF64; - GotEntrySize = 8; - GotPltEntrySize = 8; - PltEntrySize = 16; - PltHeaderSize = 16; - TlsGdRelaxSkip = 2; - TrapInstr = 0xcccccccc; // 0xcc = INT3 - - // Align to the large page size (known as a superpage or huge page). - // FreeBSD automatically promotes large, superpage-aligned allocations. - DefaultImageBase = 0x200000; -} - -template -RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_X86_64_8: - case R_X86_64_16: - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_DTPOFF32: - case R_X86_64_DTPOFF64: - return R_ABS; - case R_X86_64_TPOFF32: - return R_TLS; - case R_X86_64_TLSLD: - return R_TLSLD_PC; - case R_X86_64_TLSGD: - return R_TLSGD_PC; - case R_X86_64_SIZE32: - case R_X86_64_SIZE64: - return R_SIZE; - case R_X86_64_PLT32: - return R_PLT_PC; - case R_X86_64_PC32: - case R_X86_64_PC64: - return R_PC; - case R_X86_64_GOT32: - case R_X86_64_GOT64: - return R_GOT_FROM_END; - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_GOTTPOFF: - return R_GOT_PC; - case R_X86_64_NONE: - return R_NONE; - default: - return R_INVALID; - } -} - -template void X86_64::writeGotPltHeader(uint8_t *Buf) const { - // The first entry holds the value of _DYNAMIC. It is not clear why that is - // required, but it is documented in the psabi and the glibc dynamic linker - // seems to use it (note that this is relevant for linking ld.so, not any - // other program). - write64le(Buf, InX::Dynamic->getVA()); -} - -template -void X86_64::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - // See comments in X86::writeGotPlt. - write32le(Buf, S.getPltVA() + 6); -} - -template void X86_64::writePltHeader(uint8_t *Buf) const { - const uint8_t PltData[] = { - 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip) - 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip) - 0x0f, 0x1f, 0x40, 0x00, // nop - }; - memcpy(Buf, PltData, sizeof(PltData)); - uint64_t GotPlt = InX::GotPlt->getVA(); - uint64_t Plt = InX::Plt->getVA(); - write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 - write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 -} - -template -void X86_64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Inst[] = { - 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip) - 0x68, 0, 0, 0, 0, // pushq - 0xe9, 0, 0, 0, 0, // jmpq plt[0] - }; - memcpy(Buf, Inst, sizeof(Inst)); - - write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); - write32le(Buf + 7, Index); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); -} - -template bool X86_64::isPicRel(RelType Type) const { - return Type != R_X86_64_PC32 && Type != R_X86_64_32 && - Type != R_X86_64_TPOFF32; -} - -template -void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, - uint64_t Val) const { - // Convert - // .byte 0x66 - // leaq x@tlsgd(%rip), %rdi - // .word 0x6666 - // rex64 - // call __tls_get_addr@plt - // to - // mov %fs:0x0,%rax - // lea x@tpoff,%rax - const uint8_t Inst[] = { - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax - 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax - }; - memcpy(Loc - 4, Inst, sizeof(Inst)); - - // The original code used a pc relative relocation and so we have to - // compensate for the -4 in had in the addend. - write32le(Loc + 8, Val + 4); -} - -template -void X86_64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, - uint64_t Val) const { - // Convert - // .byte 0x66 - // leaq x@tlsgd(%rip), %rdi - // .word 0x6666 - // rex64 - // call __tls_get_addr@plt - // to - // mov %fs:0x0,%rax - // addq x@tpoff,%rax - const uint8_t Inst[] = { - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax - 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax - }; - memcpy(Loc - 4, Inst, sizeof(Inst)); - - // Both code sequences are PC relatives, but since we are moving the constant - // forward by 8 bytes we have to subtract the value by 8. - write32le(Loc + 8, Val - 8); -} - -// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to -// R_X86_64_TPOFF32 so that it does not use GOT. -template -void X86_64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, - uint64_t Val) const { - uint8_t *Inst = Loc - 3; - uint8_t Reg = Loc[-1] >> 3; - uint8_t *RegSlot = Loc - 1; - - // Note that ADD with RSP or R12 is converted to ADD instead of LEA - // because LEA with these registers needs 4 bytes to encode and thus - // wouldn't fit the space. - - if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { - // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" - memcpy(Inst, "\x48\x81\xc4", 3); - } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { - // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" - memcpy(Inst, "\x49\x81\xc4", 3); - } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { - // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" - memcpy(Inst, "\x4d\x8d", 2); - *RegSlot = 0x80 | (Reg << 3) | Reg; - } else if (memcmp(Inst, "\x48\x03", 2) == 0) { - // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" - memcpy(Inst, "\x48\x8d", 2); - *RegSlot = 0x80 | (Reg << 3) | Reg; - } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { - // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" - memcpy(Inst, "\x49\xc7", 2); - *RegSlot = 0xc0 | Reg; - } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { - // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" - memcpy(Inst, "\x48\xc7", 2); - *RegSlot = 0xc0 | Reg; - } else { - error(getErrorLocation(Loc - 3) + - "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); - } - - // The original code used a PC relative relocation. - // Need to compensate for the -4 it had in the addend. - write32le(Loc, Val + 4); -} - -template -void X86_64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, - uint64_t Val) const { - // Convert - // leaq bar@tlsld(%rip), %rdi - // callq __tls_get_addr@PLT - // leaq bar@dtpoff(%rax), %rcx - // to - // .word 0x6666 - // .byte 0x66 - // mov %fs:0,%rax - // leaq bar@tpoff(%rax), %rcx - if (Type == R_X86_64_DTPOFF64) { - write64le(Loc, Val); - return; - } - if (Type == R_X86_64_DTPOFF32) { - write32le(Loc, Val); - return; - } - - const uint8_t Inst[] = { - 0x66, 0x66, // .word 0x6666 - 0x66, // .byte 0x66 - 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax - }; - memcpy(Loc - 3, Inst, sizeof(Inst)); -} - -template -void X86_64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_X86_64_8: - checkUInt<8>(Loc, Val, Type); - *Loc = Val; - break; - case R_X86_64_16: - checkUInt<16>(Loc, Val, Type); - write16le(Loc, Val); - break; - case R_X86_64_32: - checkUInt<32>(Loc, Val, Type); - write32le(Loc, Val); - break; - case R_X86_64_32S: - case R_X86_64_TPOFF32: - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PC32: - case R_X86_64_GOTTPOFF: - case R_X86_64_PLT32: - case R_X86_64_TLSGD: - case R_X86_64_TLSLD: - case R_X86_64_DTPOFF32: - case R_X86_64_SIZE32: - checkInt<32>(Loc, Val, Type); - write32le(Loc, Val); - break; - case R_X86_64_64: - case R_X86_64_DTPOFF64: - case R_X86_64_GLOB_DAT: - case R_X86_64_PC64: - case R_X86_64_SIZE64: - case R_X86_64_GOT64: - write64le(Loc, Val); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -template -RelExpr X86_64::adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr RelExpr) const { - if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) - return RelExpr; - const uint8_t Op = Data[-2]; - const uint8_t ModRm = Data[-1]; - - // FIXME: When PIC is disabled and foo is defined locally in the - // lower 32 bit address space, memory operand in mov can be converted into - // immediate operand. Otherwise, mov must be changed to lea. We support only - // latter relaxation at this moment. - if (Op == 0x8b) - return R_RELAX_GOT_PC; - - // Relax call and jmp. - if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) - return R_RELAX_GOT_PC; - - // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. - // If PIC then no relaxation is available. - // We also don't relax test/binop instructions without REX byte, - // they are 32bit operations and not common to have. - assert(Type == R_X86_64_REX_GOTPCRELX); - return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; -} - -// A subset of relaxations can only be applied for no-PIC. This method -// handles such relaxations. Instructions encoding information was taken from: -// "Intel 64 and IA-32 Architectures Software Developer's Manual V2" -// (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ -// 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) -template -void X86_64::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, - uint8_t ModRm) const { - const uint8_t Rex = Loc[-3]; - // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". - if (Op == 0x85) { - // See "TEST-Logical Compare" (4-428 Vol. 2B), - // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). - - // ModR/M byte has form XX YYY ZZZ, where - // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). - // XX has different meanings: - // 00: The operand's memory address is in reg1. - // 01: The operand's memory address is reg1 + a byte-sized displacement. - // 10: The operand's memory address is reg1 + a word-sized displacement. - // 11: The operand is reg1 itself. - // If an instruction requires only one operand, the unused reg2 field - // holds extra opcode bits rather than a register code - // 0xC0 == 11 000 000 binary. - // 0x38 == 00 111 000 binary. - // We transfer reg2 to reg1 here as operand. - // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). - Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. - - // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 - // See "TEST-Logical Compare" (4-428 Vol. 2B). - Loc[-2] = 0xf7; - - // Move R bit to the B bit in REX byte. - // REX byte is encoded as 0100WRXB, where - // 0100 is 4bit fixed pattern. - // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the - // default operand size is used (which is 32-bit for most but not all - // instructions). - // REX.R This 1-bit value is an extension to the MODRM.reg field. - // REX.X This 1-bit value is an extension to the SIB.index field. - // REX.B This 1-bit value is an extension to the MODRM.rm field or the - // SIB.base field. - // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). - Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; - write32le(Loc, Val); - return; - } - - // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub - // or xor operations. - - // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". - // Logic is close to one for test instruction above, but we also - // write opcode extension here, see below for details. - Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. - - // Primary opcode is 0x81, opcode extension is one of: - // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, - // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. - // This value was wrote to MODRM.reg in a line above. - // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), - // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for - // descriptions about each operation. - Loc[-2] = 0x81; - Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; - write32le(Loc, Val); -} - -template -void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { - const uint8_t Op = Loc[-2]; - const uint8_t ModRm = Loc[-1]; - - // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". - if (Op == 0x8b) { - Loc[-2] = 0x8d; - write32le(Loc, Val); - return; - } - - if (Op != 0xff) { - // We are relaxing a rip relative to an absolute, so compensate - // for the old -4 addend. - assert(!Config->Pic); - relaxGotNoPic(Loc, Val + 4, Op, ModRm); - return; - } - - // Convert call/jmp instructions. - if (ModRm == 0x15) { - // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". - // Instead we convert to "addr32 call foo" where addr32 is an instruction - // prefix. That makes result expression to be a single instruction. - Loc[-2] = 0x67; // addr32 prefix - Loc[-1] = 0xe8; // call - write32le(Loc, Val); - return; - } - - // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". - // jmp doesn't return, so it is fine to use nop here, it is just a stub. - assert(ModRm == 0x25); - Loc[-2] = 0xe9; // jmp - Loc[3] = 0x90; // nop - write32le(Loc - 1, Val + 1); -} - -namespace { -template class Retpoline : public X86_64 { -public: - Retpoline(); - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; -}; - -template class RetpolineZNow : public X86_64 { -public: - RetpolineZNow(); - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; -}; -} // namespace - -template Retpoline::Retpoline() { - TargetInfo::PltHeaderSize = 48; - TargetInfo::PltEntrySize = 32; -} - -template -void Retpoline::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - write32le(Buf, S.getPltVA() + 17); -} - -template void Retpoline::writePltHeader(uint8_t *Buf) const { - const uint8_t Insn[] = { - 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 - 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next - 0xf3, 0x90, // 12: loop: pause - 0x0f, 0xae, 0xe8, // 14: lfence - 0xeb, 0xf9, // 17: jmp loop - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 - 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) - 0xc3, // 24: ret - }; - memcpy(Buf, Insn, sizeof(Insn)); - - uint64_t GotPlt = InX::GotPlt->getVA(); - uint64_t Plt = InX::Plt->getVA(); - write32le(Buf + 2, GotPlt - Plt - 6 + 8); - write32le(Buf + 9, GotPlt - Plt - 13 + 16); -} - -template -void Retpoline::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Insn[] = { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 - 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 - 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 - 0x68, 0, 0, 0, 0, // 11: pushq - 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 - }; - memcpy(Buf, Insn, sizeof(Insn)); - - uint64_t Off = TargetInfo::PltHeaderSize + TargetInfo::PltEntrySize * Index; - - write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); - write32le(Buf + 8, -Off - 12 + 32); - write32le(Buf + 13, -Off - 17 + 18); - write32le(Buf + 18, Index); - write32le(Buf + 23, -Off - 27); -} - -template RetpolineZNow::RetpolineZNow() { - TargetInfo::PltHeaderSize = 32; - TargetInfo::PltEntrySize = 16; -} - -template -void RetpolineZNow::writePltHeader(uint8_t *Buf) const { - const uint8_t Insn[] = { - 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next - 0xf3, 0x90, // 5: loop: pause - 0x0f, 0xae, 0xe8, // 7: lfence - 0xeb, 0xf9, // a: jmp loop - 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 - 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) - 0xc3, // 14: ret - }; - memcpy(Buf, Insn, sizeof(Insn)); -} - -template -void RetpolineZNow::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Insn[] = { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 - 0xe9, 0, 0, 0, 0, // jmp plt+0 - }; - memcpy(Buf, Insn, sizeof(Insn)); - - write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); - write32le(Buf + 8, - -Index * TargetInfo::PltEntrySize - TargetInfo::PltHeaderSize - 12); -} - -template TargetInfo *getTargetInfo() { - if (Config->ZRetpolineplt) { - if (Config->ZNow) { - static RetpolineZNow T; - return &T; - } - static Retpoline T; - return &T; - } - - static X86_64 T; - return &T; -} - -TargetInfo *elf::getX32TargetInfo() { return getTargetInfo(); } -TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/X86.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/X86.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Arch/X86.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Arch/X86.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,543 +0,0 @@ -//===- X86.cpp ------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputFiles.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support::endian; -using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - -namespace { -class X86 : public TargetInfo { -public: - X86(); - RelExpr getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const override; - int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; - void writeGotPltHeader(uint8_t *Buf) const override; - RelType getDynRel(RelType Type) const override; - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - - RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr Expr) const override; - void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; - void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; -}; -} // namespace - -X86::X86() { - GotBaseSymOff = -1; - CopyRel = R_386_COPY; - GotRel = R_386_GLOB_DAT; - PltRel = R_386_JUMP_SLOT; - IRelativeRel = R_386_IRELATIVE; - RelativeRel = R_386_RELATIVE; - TlsGotRel = R_386_TLS_TPOFF; - TlsModuleIndexRel = R_386_TLS_DTPMOD32; - TlsOffsetRel = R_386_TLS_DTPOFF32; - GotEntrySize = 4; - GotPltEntrySize = 4; - PltEntrySize = 16; - PltHeaderSize = 16; - TlsGdRelaxSkip = 2; - TrapInstr = 0xcccccccc; // 0xcc = INT3 -} - -static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; } - -RelExpr X86::getRelExpr(RelType Type, const Symbol &S, - const uint8_t *Loc) const { - switch (Type) { - case R_386_8: - case R_386_16: - case R_386_32: - case R_386_TLS_LDO_32: - return R_ABS; - case R_386_TLS_GD: - return R_TLSGD; - case R_386_TLS_LDM: - return R_TLSLD; - case R_386_PLT32: - return R_PLT_PC; - case R_386_PC8: - case R_386_PC16: - case R_386_PC32: - return R_PC; - case R_386_GOTPC: - return R_GOTONLY_PC_FROM_END; - case R_386_TLS_IE: - return R_GOT; - case R_386_GOT32: - case R_386_GOT32X: - // These relocations are arguably mis-designed because their calculations - // depend on the instructions they are applied to. This is bad because we - // usually don't care about whether the target section contains valid - // machine instructions or not. But this is part of the documented ABI, so - // we had to implement as the standard requires. - // - // x86 does not support PC-relative data access. Therefore, in order to - // access GOT contents, a GOT address needs to be known at link-time - // (which means non-PIC) or compilers have to emit code to get a GOT - // address at runtime (which means code is position-independent but - // compilers need to emit extra code for each GOT access.) This decision - // is made at compile-time. In the latter case, compilers emit code to - // load an GOT address to a register, which is usually %ebx. - // - // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or - // foo@GOT(%reg). - // - // foo@GOT is not usable in PIC. If we are creating a PIC output and if we - // find such relocation, we should report an error. foo@GOT is resolved to - // an *absolute* address of foo's GOT entry, because both GOT address and - // foo's offset are known. In other words, it's G + A. - // - // foo@GOT(%reg) needs to be resolved to a *relative* offset from a GOT to - // foo's GOT entry in the table, because GOT address is not known but foo's - // offset in the table is known. It's G + A - GOT. - // - // It's unfortunate that compilers emit the same relocation for these - // different use cases. In order to distinguish them, we have to read a - // machine instruction. - // - // The following code implements it. We assume that Loc[0] is the first - // byte of a displacement or an immediate field of a valid machine - // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at - // the byte, we can determine whether the instruction is register-relative - // (i.e. it was generated for foo@GOT(%reg)) or absolute (i.e. foo@GOT). - return hasBaseReg(Loc[-1]) ? R_GOT_FROM_END : R_GOT; - case R_386_TLS_GOTIE: - return R_GOT_FROM_END; - case R_386_GOTOFF: - return R_GOTREL_FROM_END; - case R_386_TLS_LE: - return R_TLS; - case R_386_TLS_LE_32: - return R_NEG_TLS; - case R_386_NONE: - return R_NONE; - default: - return R_INVALID; - } -} - -RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data, - RelExpr Expr) const { - switch (Expr) { - default: - return Expr; - case R_RELAX_TLS_GD_TO_IE: - return R_RELAX_TLS_GD_TO_IE_END; - case R_RELAX_TLS_GD_TO_LE: - return R_RELAX_TLS_GD_TO_LE_NEG; - } -} - -void X86::writeGotPltHeader(uint8_t *Buf) const { - write32le(Buf, InX::Dynamic->getVA()); -} - -void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - // Entries in .got.plt initially points back to the corresponding - // PLT entries with a fixed offset to skip the first instruction. - write32le(Buf, S.getPltVA() + 6); -} - -void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { - // An x86 entry is the address of the ifunc resolver function. - write32le(Buf, S.getVA()); -} - -RelType X86::getDynRel(RelType Type) const { - if (Type == R_386_TLS_LE) - return R_386_TLS_TPOFF; - if (Type == R_386_TLS_LE_32) - return R_386_TLS_TPOFF32; - return Type; -} - -void X86::writePltHeader(uint8_t *Buf) const { - if (Config->Pic) { - const uint8_t V[] = { - 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) - 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) - 0x90, 0x90, 0x90, 0x90 // nop - }; - memcpy(Buf, V, sizeof(V)); - - uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); - uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; - write32le(Buf + 2, GotPlt + 4); - write32le(Buf + 8, GotPlt + 8); - return; - } - - const uint8_t PltData[] = { - 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) - 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) - 0x90, 0x90, 0x90, 0x90, // nop - }; - memcpy(Buf, PltData, sizeof(PltData)); - uint32_t GotPlt = InX::GotPlt->getVA(); - write32le(Buf + 2, GotPlt + 4); - write32le(Buf + 8, GotPlt + 8); -} - -void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Inst[] = { - 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx) - 0x68, 0, 0, 0, 0, // pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC - }; - memcpy(Buf, Inst, sizeof(Inst)); - - if (Config->Pic) { - // jmp *foo@GOT(%ebx) - uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); - Buf[1] = 0xa3; - write32le(Buf + 2, GotPltEntryAddr - Ebx); - } else { - // jmp *foo_in_GOT - Buf[1] = 0x25; - write32le(Buf + 2, GotPltEntryAddr); - } - - write32le(Buf + 7, RelOff); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); -} - -int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { - switch (Type) { - case R_386_8: - case R_386_PC8: - return SignExtend64<8>(*Buf); - case R_386_16: - case R_386_PC16: - return SignExtend64<16>(read16le(Buf)); - case R_386_32: - case R_386_GOT32: - case R_386_GOT32X: - case R_386_GOTOFF: - case R_386_GOTPC: - case R_386_PC32: - case R_386_PLT32: - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - return SignExtend64<32>(read32le(Buf)); - default: - return 0; - } -} - -void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { - switch (Type) { - case R_386_8: - // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are - // being used for some 16-bit programs such as boot loaders, so - // we want to support them. - checkUInt<8>(Loc, Val, Type); - *Loc = Val; - break; - case R_386_PC8: - checkInt<8>(Loc, Val, Type); - *Loc = Val; - break; - case R_386_16: - checkUInt<16>(Loc, Val, Type); - write16le(Loc, Val); - break; - case R_386_PC16: - // R_386_PC16 is normally used with 16 bit code. In that situation - // the PC is 16 bits, just like the addend. This means that it can - // point from any 16 bit address to any other if the possibility - // of wrapping is included. - // The only restriction we have to check then is that the destination - // address fits in 16 bits. That is impossible to do here. The problem is - // that we are passed the final value, which already had the - // current location subtracted from it. - // We just check that Val fits in 17 bits. This misses some cases, but - // should have no false positives. - checkInt<17>(Loc, Val, Type); - write16le(Loc, Val); - break; - case R_386_32: - case R_386_GLOB_DAT: - case R_386_GOT32: - case R_386_GOT32X: - case R_386_GOTOFF: - case R_386_GOTPC: - case R_386_PC32: - case R_386_PLT32: - case R_386_RELATIVE: - case R_386_TLS_DTPMOD32: - case R_386_TLS_DTPOFF32: - case R_386_TLS_GD: - case R_386_TLS_GOTIE: - case R_386_TLS_IE: - case R_386_TLS_LDM: - case R_386_TLS_LDO_32: - case R_386_TLS_LE: - case R_386_TLS_LE_32: - case R_386_TLS_TPOFF: - case R_386_TLS_TPOFF32: - checkInt<32>(Loc, Val, Type); - write32le(Loc, Val); - break; - default: - error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); - } -} - -void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // Convert - // leal x@tlsgd(, %ebx, 1), - // call __tls_get_addr@plt - // to - // movl %gs:0,%eax - // subl $x@ntpoff,%eax - const uint8_t Inst[] = { - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax - 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax - }; - memcpy(Loc - 3, Inst, sizeof(Inst)); - write32le(Loc + 5, Val); -} - -void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // Convert - // leal x@tlsgd(, %ebx, 1), - // call __tls_get_addr@plt - // to - // movl %gs:0, %eax - // addl x@gotntpoff(%ebx), %eax - const uint8_t Inst[] = { - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax - 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax - }; - memcpy(Loc - 3, Inst, sizeof(Inst)); - write32le(Loc + 5, Val); -} - -// In some conditions, relocations can be optimized to avoid using GOT. -// This function does that for Initial Exec to Local Exec case. -void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - // Ulrich's document section 6.2 says that @gotntpoff can - // be used with MOVL or ADDL instructions. - // @indntpoff is similar to @gotntpoff, but for use in - // position dependent code. - uint8_t Reg = (Loc[-1] >> 3) & 7; - - if (Type == R_386_TLS_IE) { - if (Loc[-1] == 0xa1) { - // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" - // This case is different from the generic case below because - // this is a 5 byte instruction while below is 6 bytes. - Loc[-1] = 0xb8; - } else if (Loc[-2] == 0x8b) { - // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" - Loc[-2] = 0xc7; - Loc[-1] = 0xc0 | Reg; - } else { - // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" - Loc[-2] = 0x81; - Loc[-1] = 0xc0 | Reg; - } - } else { - assert(Type == R_386_TLS_GOTIE); - if (Loc[-2] == 0x8b) { - // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" - Loc[-2] = 0xc7; - Loc[-1] = 0xc0 | Reg; - } else { - // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" - Loc[-2] = 0x8d; - Loc[-1] = 0x80 | (Reg << 3) | Reg; - } - } - write32le(Loc, Val); -} - -void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - if (Type == R_386_TLS_LDO_32) { - write32le(Loc, Val); - return; - } - - // Convert - // leal foo(%reg),%eax - // call ___tls_get_addr - // to - // movl %gs:0,%eax - // nop - // leal 0(%esi,1),%esi - const uint8_t Inst[] = { - 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax - 0x90, // nop - 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi - }; - memcpy(Loc - 2, Inst, sizeof(Inst)); -} - -namespace { -class RetpolinePic : public X86 { -public: - RetpolinePic(); - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; -}; - -class RetpolineNoPic : public X86 { -public: - RetpolineNoPic(); - void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; - void writePltHeader(uint8_t *Buf) const override; - void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, - int32_t Index, unsigned RelOff) const override; -}; -} // namespace - -RetpolinePic::RetpolinePic() { - PltHeaderSize = 48; - PltEntrySize = 32; -} - -void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - write32le(Buf, S.getPltVA() + 17); -} - -void RetpolinePic::writePltHeader(uint8_t *Buf) const { - const uint8_t Insn[] = { - 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) - 0x50, // 6: pushl %eax - 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax - 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next - 0xf3, 0x90, // 12: loop: pause - 0x0f, 0xae, 0xe8, // 14: lfence - 0xeb, 0xf9, // 17: jmp loop - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 - 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) - 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx - 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) - 0x89, 0xc8, // 2b: mov %ecx, %eax - 0x59, // 2d: pop %ecx - 0xc3, // 2e: ret - }; - memcpy(Buf, Insn, sizeof(Insn)); - - uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); - uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; - write32le(Buf + 2, GotPlt + 4); - write32le(Buf + 9, GotPlt + 8); -} - -void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Insn[] = { - 0x50, // pushl %eax - 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax - 0xe8, 0, 0, 0, 0, // call plt+0x20 - 0xe9, 0, 0, 0, 0, // jmp plt+0x12 - 0x68, 0, 0, 0, 0, // pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // jmp plt+0 - }; - memcpy(Buf, Insn, sizeof(Insn)); - - uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); - write32le(Buf + 3, GotPltEntryAddr - Ebx); - write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); - write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); - write32le(Buf + 18, RelOff); - write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); -} - -RetpolineNoPic::RetpolineNoPic() { - PltHeaderSize = 48; - PltEntrySize = 32; -} - -void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - write32le(Buf, S.getPltVA() + 16); -} - -void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { - const uint8_t PltData[] = { - 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 - 0x50, // 6: pushl %eax - 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax - 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next - 0xf3, 0x90, // 11: loop: pause - 0x0f, 0xae, 0xe8, // 13: lfence - 0xeb, 0xf9, // 16: jmp loop - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 - 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 - 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) - 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx - 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) - 0x89, 0xc8, // 2b: mov %ecx, %eax - 0x59, // 2d: pop %ecx - 0xc3, // 2e: ret - }; - memcpy(Buf, PltData, sizeof(PltData)); - - uint32_t GotPlt = InX::GotPlt->getVA(); - write32le(Buf + 2, GotPlt + 4); - write32le(Buf + 8, GotPlt + 8); -} - -void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - const uint8_t Insn[] = { - 0x50, // 0: pushl %eax - 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax - 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 - 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 - 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 - }; - memcpy(Buf, Insn, sizeof(Insn)); - - write32le(Buf + 2, GotPltEntryAddr); - write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17); - write32le(Buf + 17, RelOff); - write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26); -} - -TargetInfo *elf::getX86TargetInfo() { - if (Config->ZRetpolineplt) { - if (Config->Pic) { - static RetpolinePic T; - return &T; - } - static RetpolineNoPic T; - return &T; - } - - static X86 T; - return &T; -} diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Bits.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Bits.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Bits.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Bits.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -//===- Bits.h ---------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_BITS_H -#define LLD_ELF_BITS_H - -#include "Config.h" -#include "llvm/Support/Endian.h" - -namespace lld { -namespace elf { - -inline uint64_t readUint(uint8_t *Buf) { - if (Config->Is64) - return llvm::support::endian::read64(Buf, Config->Endianness); - return llvm::support::endian::read32(Buf, Config->Endianness); -} - -inline void writeUint(uint8_t *Buf, uint64_t Val) { - if (Config->Is64) - llvm::support::endian::write64(Buf, Val, Config->Endianness); - else - llvm::support::endian::write32(Buf, Val, Config->Endianness); -} - -} // namespace elf -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/CMakeLists.txt rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/CMakeLists.txt --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/CMakeLists.txt 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS Options.td) -tablegen(LLVM Options.inc -gen-opt-parser-defs) -add_public_tablegen_target(ELFOptionsTableGen) - -if(NOT LLD_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - -add_lld_library(lldELF - AArch64ErrataFix.cpp - Arch/AArch64.cpp - Arch/AMDGPU.cpp - Arch/ARM.cpp - Arch/AVR.cpp - Arch/Mips.cpp - Arch/MipsArchTree.cpp - Arch/PPC.cpp - Arch/PPC64.cpp - Arch/SPARCV9.cpp - Arch/X86.cpp - Arch/X86_64.cpp - Driver.cpp - DriverUtils.cpp - EhFrame.cpp - Filesystem.cpp - GdbIndex.cpp - ICF.cpp - InputFiles.cpp - InputSection.cpp - LTO.cpp - LinkerScript.cpp - MapFile.cpp - MarkLive.cpp - OutputSections.cpp - Relocations.cpp - ScriptLexer.cpp - ScriptParser.cpp - Strings.cpp - SymbolTable.cpp - Symbols.cpp - SyntheticSections.cpp - Target.cpp - Thunks.cpp - Writer.cpp - - LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} - BinaryFormat - Core - DebugInfoDWARF - LTO - MC - Object - Option - Support - - LINK_LIBS - lldCommon - ${LLVM_PTHREAD_LIB} - - DEPENDS - ELFOptionsTableGen - ${tablegen_deps} - ) diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Config.h rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Config.h --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Config.h 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Config.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -//===- Config.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_CONFIG_H -#define LLD_ELF_CONFIG_H - -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/Support/CachePruning.h" -#include "llvm/Support/CodeGen.h" -#include "llvm/Support/Endian.h" - -#include - -namespace lld { -namespace elf { - -class InputFile; - -enum ELFKind { - ELFNoneKind, - ELF32LEKind, - ELF32BEKind, - ELF64LEKind, - ELF64BEKind -}; - -// For --build-id. -enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; - -// For --discard-{all,locals,none}. -enum class DiscardPolicy { Default, All, Locals, None }; - -// For --strip-{all,debug}. -enum class StripPolicy { None, All, Debug }; - -// For --unresolved-symbols. -enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; - -// For --orphan-handling. -enum class OrphanHandlingPolicy { Place, Warn, Error }; - -// For --sort-section and linkerscript sorting rules. -enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; - -// For --target2 -enum class Target2Policy { Abs, Rel, GotRel }; - -struct SymbolVersion { - llvm::StringRef Name; - bool IsExternCpp; - bool HasWildcard; -}; - -// This struct contains symbols version definition that -// can be found in version script if it is used for link. -struct VersionDefinition { - llvm::StringRef Name; - uint16_t Id = 0; - std::vector Globals; - size_t NameOff = 0; // Offset in the string table -}; - -// This struct contains the global configuration for the linker. -// Most fields are direct mapping from the command line options -// and such fields have the same name as the corresponding options. -// Most fields are initialized by the driver. -struct Configuration { - uint8_t OSABI = 0; - llvm::CachePruningPolicy ThinLTOCachePolicy; - llvm::StringMap SectionStartMap; - llvm::StringRef Chroot; - llvm::StringRef DynamicLinker; - llvm::StringRef Entry; - llvm::StringRef Emulation; - llvm::StringRef Fini; - llvm::StringRef Init; - llvm::StringRef LTOAAPipeline; - llvm::StringRef LTONewPmPasses; - llvm::StringRef MapFile; - llvm::StringRef OutputFile; - llvm::StringRef OptRemarksFilename; - llvm::StringRef SoName; - llvm::StringRef Sysroot; - llvm::StringRef ThinLTOCacheDir; - std::string Rpath; - std::vector VersionDefinitions; - std::vector Argv; - std::vector AuxiliaryList; - std::vector FilterList; - std::vector SearchPaths; - std::vector SymbolOrderingFile; - std::vector Undefined; - std::vector DynamicList; - std::vector VersionScriptGlobals; - std::vector VersionScriptLocals; - std::vector BuildIdVector; - bool AllowMultipleDefinition; - bool AndroidPackDynRelocs = false; - bool ARMHasBlx = false; - bool ARMHasMovtMovw = false; - bool ARMJ1J2BranchEncoding = false; - bool AsNeeded = false; - bool Bsymbolic; - bool BsymbolicFunctions; - bool CompressDebugSections; - bool DefineCommon; - bool Demangle = true; - bool DisableVerify; - bool EhFrameHdr; - bool EmitRelocs; - bool EnableNewDtags; - bool ExportDynamic; - bool FixCortexA53Errata843419; - bool GcSections; - bool GdbIndex; - bool GnuHash = false; - bool HasDynamicList = false; - bool HasDynSymTab; - bool ICF; - bool ICFData; - bool MergeArmExidx; - bool MipsN32Abi = false; - bool NoGnuUnique; - bool NoUndefinedVersion; - bool NoinhibitExec; - bool Nostdlib; - bool OFormatBinary; - bool Omagic; - bool OptRemarksWithHotness; - bool Pie; - bool PrintGcSections; - bool Relocatable; - bool SaveTemps; - bool SingleRoRx; - bool Shared; - bool Static = false; - bool SysvHash = false; - bool Target1Rel; - bool Trace; - bool Verbose; - bool WarnCommon; - bool WarnMissingEntry; - bool ZCombreloc; - bool ZExecstack; - bool ZNocopyreloc; - bool ZNodelete; - bool ZNodlopen; - bool ZNow; - bool ZOrigin; - bool ZRelro; - bool ZRodynamic; - bool ZText; - bool ZRetpolineplt; - bool ExitEarly; - bool ZWxneeded; - DiscardPolicy Discard; - OrphanHandlingPolicy OrphanHandling; - SortSectionPolicy SortSection; - StripPolicy Strip; - UnresolvedPolicy UnresolvedSymbols; - Target2Policy Target2; - BuildIdKind BuildId = BuildIdKind::None; - ELFKind EKind = ELFNoneKind; - uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; - uint16_t EMachine = llvm::ELF::EM_NONE; - llvm::Optional ImageBase; - uint64_t MaxPageSize; - uint64_t ZStackSize; - unsigned LTOPartitions; - unsigned LTOO; - unsigned Optimize; - unsigned ThinLTOJobs; - - // The following config options do not directly correspond to any - // particualr command line options. - - // True if we need to pass through relocations in input files to the - // output file. Usually false because we consume relocations. - bool CopyRelocs; - - // True if the target is ELF64. False if ELF32. - bool Is64; - - // True if the target is little-endian. False if big-endian. - bool IsLE; - - // endianness::little if IsLE is true. endianness::big otherwise. - llvm::support::endianness Endianness; - - // True if the target is the little-endian MIPS64. - // - // The reason why we have this variable only for the MIPS is because - // we use this often. Some ELF headers for MIPS64EL are in a - // mixed-endian (which is horrible and I'd say that's a serious spec - // bug), and we need to know whether we are reading MIPS ELF files or - // not in various places. - // - // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official - // name whatever that means. A fun hypothesis is that "EL" is short for - // little-endian written in the little-endian order, but I don't know - // if that's true.) - bool IsMips64EL; - - // Holds set of ELF header flags for the target. - uint32_t EFlags = 0; - - // The ELF spec defines two types of relocation table entries, RELA and - // REL. RELA is a triplet of (offset, info, addend) while REL is a - // tuple of (offset, info). Addends for REL are implicit and read from - // the location where the relocations are applied. So, REL is more - // compact than RELA but requires a bit of more work to process. - // - // (From the linker writer's view, this distinction is not necessary. - // If the ELF had chosen whichever and sticked with it, it would have - // been easier to write code to process relocations, but it's too late - // to change the spec.) - // - // Each ABI defines its relocation type. IsRela is true if target - // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A - // few 32-bit ABIs are using RELA too. - bool IsRela; - - // True if we are creating position-independent code. - bool Pic; - - // 4 for ELF32, 8 for ELF64. - int Wordsize; -}; - -// The only instance of Configuration struct. -extern Configuration *Config; - -} // namespace elf -} // namespace lld - -#endif diff -Nru rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Driver.cpp rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Driver.cpp --- rustc-1.26.0+dfsg0+llvm/src/tools/lld/ELF/Driver.cpp 2018-05-07 17:31:55.000000000 +0000 +++ rustc-1.26.1+dfsg0+llvm/src/tools/lld/ELF/Driver.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1133 +0,0 @@ -//===- Driver.cpp ---------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The driver drives the entire linking process. It is responsible for -// parsing command line options and doing whatever it is instructed to do. -// -// One notable thing in the LLD's driver when compared to other linkers is -// that the LLD's driver is agnostic on the host operating system. -// Other linkers usually have implicit default values (such as a dynamic -// linker path or library paths) for each host OS. -// -// I don't think implicit default values are useful because they are -// usually explicitly specified by the compiler driver. They can even -// be harmful when you are doing cross-linking. Therefore, in LLD, we -// simply trust the compiler driver to pass all required options and -// don't try to make effort on our side. -// -//===----------------------------------------------------------------------===// - -#include "Driver.h" -#include "Config.h" -#include "Filesystem.h" -#include "ICF.h" -#include "InputFiles.h" -#include "InputSection.h" -#include "LinkerScript.h" -#include "OutputSections.h" -#include "ScriptParser.h" -#include "Strings.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "SyntheticSections.h" -#include "Target.h" -#include "Writer.h" -#include "lld/Common/Args.h" -#include "lld/Common/Driver.h" -#include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" -#include "lld/Common/Threads.h" -#include "lld/Common/Version.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TarWriter.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" -#include -#include - -using namespace llvm; -using namespace llvm::ELF; -using namespace llvm::object; -using namespace llvm::sys; - -using namespace lld; -using namespace lld::elf; - -Configuration *elf::Config; -LinkerDriver *elf::Driver; - -static void setConfigs(); - -bool elf::link(ArrayRef Args, bool CanExitEarly, - raw_ostream &Error) { - errorHandler().LogName = Args[0]; - errorHandler().ErrorLimitExceededMsg = - "too many errors emitted, stopping now (use " - "-error-limit=0 to see all errors)"; - errorHandler().ErrorOS = &Error; - errorHandler().ColorDiagnostics = Error.has_colors(); - InputSections.clear(); - OutputSections.clear(); - Tar = nullptr; - BinaryFiles.clear(); - BitcodeFiles.clear(); - ObjectFiles.clear(); - SharedFiles.clear(); - - Config = make(); - Driver = make(); - Script = make(); - Symtab = make(); - Config->Argv = {Args.begin(), Args.end()}; - - Driver->main(Args, CanExitEarly); - - // Exit immediately if we don't need to return to the caller. - // This saves time because the overhead of calling destructors - // for all globally-allocated objects is not negligible. - if (Config->ExitEarly) - exitLld(errorCount() ? 1 : 0); - - freeArena(); - return !errorCount(); -} - -// Parses a linker -m option. -static std::tuple parseEmulation(StringRef Emul) { - uint8_t OSABI = 0; - StringRef S = Emul; - if (S.endswith("_fbsd")) { - S = S.drop_back(5); - OSABI = ELFOSABI_FREEBSD; - } - - std::pair Ret = - StringSwitch>(S) - .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) - .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) - .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) - .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) - .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) - .Case("elf32ppc", {ELF32BEKind, EM_PPC}) - .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) - .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) - .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) - .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) - .Case("elf_i386", {ELF32LEKind, EM_386}) - .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) - .Default({ELFNoneKind, EM_NONE}); - - if (Ret.first == ELFNoneKind) - error("unknown emulation: " + Emul); - return std::make_tuple(Ret.first, Ret.second, OSABI); -} - -// Returns slices of MB by parsing MB as an archive file. -// Each slice consists of a member file in the archive. -std::vector> static getArchiveMembers( - MemoryBufferRef MB) { - std::unique_ptr File = - CHECK(Archive::create(MB), - MB.getBufferIdentifier() + ": failed to parse archive"); - - std::vector> V; - Error Err = Error::success(); - bool AddToTar = File->isThin() && Tar; - for (const ErrorOr &COrErr : File->children(Err)) { - Archive::Child C = - CHECK(COrErr, MB.getBufferIdentifier() + - ": could not get the child of the archive"); - MemoryBufferRef MBRef = - CHECK(C.getMemoryBufferRef(), - MB.getBufferIdentifier() + - ": could not get the buffer for a child of the archive"); - if (AddToTar) - Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer()); - V.push_back(std::make_pair(MBRef, C.getChildOffset())); - } - if (Err) - fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + - toString(std::move(Err))); - - // Take ownership of memory buffers created for members of thin archives. - for (std::unique_ptr &MB : File->takeThinBuffers()) - make>(std::move(MB)); - - return V; -} - -// Opens a file and create a file object. Path has to be resolved already. -void LinkerDriver::addFile(StringRef Path, bool WithLOption) { - using namespace sys::fs; - - Optional Buffer = readFile(Path); - if (!Buffer.hasValue()) - return; - MemoryBufferRef MBRef = *Buffer; - - if (InBinary) { - Files.push_back(make(MBRef)); - return; - } - - switch (identify_magic(MBRef.getBuffer())) { - case file_magic::unknown: - readLinkerScript(MBRef); - return; - case file_magic::archive: { - // Handle -whole-archive. - if (InWholeArchive) { - for (const auto &P : getArchiveMembers(MBRef)) - Files.push_back(createObjectFile(P.first, Path, P.second)); - return; - } - - std::unique_ptr File = - CHECK(Archive::create(MBRef), Path + ": failed to parse archive"); - - // If an archive file has no symbol table, it is likely that a user - // is attempting LTO and using a default ar command that doesn't - // understand the LLVM bitcode file. It is a pretty common error, so - // we'll handle it as if it had a symbol table. - if (!File->isEmpty() && !File->hasSymbolTable()) { - for (const auto &P : getArchiveMembers(MBRef)) - Files.push_back(make(P.first, Path, P.second)); - return; - } - - // Handle the regular case. - Files.push_back(make(std::move(File))); - return; - } - case file_magic::elf_shared_object: - if (Config->Relocatable) { - error("attempted static link of dynamic object " + Path); - return; - } - - // DSOs usually have DT_SONAME tags in their ELF headers, and the - // sonames are used to identify DSOs. But if they are missing, - // they are identified by filenames. We don't know whether the new - // file has a DT_SONAME or not because we haven't parsed it yet. - // Here, we set the default soname for the file because we might - // need it later. - // - // If a file was specified by -lfoo, the directory part is not - // significant, as a user did not specify it. This behavior is - // compatible with GNU. - Files.push_back( - createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); - return; - default: - if (InLib) - Files.push_back(make(MBRef, "", 0)); - else - Files.push_back(createObjectFile(MBRef)); - } -} - -// Add a given library by searching it from input search paths. -void LinkerDriver::addLibrary(StringRef Name) { - if (Optional Path = searchLibrary(Name)) - addFile(*Path, /*WithLOption=*/true); - else - error("unable to find library -l" + Name); -} - -// This function is called on startup. We need this for LTO since -// LTO calls LLVM functions to compile bitcode files to native code. -// Technically this can be delayed until we read bitcode files, but -// we don't bother to do lazily because the initialization is fast. -static void initLLVM(opt::InputArgList &Args) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); - InitializeAllAsmParsers(); - - // Parse and evaluate -mllvm options. - std::vector V; - V.push_back("lld (LLVM option parsing)"); - for (auto *Arg : Args.filtered(OPT_mllvm)) - V.push_back(Arg->getValue()); - cl::ParseCommandLineOptions(V.size(), V.data()); -} - -// Some command line options or some combinations of them are not allowed. -// This function checks for such errors. -static void checkOptions(opt::InputArgList &Args) { - // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup - // table which is a relatively new feature. - if (Config->EMachine == EM_MIPS && Config->GnuHash) - error("the .gnu.hash section is not compatible with the MIPS target."); - - if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64) - error("--fix-cortex-a53-843419 is only supported on AArch64 targets."); - - if (Config->Pie && Config->Shared) - error("-shared and -pie may not be used together"); - - if (!Config->Shared && !Config->FilterList.empty()) - error("-F may not be used without -shared"); - - if (!Config->Shared && !Config->AuxiliaryList.empty()) - error("-f may not be used without -shared"); - - if (!Config->Relocatable && !Config->DefineCommon) - error("-no-define-common not supported in non relocatable output"); - - if (Config->Relocatable) { - if (Config->Shared) - error("-r and -shared may not be used together"); - if (Config->GcSections) - error("-r and --gc-sections may not be used together"); - if (Config->ICF) - error("-r and --icf may not be used together"); - if (Config->Pie) - error("-r and -pie may not be used together"); - } -} - -static const char *getReproduceOption(opt::InputArgList &Args) { - if (auto *Arg = Args.getLastArg(OPT_reproduce)) - return Arg->getValue(); - return getenv("LLD_REPRODUCE"); -} - -static bool hasZOption(opt::InputArgList &Args, StringRef Key) { - for (auto *Arg : Args.filtered(OPT_z)) - if (Key == Arg->getValue()) - return true; - return false; -} - -void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { - ELFOptTable Parser; - opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); - - // Interpret this flag early because error() depends on them. - errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); - - // Handle -help - if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); - return; - } - - // Handle -v or -version. - // - // A note about "compatible with GNU linkers" message: this is a hack for - // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and - // still the newest version in March 2017) or earlier to recognize LLD as - // a GNU compatible linker. As long as an output for the -v option - // contains "GNU" or "with BFD", they recognize us as GNU-compatible. - // - // This is somewhat ugly hack, but in reality, we had no choice other - // than doing this. Considering the very long release cycle of Libtool, - // it is not easy to improve it to recognize LLD as a GNU compatible - // linker in a timely manner. Even if we can make it, there are still a - // lot of "configure" scripts out there that are generated by old version - // of Libtool. We cannot convince every software developer to migrate to - // the latest version and re-generate scripts. So we have this hack. - if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) - message(getLLDVersion() + " (compatible with GNU linkers)"); - - // The behavior of -v or --version is a bit strange, but this is - // needed for compatibility with GNU linkers. - if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT)) - return; - if (Args.hasArg(OPT_version)) - return; - - Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); - errorHandler().ExitEarly = Config->ExitEarly; - - if (const char *Path = getReproduceOption(Args)) { - // Note that --reproduce is a debug option so you can ignore it - // if you are trying to understand the whole picture of the code. - Expected> ErrOrWriter = - TarWriter::create(Path, path::stem(Path)); - if (ErrOrWriter) { - Tar = ErrOrWriter->get(); - Tar->append("response.txt", createResponseFile(Args)); - Tar->append("version.txt", getLLDVersion() + "\n"); - make>(std::move(*ErrOrWriter)); - } else { - error(Twine("--reproduce: failed to open ") + Path + ": " + - toString(ErrOrWriter.takeError())); - } - } - - readConfigs(Args); - initLLVM(Args); - createFiles(Args); - inferMachineType(); - setConfigs(); - checkOptions(Args); - if (errorCount()) - return; - - switch (Config->EKind) { - case ELF32LEKind: - link(Args); - return; - case ELF32BEKind: - link(Args); - return; - case ELF64LEKind: - link(Args); - return; - case ELF64BEKind: - link(Args); - return; - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -static std::string getRpath(opt::InputArgList &Args) { - std::vector V = args::getStrings(Args, OPT_rpath); - return llvm::join(V.begin(), V.end(), ":"); -} - -// Determines what we should do if there are remaining unresolved -// symbols after the name resolution. -static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { - if (Args.hasArg(OPT_relocatable)) - return UnresolvedPolicy::IgnoreAll; - - UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols, - OPT_warn_unresolved_symbols, true) - ? UnresolvedPolicy::ReportError - : UnresolvedPolicy::Warn; - - // Process the last of -unresolved-symbols, -no-undefined or -z defs. - for (auto *Arg : llvm::reverse(Args)) { - switch (Arg->getOption().getID()) { - case OPT_unresolved_symbols: { - StringRef S = Arg->getValue(); - if (S == "ignore-all" || S == "ignore-in-object-files") - return UnresolvedPolicy::Ignore; - if (S == "ignore-in-shared-libs" || S == "report-all") - return ErrorOrWarn; - error("unknown --unresolved-symbols value: " + S); - continue; - } - case OPT_no_undefined: - return ErrorOrWarn; - case OPT_z: - if (StringRef(Arg->getValue()) == "defs") - return ErrorOrWarn; - continue; - } - } - - // -shared implies -unresolved-symbols=ignore-all because missing - // symbols are likely to be resolved at runtime using other DSOs. - if (Config->Shared) - return UnresolvedPolicy::Ignore; - return ErrorOrWarn; -} - -static Target2Policy getTarget2(opt::InputArgList &Args) { - StringRef S = Args.getLastArgValue(OPT_target2, "got-rel"); - if (S == "rel") - return Target2Policy::Rel; - if (S == "abs") - return Target2Policy::Abs; - if (S == "got-rel") - return Target2Policy::GotRel; - error("unknown --target2 option: " + S); - return Target2Policy::GotRel; -} - -static bool isOutputFormatBinary(opt::InputArgList &Args) { - if (auto *Arg = Args.getLastArg(OPT_oformat)) { - StringRef S = Arg->getValue(); - if (S == "binary") - return true; - error("unknown --oformat value: " + S); - } - return false; -} - -static DiscardPolicy getDiscard(opt::InputArgList &Args) { - if (Args.hasArg(OPT_relocatable)) - return DiscardPolicy::None; - - auto *Arg = - Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); - if (!Arg) - return DiscardPolicy::Default; - if (Arg->getOption().getID() == OPT_discard_all) - return DiscardPolicy::All; - if (Arg->getOption().getID() == OPT_discard_locals) - return DiscardPolicy::Locals; - return DiscardPolicy::None; -} - -static StringRef getDynamicLinker(opt::InputArgList &Args) { - auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); - if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) - return ""; - return Arg->getValue(); -} - -static StripPolicy getStrip(opt::InputArgList &Args) { - if (Args.hasArg(OPT_relocatable)) - return StripPolicy::None; - - auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); - if (!Arg) - return StripPolicy::None; - if (Arg->getOption().getID() == OPT_strip_all) - return StripPolicy::All; - return StripPolicy::Debug; -} - -static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) { - uint64_t VA = 0; - if (S.startswith("0x")) - S = S.drop_front(2); - if (!to_integer(S, VA, 16)) - error("invalid argument: " + toString(Arg)); - return VA; -} - -static StringMap getSectionStartMap(opt::InputArgList &Args) { - StringMap Ret; - for (auto *Arg : Args.filtered(OPT_section_start)) { - StringRef Name; - StringRef Addr; - std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); - Ret[Name] = parseSectionAddress(Addr, *Arg); - } - - if (auto *Arg = Args.getLastArg(OPT_Ttext)) - Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg); - if (auto *Arg = Args.getLastArg(OPT_Tdata)) - Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg); - if (auto *Arg = Args.getLastArg(OPT_Tbss)) - Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg); - return Ret; -} - -static SortSectionPolicy getSortSection(opt::InputArgList &Args) { - StringRef S = Args.getLastArgValue(OPT_sort_section); - if (S == "alignment") - return SortSectionPolicy::Alignment; - if (S == "name") - return SortSectionPolicy::Name; - if (!S.empty()) - error("unknown --sort-section rule: " + S); - return SortSectionPolicy::Default; -} - -static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { - StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place"); - if (S == "warn") - return OrphanHandlingPolicy::Warn; - if (S == "error") - return OrphanHandlingPolicy::Error; - if (S != "place") - error("unknown --orphan-handling mode: " + S); - return OrphanHandlingPolicy::Place; -} - -// Parse --build-id or --build-id=