diff --git a/configure b/configure index 60d366100f8..1360a1ff0ee 100755 --- a/configure +++ b/configure @@ -625,6 +625,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary" valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples" valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples" valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" +valopt_nosave libc-dir "/usr/lib" "installation directory of the system libc" # Temporarily support old triples until buildbots get updated CFG_BUILD=$(to_llvm_triple $CFG_BUILD) @@ -1080,6 +1081,9 @@ program_transform_name=$($CFG_CC -v 2>&1 | sed -n "s/.*--program-transform-name= CFG_STDCPP_NAME=$(echo "stdc++" | sed "${program_transform_name}") putvar CFG_STDCPP_NAME +#CFG_LIB_SEARCH_PATH=$($CFG_CC -print-search-dirs | sed -n "/libraries: =/ { s/.*=//; P }") +#putvar CFG_LIB_SEARCH_PATH + # a little post-processing of various config values CFG_PREFIX=${CFG_PREFIX%/} CFG_MANDIR=${CFG_MANDIR%/} @@ -1280,6 +1284,16 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake putvar CFG_DISABLE_JEMALLOC ;; + *-windows-gnu) + if [ -z "$CFG_LIBC_DIR_PROVIDED" ]; then + # Use gcc location to find mingw libc directory + for dir in $(dirname $CFG_GCC)/../*-mingw32/lib; do + if [ -d "$dir" ]; then + CFG_LIBC_DIR=$dir + fi + done + fi + ;; *) ;; esac @@ -1738,6 +1752,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK putvar CFG_MANDIR +putvar CFG_LIBC_DIR # Avoid spurious warnings from clang by feeding it original source on # ccache-miss rather than preprocessed input. diff --git a/mk/cfg/i686-pc-windows-gnu.mk b/mk/cfg/i686-pc-windows-gnu.mk index 174671a9a88..ced8bf43163 100644 --- a/mk/cfg/i686-pc-windows-gnu.mk +++ b/mk/cfg/i686-pc-windows-gnu.mk @@ -22,3 +22,4 @@ CFG_LDPATH_i686-pc-windows-gnu := CFG_RUN_i686-pc-windows-gnu=$(2) CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2)) CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32 +CFG_LIBC_STARTUP_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o diff --git a/mk/cfg/x86_64-pc-windows-gnu.mk b/mk/cfg/x86_64-pc-windows-gnu.mk index 4118ea26c07..0f49b6d585c 100644 --- a/mk/cfg/x86_64-pc-windows-gnu.mk +++ b/mk/cfg/x86_64-pc-windows-gnu.mk @@ -22,3 +22,4 @@ CFG_LDPATH_x86_64-pc-windows-gnu := CFG_RUN_x86_64-pc-windows-gnu=$(2) CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2)) CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32 +CFG_LIBC_STARTUP_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o \ No newline at end of file diff --git a/mk/target.mk b/mk/target.mk index d6fa55bf7f5..fcb3d4a1e53 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -132,6 +132,60 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ endef +# Macro for building runtime startup objects +# Of those we have two kinds: +# - Rust runtime-specific: these are Rust's equivalents of GCC's crti.o/crtn.o, +# - LibC-specific: these we don't build ourselves, but copy them from the system lib directory. +# +# $(1) - stage +# $(2) - target triple +# $(3) - host triple +define TARGET_RT_STARTUP + +# Expand build rules for rsbegin.o and rsend.o +$$(foreach obj,rsbegin rsend, \ + $$(eval $$(call TARGET_RUSTRT_STARTUP_OBJ,$(1),$(2),$(3),$$(obj))) ) + +$$(foreach obj,$$(CFG_LIBC_STARTUP_OBJECTS_$(2)), \ + $$(eval $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core : $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ + $$(eval $$(call COPY_LIBC_STARTUP,$$(TLIB$(1)_T_$(2)_H_$(3)),$$(obj))) ) +endef + +# TARGET_RT_STARTUP's helper for copying LibC startup objects +# $(1) - target lib directory +# $(2) - object name +define COPY_LIBC_STARTUP + +$(1)/$(2) : $$(CFG_LIBC_DIR)/$(2) + @$$(call E, cp: $$@) + @cp $$^ $$@ +endef + +# Macro for building runtime startup/shutdown object files; +# these are Rust's equivalent of crti.o, crtn.o +# +# $(1) - stage +# $(2) - target triple +# $(3) - host triple +# $(4) - object name +define TARGET_RUSTRT_STARTUP_OBJ + +$$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o:\ + $(S)src/rtstartup/$(4).rs \ + $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \ + $$(HSREQ$(1)_T_$(2)_H_$(3)) \ + | $$(TBIN$(1)_T_$(2)_H_$(3))/ + @$$(call E, rustc: $$@) + $$(STAGE$(1)_T_$(2)_H_$(3)) --emit=obj -o $$@ $$< + +# Add dependencies on Rust startup objects to all crates that depend on core. +# This ensures that they are built after core (since they depend on it), +# but before everything else (since they are needed for linking dylib crates). +$$(foreach crate, $$(TARGET_CRATES), \ + $$(if $$(findstring core,$$(DEPS_$$(crate))), \ + $$(eval $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate) : $$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o) )) +endef + # Every recipe in RUST_TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3), # a directory that can be cleaned out during the middle of a run of # the get-snapshot.py script. Therefore, every recipe needs to have @@ -174,3 +228,8 @@ $(foreach host,$(CFG_HOST), \ $(foreach stage,$(STAGES), \ $(foreach tool,$(TOOLS), \ $(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool))))))) + +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach stage,$(STAGES), \ + $(eval $(call TARGET_RT_STARTUP,$(stage),$(target),$(host)))))) diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index c825f6043d2..fa12bbd8932 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -11,17 +11,12 @@ use target::Target; pub fn target() -> Target { - let mut options = super::windows_base::opts(); - options.cpu = "pentium4".to_string(); + let mut base = super::windows_base::opts(); + base.cpu = "pentium4".to_string(); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - options.pre_link_args.push("-Wl,--large-address-aware".to_string()); - - // Make sure that we link to the dynamic libgcc, otherwise cross-module - // DWARF stack unwinding will not work. - // This behavior may be overridden by -Clink-args="-static-libgcc" - options.pre_link_args.push("-shared-libgcc".to_string()); + base.pre_link_args.push("-Wl,--large-address-aware".to_string()); Target { llvm_target: "i686-pc-windows-gnu".to_string(), @@ -31,6 +26,6 @@ pub fn target() -> Target { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), - options: options, + options: base, } } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 197f8c760b0..7af31e33aba 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -98,16 +98,25 @@ pub struct TargetOptions { pub linker: String, /// Archive utility to use when managing archives. Defaults to "ar". pub ar: String, + /// Linker arguments that are unconditionally passed *before* any /// user-defined libraries. pub pre_link_args: Vec, + /// Objects to link before all others, always found within the + /// sysroot folder. + pub pre_link_objects_exe: Vec, // ... when linking an executable + pub pre_link_objects_dll: Vec, // ... when linking a dylib + /// Linker arguments that are unconditionally passed after any + /// user-defined but before post_link_objects. Standard platform + /// libraries that should be always be linked to, usually go here. + pub late_link_args: Vec, + /// Objects to link after all others, always found within the + /// sysroot folder. + pub post_link_objects: Vec, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. pub post_link_args: Vec, - /// Objects to link before and after all others, always found within the - /// sysroot folder. - pub pre_link_objects: Vec, - pub post_link_objects: Vec, + /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults /// to "default". pub cpu: String, @@ -219,8 +228,10 @@ impl Default for TargetOptions { no_compiler_rt: false, no_default_libraries: true, position_independent_executables: false, - pre_link_objects: Vec::new(), + pre_link_objects_exe: Vec::new(), + pre_link_objects_dll: Vec::new(), post_link_objects: Vec::new(), + late_link_args: Vec::new(), archive_format: String::new(), custom_unwind_resume: false, lib_allocation_crate: "alloc_system".to_string(), diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index 2e597367902..fc1e192f1e1 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -23,10 +23,7 @@ pub fn opts() -> TargetOptions { exe_suffix: ".exe".to_string(), staticlib_prefix: "".to_string(), staticlib_suffix: ".lib".to_string(), - // Unfortunately right now passing -nodefaultlibs to gcc on windows - // doesn't work so hot (in terms of native dependencies). This flag - // should hopefully be removed one day though! - no_default_libraries: false, + no_default_libraries: true, is_like_windows: true, archive_format: "gnu".to_string(), pre_link_args: vec!( @@ -63,7 +60,32 @@ pub fn opts() -> TargetOptions { // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), + + // Do not use the standard system startup files or libraries when linking + "-nostdlib".to_string(), ), + pre_link_objects_exe: vec!( + "crt2.o".to_string(), + "rsbegin.o".to_string(), + ), + pre_link_objects_dll: vec!( + "dllcrt2.o".to_string(), + "rsbegin.o".to_string(), + ), + late_link_args: vec!( + "-lmingwex".to_string(), + "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc + "-lmsvcrt".to_string(), + "-ladvapi32".to_string(), + "-lshell32".to_string(), + "-luser32".to_string(), + "-lkernel32".to_string(), + ), + post_link_objects: vec!( + "rsend.o".to_string() + ), + custom_unwind_resume: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 2bd363e46bb..3e843853915 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -13,10 +13,7 @@ use target::Target; pub fn target() -> Target { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); - // On Win64 unwinding is handled by the OS, so we can link libgcc statically. - base.pre_link_args.push("-static-libgcc".to_string()); base.pre_link_args.push("-m64".to_string()); - base.custom_unwind_resume = true; Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index a5ac78cd5b6..dafbb924a9c 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -58,8 +58,8 @@ pub fn target() -> Target { // // Each target directory for musl has these object files included in it so // they'll be included from there. - base.pre_link_objects.push("crt1.o".to_string()); - base.pre_link_objects.push("crti.o".to_string()); + base.pre_link_objects_exe.push("crt1.o".to_string()); + base.pre_link_objects_exe.push("crti.o".to_string()); base.post_link_objects.push("crtn.o".to_string()); // MUSL support doesn't currently include dynamic linking, so there's no diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index bae14afd81d..21b438ae814 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -850,7 +850,13 @@ fn link_natively(sess: &Session, dylib: bool, let root = sess.target_filesearch(PathKind::Native).get_lib_path(); cmd.args(&sess.target.target.options.pre_link_args); - for obj in &sess.target.target.options.pre_link_objects { + + let pre_link_objects = if dylib { + &sess.target.target.options.pre_link_objects_dll + } else { + &sess.target.target.options.pre_link_objects_exe + }; + for obj in pre_link_objects { cmd.arg(root.join(obj)); } @@ -866,6 +872,7 @@ fn link_natively(sess: &Session, dylib: bool, linker.link_staticlib("compiler-rt"); } } + cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { cmd.arg(root.join(obj)); } diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs new file mode 100644 index 00000000000..17684b74b70 --- /dev/null +++ b/src/rtstartup/rsbegin.rs @@ -0,0 +1,61 @@ +// Copyright 2015 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(no_std)] +#![feature(linkage)] + +#![crate_type="rlib"] +#![no_std] +#![allow(non_camel_case_types)] + +#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] +pub mod eh_frames +{ + #[no_mangle] + #[link_section = ".eh_frame"] + pub static __EH_FRAME_BEGIN__: [u8; 0] = []; + + // Scratch space for unwinder's internal book-keeping. + // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h. + static mut obj: [isize; 6] = [0; 6]; + + extern { + fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8); + fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8); + } + + unsafe fn init() { + rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, + &mut obj as *mut _ as *mut u8); + } + + unsafe fn uninit() { + rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, + &mut obj as *mut _ as *mut u8); + } + + pub mod ms_init + { + // .CRT$X?? sections are roughly analogous to ELF's .init_array and .fini_array, + // except that they exploit the fact that linker will sort them alphabitically, + // so e.g. sections with names between .CRT$XIA and .CRT$XIZ are guaranteed to be + // placed between those two, without requiring any ordering of objects on the linker + // command line. + // Note that ordering of same-named sections from different objects is not guaranteed. + // Since .CRT$XIA contains init array's header symbol, which must always come first, + // we place our initialization callback into .CRT$XIB. + + #[link_section = ".CRT$XIB"] // .CRT$XI? : C initialization callbacks + pub static P_INIT: unsafe fn() = super::init; + + #[link_section = ".CRT$XTY"] // .CRT$XT? : C termination callbacks + pub static P_UNINIT: unsafe fn() = super::uninit; + } +} diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs new file mode 100644 index 00000000000..df7759877e9 --- /dev/null +++ b/src/rtstartup/rsend.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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(no_std)] + +#![crate_type="rlib"] +#![no_std] + +#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] +pub mod eh_frames +{ + // Terminate the frame unwind info section with a 0 as a sentinel; + // this would be the 'length' field in a real FDE. + #[no_mangle] + #[link_section = ".eh_frame"] + pub static __EH_FRAME_END__: u32 = 0; +}