Skip to content

Commit bd0cf1b

Browse files
committed
Don't use GCC's startup objects (crtbegin.o/crtend.o); build and use our own (for now on for -windows-gnu target only).
Since it isn't possible to disable linkage of just GCC startup objects, we now need logic for finding libc installation directory and copying the required startup files (e.g. crt2.o) to rustlib directory. Bonus change: use the `-nodefaultlibs` flag on Windows, thus paving the way to direct linker invocation.
1 parent c807ff3 commit bd0cf1b

File tree

12 files changed

+217
-24
lines changed

12 files changed

+217
-24
lines changed

configure

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
625625
valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
626626
valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
627627
valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
628+
valopt_nosave libc-dir "/usr/lib" "installation directory of the system libc"
628629

629630
# Temporarily support old triples until buildbots get updated
630631
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=
10801081
CFG_STDCPP_NAME=$(echo "stdc++" | sed "${program_transform_name}")
10811082
putvar CFG_STDCPP_NAME
10821083

1084+
#CFG_LIB_SEARCH_PATH=$($CFG_CC -print-search-dirs | sed -n "/libraries: =/ { s/.*=//; P }")
1085+
#putvar CFG_LIB_SEARCH_PATH
1086+
10831087
# a little post-processing of various config values
10841088
CFG_PREFIX=${CFG_PREFIX%/}
10851089
CFG_MANDIR=${CFG_MANDIR%/}
@@ -1280,6 +1284,16 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
12801284
putvar CFG_DISABLE_JEMALLOC
12811285
;;
12821286

1287+
*-windows-gnu)
1288+
if [ -z "$CFG_LIBC_DIR_PROVIDED" ]; then
1289+
# Use gcc location to find mingw libc directory
1290+
for dir in $(dirname $CFG_GCC)/../*-mingw32/lib; do
1291+
if [ -d "$dir" ]; then
1292+
CFG_LIBC_DIR=$dir
1293+
fi
1294+
done
1295+
fi
1296+
;;
12831297
*)
12841298
;;
12851299
esac
@@ -1738,6 +1752,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK
17381752
putvar CFG_ARM_LINUX_ANDROIDEABI_NDK
17391753
putvar CFG_I686_LINUX_ANDROID_NDK
17401754
putvar CFG_MANDIR
1755+
putvar CFG_LIBC_DIR
17411756

17421757
# Avoid spurious warnings from clang by feeding it original source on
17431758
# ccache-miss rather than preprocessed input.

mk/cfg/i686-pc-windows-gnu.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ CFG_LDPATH_i686-pc-windows-gnu :=
2222
CFG_RUN_i686-pc-windows-gnu=$(2)
2323
CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2))
2424
CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32
25+
CFG_LIBC_STARTUP_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o

mk/cfg/x86_64-pc-windows-gnu.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ CFG_LDPATH_x86_64-pc-windows-gnu :=
2222
CFG_RUN_x86_64-pc-windows-gnu=$(2)
2323
CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2))
2424
CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32
25+
CFG_LIBC_STARTUP_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o

mk/target.mk

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,60 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
132132

133133
endef
134134

135+
# Macro for building runtime startup objects
136+
# Of those we have two kinds:
137+
# - Rust runtime-specific: these are Rust's equivalents of GCC's crti.o/crtn.o,
138+
# - LibC-specific: these we don't build ourselves, but copy them from the system lib directory.
139+
#
140+
# $(1) - stage
141+
# $(2) - target triple
142+
# $(3) - host triple
143+
define TARGET_RT_STARTUP
144+
145+
# Expand build rules for rsbegin.o and rsend.o
146+
$$(foreach obj,rsbegin rsend, \
147+
$$(eval $$(call TARGET_RUSTRT_STARTUP_OBJ,$(1),$(2),$(3),$$(obj))) )
148+
149+
$$(foreach obj,$$(CFG_LIBC_STARTUP_OBJECTS_$(2)), \
150+
$$(eval $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core : $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
151+
$$(eval $$(call COPY_LIBC_STARTUP,$$(TLIB$(1)_T_$(2)_H_$(3)),$$(obj))) )
152+
endef
153+
154+
# TARGET_RT_STARTUP's helper for copying LibC startup objects
155+
# $(1) - target lib directory
156+
# $(2) - object name
157+
define COPY_LIBC_STARTUP
158+
159+
$(1)/$(2) : $$(CFG_LIBC_DIR)/$(2)
160+
@$$(call E, cp: $$@)
161+
@cp $$^ $$@
162+
endef
163+
164+
# Macro for building runtime startup/shutdown object files;
165+
# these are Rust's equivalent of crti.o, crtn.o
166+
#
167+
# $(1) - stage
168+
# $(2) - target triple
169+
# $(3) - host triple
170+
# $(4) - object name
171+
define TARGET_RUSTRT_STARTUP_OBJ
172+
173+
$$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o:\
174+
$(S)src/rtstartup/$(4).rs \
175+
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \
176+
$$(HSREQ$(1)_T_$(2)_H_$(3)) \
177+
| $$(TBIN$(1)_T_$(2)_H_$(3))/
178+
@$$(call E, rustc: $$@)
179+
$$(STAGE$(1)_T_$(2)_H_$(3)) --emit=obj -o $$@ $$<
180+
181+
# Add dependencies on Rust startup objects to all crates that depend on core.
182+
# This ensures that they are built after core (since they depend on it),
183+
# but before everything else (since they are needed for linking dylib crates).
184+
$$(foreach crate, $$(TARGET_CRATES), \
185+
$$(if $$(findstring core,$$(DEPS_$$(crate))), \
186+
$$(eval $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate) : $$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o) ))
187+
endef
188+
135189
# Every recipe in RUST_TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3),
136190
# a directory that can be cleaned out during the middle of a run of
137191
# the get-snapshot.py script. Therefore, every recipe needs to have
@@ -174,3 +228,8 @@ $(foreach host,$(CFG_HOST), \
174228
$(foreach stage,$(STAGES), \
175229
$(foreach tool,$(TOOLS), \
176230
$(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))
231+
232+
$(foreach host,$(CFG_HOST), \
233+
$(foreach target,$(CFG_TARGET), \
234+
$(foreach stage,$(STAGES), \
235+
$(eval $(call TARGET_RT_STARTUP,$(stage),$(target),$(host))))))

src/librustc_back/target/i686_pc_windows_gnu.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111
use target::Target;
1212

1313
pub fn target() -> Target {
14-
let mut options = super::windows_base::opts();
15-
options.cpu = "pentium4".to_string();
14+
let mut base = super::windows_base::opts();
15+
base.cpu = "pentium4".to_string();
1616

1717
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
1818
// space available to x86 Windows binaries on x86_64.
19-
options.pre_link_args.push("-Wl,--large-address-aware".to_string());
20-
21-
// Make sure that we link to the dynamic libgcc, otherwise cross-module
22-
// DWARF stack unwinding will not work.
23-
// This behavior may be overridden by -Clink-args="-static-libgcc"
24-
options.pre_link_args.push("-shared-libgcc".to_string());
19+
base.pre_link_args.push("-Wl,--large-address-aware".to_string());
2520

2621
Target {
2722
llvm_target: "i686-pc-windows-gnu".to_string(),
@@ -31,6 +26,6 @@ pub fn target() -> Target {
3126
target_os: "windows".to_string(),
3227
target_env: "gnu".to_string(),
3328
target_vendor: "pc".to_string(),
34-
options: options,
29+
options: base,
3530
}
3631
}

src/librustc_back/target/mod.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,25 @@ pub struct TargetOptions {
9898
pub linker: String,
9999
/// Archive utility to use when managing archives. Defaults to "ar".
100100
pub ar: String,
101+
101102
/// Linker arguments that are unconditionally passed *before* any
102103
/// user-defined libraries.
103104
pub pre_link_args: Vec<String>,
105+
/// Objects to link before all others, always found within the
106+
/// sysroot folder.
107+
pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
108+
pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
109+
/// Linker arguments that are unconditionally passed after any
110+
/// user-defined but before post_link_objects. Standard platform
111+
/// libraries that should be always be linked to, usually go here.
112+
pub late_link_args: Vec<String>,
113+
/// Objects to link after all others, always found within the
114+
/// sysroot folder.
115+
pub post_link_objects: Vec<String>,
104116
/// Linker arguments that are unconditionally passed *after* any
105117
/// user-defined libraries.
106118
pub post_link_args: Vec<String>,
107-
/// Objects to link before and after all others, always found within the
108-
/// sysroot folder.
109-
pub pre_link_objects: Vec<String>,
110-
pub post_link_objects: Vec<String>,
119+
111120
/// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
112121
/// to "default".
113122
pub cpu: String,
@@ -219,8 +228,10 @@ impl Default for TargetOptions {
219228
no_compiler_rt: false,
220229
no_default_libraries: true,
221230
position_independent_executables: false,
222-
pre_link_objects: Vec::new(),
231+
pre_link_objects_exe: Vec::new(),
232+
pre_link_objects_dll: Vec::new(),
223233
post_link_objects: Vec::new(),
234+
late_link_args: Vec::new(),
224235
archive_format: String::new(),
225236
custom_unwind_resume: false,
226237
lib_allocation_crate: "alloc_system".to_string(),

src/librustc_back/target/windows_base.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ pub fn opts() -> TargetOptions {
2323
exe_suffix: ".exe".to_string(),
2424
staticlib_prefix: "".to_string(),
2525
staticlib_suffix: ".lib".to_string(),
26-
// Unfortunately right now passing -nodefaultlibs to gcc on windows
27-
// doesn't work so hot (in terms of native dependencies). This flag
28-
// should hopefully be removed one day though!
29-
no_default_libraries: false,
26+
no_default_libraries: true,
3027
is_like_windows: true,
3128
archive_format: "gnu".to_string(),
3229
pre_link_args: vec!(
@@ -63,7 +60,32 @@ pub fn opts() -> TargetOptions {
6360

6461
// Always enable DEP (NX bit) when it is available
6562
"-Wl,--nxcompat".to_string(),
63+
64+
// Do not use the standard system startup files or libraries when linking
65+
"-nostdlib".to_string(),
66+
),
67+
pre_link_objects_exe: vec!(
68+
"crt2.o".to_string(),
69+
"rsbegin.o".to_string(),
70+
),
71+
pre_link_objects_dll: vec!(
72+
"dllcrt2.o".to_string(),
73+
"rsbegin.o".to_string(),
74+
),
75+
late_link_args: vec!(
76+
"-lmingwex".to_string(),
77+
"-lmingw32".to_string(),
78+
"-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc
79+
"-lmsvcrt".to_string(),
80+
"-ladvapi32".to_string(),
81+
"-lshell32".to_string(),
82+
"-luser32".to_string(),
83+
"-lkernel32".to_string(),
84+
),
85+
post_link_objects: vec!(
86+
"rsend.o".to_string()
6687
),
88+
custom_unwind_resume: true,
6789
exe_allocation_crate: super::maybe_jemalloc(),
6890

6991
.. Default::default()

src/librustc_back/target/x86_64_pc_windows_gnu.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ use target::Target;
1313
pub fn target() -> Target {
1414
let mut base = super::windows_base::opts();
1515
base.cpu = "x86-64".to_string();
16-
// On Win64 unwinding is handled by the OS, so we can link libgcc statically.
17-
base.pre_link_args.push("-static-libgcc".to_string());
1816
base.pre_link_args.push("-m64".to_string());
19-
base.custom_unwind_resume = true;
2017

2118
Target {
2219
llvm_target: "x86_64-pc-windows-gnu".to_string(),

src/librustc_back/target/x86_64_unknown_linux_musl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ pub fn target() -> Target {
5858
//
5959
// Each target directory for musl has these object files included in it so
6060
// they'll be included from there.
61-
base.pre_link_objects.push("crt1.o".to_string());
62-
base.pre_link_objects.push("crti.o".to_string());
61+
base.pre_link_objects_exe.push("crt1.o".to_string());
62+
base.pre_link_objects_exe.push("crti.o".to_string());
6363
base.post_link_objects.push("crtn.o".to_string());
6464

6565
// MUSL support doesn't currently include dynamic linking, so there's no

src/librustc_trans/back/link.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,13 @@ fn link_natively(sess: &Session, dylib: bool,
850850

851851
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
852852
cmd.args(&sess.target.target.options.pre_link_args);
853-
for obj in &sess.target.target.options.pre_link_objects {
853+
854+
let pre_link_objects = if dylib {
855+
&sess.target.target.options.pre_link_objects_dll
856+
} else {
857+
&sess.target.target.options.pre_link_objects_exe
858+
};
859+
for obj in pre_link_objects {
854860
cmd.arg(root.join(obj));
855861
}
856862

@@ -866,6 +872,7 @@ fn link_natively(sess: &Session, dylib: bool,
866872
linker.link_staticlib("compiler-rt");
867873
}
868874
}
875+
cmd.args(&sess.target.target.options.late_link_args);
869876
for obj in &sess.target.target.options.post_link_objects {
870877
cmd.arg(root.join(obj));
871878
}

0 commit comments

Comments
 (0)