about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure15
-rw-r--r--mk/cfg/i686-pc-windows-gnu.mk1
-rw-r--r--mk/cfg/x86_64-pc-windows-gnu.mk1
-rw-r--r--mk/target.mk59
-rw-r--r--src/librustc_back/target/i686_pc_windows_gnu.rs13
-rw-r--r--src/librustc_back/target/mod.rs21
-rw-r--r--src/librustc_back/target/windows_base.rs30
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_gnu.rs3
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_musl.rs4
-rw-r--r--src/librustc_trans/back/link.rs9
-rw-r--r--src/rtstartup/rsbegin.rs61
-rw-r--r--src/rtstartup/rsend.rs24
12 files changed, 217 insertions, 24 deletions
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<String>,
+    /// Objects to link before all others, always found within the
+    /// sysroot folder.
+    pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
+    pub pre_link_objects_dll: Vec<String>, // ... 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<String>,
+    /// Objects to link after all others, always found within the
+    /// sysroot folder.
+    pub post_link_objects: Vec<String>,
     /// Linker arguments that are unconditionally passed *after* any
     /// user-defined libraries.
     pub post_link_args: Vec<String>,
-    /// Objects to link before and after all others, always found within the
-    /// sysroot folder.
-    pub pre_link_objects: Vec<String>,
-    pub post_link_objects: Vec<String>,
+
     /// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
+}