]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 | 1 | use super::archive; |
dfeec247 XL |
2 | use super::command::Command; |
3 | use super::symbol_export; | |
f035d41b | 4 | use rustc_span::symbol::sym; |
a1dfa0c6 | 5 | |
cc61c64b | 6 | use std::ffi::{OsStr, OsString}; |
e9174d1e | 7 | use std::fs::{self, File}; |
e9174d1e | 8 | use std::io::prelude::*; |
9e0c209e | 9 | use std::io::{self, BufWriter}; |
62682a34 | 10 | use std::path::{Path, PathBuf}; |
136023e0 | 11 | use std::{env, mem, str}; |
3157f602 | 12 | |
dfeec247 | 13 | use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; |
ba9703b0 | 14 | use rustc_middle::middle::dependency_format::Linkage; |
04454e1e | 15 | use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; |
ba9703b0 | 16 | use rustc_middle::ty::TyCtxt; |
f9f354fc | 17 | use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; |
ba9703b0 | 18 | use rustc_session::Session; |
f9f354fc XL |
19 | use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; |
20 | ||
136023e0 XL |
21 | use cc::windows_registry; |
22 | ||
f9f354fc XL |
23 | /// Disables non-English messages from localized linkers. |
24 | /// Such messages may cause issues with text encoding on Windows (#35785) | |
25 | /// and prevent inspection of linker output in case of errors, which we occasionally do. | |
26 | /// This should be acceptable because other messages from rustc are in English anyway, | |
27 | /// and may also be desirable to improve searchability of the linker diagnostics. | |
28 | pub fn disable_localization(linker: &mut Command) { | |
29 | // No harm in setting both env vars simultaneously. | |
30 | // Unix-style linkers. | |
31 | linker.env("LC_ALL", "C"); | |
32 | // MSVC's `link.exe`. | |
33 | linker.env("VSLANG", "1033"); | |
34 | } | |
3157f602 | 35 | |
136023e0 XL |
36 | // The third parameter is for env vars, used on windows to set up the |
37 | // path for MSVC to find its DLLs, and gcc to find its bundled | |
38 | // toolchain | |
39 | pub fn get_linker<'a>( | |
40 | sess: &'a Session, | |
41 | linker: &Path, | |
42 | flavor: LinkerFlavor, | |
43 | self_contained: bool, | |
44 | target_cpu: &'a str, | |
45 | ) -> Box<dyn Linker + 'a> { | |
46 | let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); | |
47 | ||
48 | // If our linker looks like a batch script on Windows then to execute this | |
49 | // we'll need to spawn `cmd` explicitly. This is primarily done to handle | |
50 | // emscripten where the linker is `emcc.bat` and needs to be spawned as | |
51 | // `cmd /c emcc.bat ...`. | |
52 | // | |
53 | // This worked historically but is needed manually since #42436 (regression | |
54 | // was tagged as #42791) and some more info can be found on #44443 for | |
55 | // emscripten itself. | |
56 | let mut cmd = match linker.to_str() { | |
57 | Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker), | |
58 | _ => match flavor { | |
59 | LinkerFlavor::Lld(f) => Command::lld(linker, f), | |
60 | LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => { | |
61 | Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path())) | |
62 | } | |
63 | _ => Command::new(linker), | |
64 | }, | |
65 | }; | |
66 | ||
67 | // UWP apps have API restrictions enforced during Store submissions. | |
68 | // To comply with the Windows App Certification Kit, | |
69 | // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). | |
70 | let t = &sess.target; | |
71 | if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link)) | |
72 | && t.vendor == "uwp" | |
73 | { | |
74 | if let Some(ref tool) = msvc_tool { | |
75 | let original_path = tool.path(); | |
76 | if let Some(ref root_lib_path) = original_path.ancestors().nth(4) { | |
5e7ed085 | 77 | let arch = match t.arch.as_ref() { |
136023e0 XL |
78 | "x86_64" => Some("x64"), |
79 | "x86" => Some("x86"), | |
80 | "aarch64" => Some("arm64"), | |
81 | "arm" => Some("arm"), | |
82 | _ => None, | |
83 | }; | |
84 | if let Some(ref a) = arch { | |
85 | // FIXME: Move this to `fn linker_with_args`. | |
86 | let mut arg = OsString::from("/LIBPATH:"); | |
87 | arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a)); | |
88 | cmd.arg(&arg); | |
89 | } else { | |
90 | warn!("arch is not supported"); | |
91 | } | |
92 | } else { | |
93 | warn!("MSVC root path lib location not found"); | |
94 | } | |
95 | } else { | |
96 | warn!("link.exe not found"); | |
3157f602 XL |
97 | } |
98 | } | |
99 | ||
136023e0 XL |
100 | // The compiler's sysroot often has some bundled tools, so add it to the |
101 | // PATH for the child. | |
c295e0f8 | 102 | let mut new_path = sess.get_tools_search_paths(self_contained); |
136023e0 XL |
103 | let mut msvc_changed_path = false; |
104 | if sess.target.is_like_msvc { | |
105 | if let Some(ref tool) = msvc_tool { | |
106 | cmd.args(tool.args()); | |
107 | for &(ref k, ref v) in tool.env() { | |
108 | if k == "PATH" { | |
109 | new_path.extend(env::split_paths(v)); | |
110 | msvc_changed_path = true; | |
111 | } else { | |
112 | cmd.env(k, v); | |
113 | } | |
17df50a5 | 114 | } |
136023e0 XL |
115 | } |
116 | } | |
dfeec247 | 117 | |
136023e0 XL |
118 | if !msvc_changed_path { |
119 | if let Some(path) = env::var_os("PATH") { | |
120 | new_path.extend(env::split_paths(&path)); | |
121 | } | |
122 | } | |
123 | cmd.env("PATH", env::join_paths(new_path).unwrap()); | |
0531ce1d | 124 | |
136023e0 XL |
125 | // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction |
126 | // to the linker args construction. | |
127 | assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); | |
136023e0 XL |
128 | match flavor { |
129 | LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { | |
130 | Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker> | |
131 | } | |
132 | LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>, | |
133 | LinkerFlavor::Gcc => { | |
134 | Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false }) | |
135 | as Box<dyn Linker> | |
136 | } | |
17df50a5 | 137 | |
136023e0 XL |
138 | LinkerFlavor::Lld(LldFlavor::Ld) |
139 | | LinkerFlavor::Lld(LldFlavor::Ld64) | |
140 | | LinkerFlavor::Ld => { | |
141 | Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true }) | |
142 | as Box<dyn Linker> | |
3157f602 | 143 | } |
136023e0 XL |
144 | |
145 | LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>, | |
146 | ||
147 | LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>, | |
148 | ||
149 | LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>, | |
5099ac24 FG |
150 | |
151 | LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>, | |
3157f602 XL |
152 | } |
153 | } | |
62682a34 | 154 | |
9fa01778 | 155 | /// Linker abstraction used by `back::link` to build up the command to invoke a |
62682a34 SL |
156 | /// linker. |
157 | /// | |
158 | /// This trait is the total list of requirements needed by `back::link` and | |
159 | /// represents the meaning of each option being passed down. This trait is then | |
160 | /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an | |
0731742a | 161 | /// MSVC linker (e.g., `link.exe`) is being used. |
62682a34 | 162 | pub trait Linker { |
ba9703b0 | 163 | fn cmd(&mut self) -> &mut Command; |
f9f354fc | 164 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); |
064997fb FG |
165 | fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool); |
166 | fn link_rust_dylib(&mut self, lib: &str, path: &Path); | |
167 | fn link_framework(&mut self, framework: &str, as_needed: bool); | |
168 | fn link_staticlib(&mut self, lib: &str, verbatim: bool); | |
62682a34 | 169 | fn link_rlib(&mut self, lib: &Path); |
c1a9b12d | 170 | fn link_whole_rlib(&mut self, lib: &Path); |
064997fb | 171 | fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]); |
62682a34 SL |
172 | fn include_path(&mut self, path: &Path); |
173 | fn framework_path(&mut self, path: &Path); | |
174 | fn output_filename(&mut self, path: &Path); | |
175 | fn add_object(&mut self, path: &Path); | |
a7813a04 | 176 | fn gc_sections(&mut self, keep_metadata: bool); |
17df50a5 | 177 | fn no_gc_sections(&mut self); |
3b2f2976 | 178 | fn full_relro(&mut self); |
0531ce1d XL |
179 | fn partial_relro(&mut self); |
180 | fn no_relro(&mut self); | |
62682a34 | 181 | fn optimize(&mut self); |
0531ce1d | 182 | fn pgo_gen(&mut self); |
74b04a01 | 183 | fn control_flow_guard(&mut self); |
923072b8 | 184 | fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); |
f9f354fc | 185 | fn no_crt_objects(&mut self); |
62682a34 | 186 | fn no_default_libraries(&mut self); |
136023e0 | 187 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); |
c30ab7b3 | 188 | fn subsystem(&mut self, subsystem: &str); |
0531ce1d XL |
189 | fn group_start(&mut self); |
190 | fn group_end(&mut self); | |
9fa01778 | 191 | fn linker_plugin_lto(&mut self); |
f035d41b | 192 | fn add_eh_frame_header(&mut self) {} |
cdc7bbd5 XL |
193 | fn add_no_exec(&mut self) {} |
194 | fn add_as_needed(&mut self) {} | |
17df50a5 | 195 | fn reset_per_library_state(&mut self) {} |
ba9703b0 XL |
196 | } |
197 | ||
198 | impl dyn Linker + '_ { | |
199 | pub fn arg(&mut self, arg: impl AsRef<OsStr>) { | |
200 | self.cmd().arg(arg); | |
201 | } | |
202 | ||
203 | pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) { | |
204 | self.cmd().args(args); | |
205 | } | |
206 | ||
207 | pub fn take_cmd(&mut self) -> Command { | |
208 | mem::replace(self.cmd(), Command::new("")) | |
209 | } | |
62682a34 SL |
210 | } |
211 | ||
cc61c64b XL |
212 | pub struct GccLinker<'a> { |
213 | cmd: Command, | |
3157f602 | 214 | sess: &'a Session, |
136023e0 | 215 | target_cpu: &'a str, |
cc61c64b XL |
216 | hinted_static: bool, // Keeps track of the current hinting mode. |
217 | // Link as ld | |
218 | is_ld: bool, | |
62682a34 SL |
219 | } |
220 | ||
cc61c64b | 221 | impl<'a> GccLinker<'a> { |
3c0e092e | 222 | /// Passes an argument directly to the linker. |
cc61c64b | 223 | /// |
3c0e092e XL |
224 | /// When the linker is not ld-like such as when using a compiler as a linker, the argument is |
225 | /// prepended by `-Wl,`. | |
226 | fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { | |
227 | self.linker_args(&[arg]); | |
228 | self | |
229 | } | |
230 | ||
231 | /// Passes a series of arguments directly to the linker. | |
232 | /// | |
233 | /// When the linker is ld-like, the arguments are simply appended to the command. When the | |
234 | /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by | |
235 | /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a | |
236 | /// single argument is appended to the command to ensure that the order of the arguments is | |
237 | /// preserved by the compiler. | |
238 | fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self { | |
239 | if self.is_ld { | |
240 | args.into_iter().for_each(|a| { | |
241 | self.cmd.arg(a); | |
242 | }); | |
cc61c64b | 243 | } else { |
3c0e092e XL |
244 | if !args.is_empty() { |
245 | let mut s = OsString::from("-Wl"); | |
246 | for a in args { | |
247 | s.push(","); | |
248 | s.push(a); | |
249 | } | |
250 | self.cmd.arg(s); | |
251 | } | |
cc61c64b XL |
252 | } |
253 | self | |
254 | } | |
255 | ||
62682a34 | 256 | fn takes_hints(&self) -> bool { |
532ac7d7 XL |
257 | // Really this function only returns true if the underlying linker |
258 | // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We | |
259 | // don't really have a foolproof way to detect that, so rule out some | |
260 | // platforms where currently this is guaranteed to *not* be the case: | |
261 | // | |
262 | // * On OSX they have their own linker, not binutils' | |
263 | // * For WebAssembly the only functional linker is LLD, which doesn't | |
264 | // support hint flags | |
cdc7bbd5 | 265 | !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm |
62682a34 | 266 | } |
cc61c64b XL |
267 | |
268 | // Some platforms take hints about whether a library is static or dynamic. | |
269 | // For those that support this, we ensure we pass the option if the library | |
270 | // was flagged "static" (most defaults are dynamic) to ensure that if | |
271 | // libfoo.a and libfoo.so both exist that the right one is chosen. | |
272 | fn hint_static(&mut self) { | |
dfeec247 XL |
273 | if !self.takes_hints() { |
274 | return; | |
275 | } | |
cc61c64b XL |
276 | if !self.hinted_static { |
277 | self.linker_arg("-Bstatic"); | |
278 | self.hinted_static = true; | |
279 | } | |
280 | } | |
281 | ||
282 | fn hint_dynamic(&mut self) { | |
dfeec247 XL |
283 | if !self.takes_hints() { |
284 | return; | |
285 | } | |
cc61c64b XL |
286 | if self.hinted_static { |
287 | self.linker_arg("-Bdynamic"); | |
288 | self.hinted_static = false; | |
289 | } | |
290 | } | |
8faf50e0 | 291 | |
9fa01778 | 292 | fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) { |
8faf50e0 XL |
293 | if let Some(plugin_path) = plugin_path { |
294 | let mut arg = OsString::from("-plugin="); | |
295 | arg.push(plugin_path); | |
296 | self.linker_arg(&arg); | |
297 | } | |
298 | ||
299 | let opt_level = match self.sess.opts.optimize { | |
300 | config::OptLevel::No => "O0", | |
301 | config::OptLevel::Less => "O1", | |
29967ef6 | 302 | config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2", |
8faf50e0 | 303 | config::OptLevel::Aggressive => "O3", |
8faf50e0 XL |
304 | }; |
305 | ||
064997fb | 306 | if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { |
c295e0f8 XL |
307 | self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); |
308 | }; | |
3c0e092e XL |
309 | self.linker_args(&[ |
310 | &format!("-plugin-opt={}", opt_level), | |
311 | &format!("-plugin-opt=mcpu={}", self.target_cpu), | |
312 | ]); | |
8faf50e0 | 313 | } |
f9f354fc XL |
314 | |
315 | fn build_dylib(&mut self, out_filename: &Path) { | |
316 | // On mac we need to tell the linker to let this library be rpathed | |
29967ef6 | 317 | if self.sess.target.is_like_osx { |
3c0e092e XL |
318 | if !self.is_ld { |
319 | self.cmd.arg("-dynamiclib"); | |
320 | } | |
321 | ||
f9f354fc XL |
322 | self.linker_arg("-dylib"); |
323 | ||
324 | // Note that the `osx_rpath_install_name` option here is a hack | |
325 | // purely to support rustbuild right now, we should get a more | |
326 | // principled solution at some point to force the compiler to pass | |
327 | // the right `-Wl,-install_name` with an `@rpath` in it. | |
064997fb | 328 | if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { |
3c0e092e XL |
329 | let mut rpath = OsString::from("@rpath/"); |
330 | rpath.push(out_filename.file_name().unwrap()); | |
331 | self.linker_args(&[OsString::from("-install_name"), rpath]); | |
f9f354fc XL |
332 | } |
333 | } else { | |
334 | self.cmd.arg("-shared"); | |
29967ef6 | 335 | if self.sess.target.is_like_windows { |
f9f354fc XL |
336 | // The output filename already contains `dll_suffix` so |
337 | // the resulting import library will have a name in the | |
338 | // form of libfoo.dll.a | |
339 | let implib_name = | |
340 | out_filename.file_name().and_then(|file| file.to_str()).map(|file| { | |
341 | format!( | |
342 | "{}{}{}", | |
29967ef6 | 343 | self.sess.target.staticlib_prefix, |
f9f354fc | 344 | file, |
29967ef6 | 345 | self.sess.target.staticlib_suffix |
f9f354fc XL |
346 | ) |
347 | }); | |
348 | if let Some(implib_name) = implib_name { | |
349 | let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); | |
350 | if let Some(implib) = implib { | |
3dfed10e | 351 | self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); |
f9f354fc XL |
352 | } |
353 | } | |
354 | } | |
355 | } | |
356 | } | |
62682a34 SL |
357 | } |
358 | ||
cc61c64b | 359 | impl<'a> Linker for GccLinker<'a> { |
ba9703b0 XL |
360 | fn cmd(&mut self) -> &mut Command { |
361 | &mut self.cmd | |
362 | } | |
f9f354fc XL |
363 | |
364 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { | |
365 | match output_kind { | |
366 | LinkOutputKind::DynamicNoPicExe => { | |
29967ef6 | 367 | if !self.is_ld && self.sess.target.linker_is_gnu { |
f9f354fc XL |
368 | self.cmd.arg("-no-pie"); |
369 | } | |
370 | } | |
371 | LinkOutputKind::DynamicPicExe => { | |
17df50a5 XL |
372 | // noop on windows w/ gcc & ld, error w/ lld |
373 | if !self.sess.target.is_like_windows { | |
374 | // `-pie` works for both gcc wrapper and ld. | |
375 | self.cmd.arg("-pie"); | |
376 | } | |
f9f354fc XL |
377 | } |
378 | LinkOutputKind::StaticNoPicExe => { | |
379 | // `-static` works for both gcc wrapper and ld. | |
380 | self.cmd.arg("-static"); | |
29967ef6 | 381 | if !self.is_ld && self.sess.target.linker_is_gnu { |
f9f354fc XL |
382 | self.cmd.arg("-no-pie"); |
383 | } | |
384 | } | |
385 | LinkOutputKind::StaticPicExe => { | |
386 | if !self.is_ld { | |
387 | // Note that combination `-static -pie` doesn't work as expected | |
388 | // for the gcc wrapper, `-static` in that case suppresses `-pie`. | |
389 | self.cmd.arg("-static-pie"); | |
390 | } else { | |
391 | // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing | |
392 | // a static pie, but currently passed because gcc and clang pass them. | |
393 | // The former suppresses the `INTERP` ELF header specifying dynamic linker, | |
394 | // which is otherwise implicitly injected by ld (but not lld). | |
395 | // The latter doesn't change anything, only ensures that everything is pic. | |
396 | self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); | |
397 | } | |
398 | } | |
399 | LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), | |
400 | LinkOutputKind::StaticDylib => { | |
401 | self.cmd.arg("-static"); | |
402 | self.build_dylib(out_filename); | |
403 | } | |
5869c6ff | 404 | LinkOutputKind::WasiReactorExe => { |
3c0e092e | 405 | self.linker_args(&["--entry", "_initialize"]); |
5869c6ff | 406 | } |
f9f354fc | 407 | } |
f035d41b XL |
408 | // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, |
409 | // it switches linking for libc and similar system libraries to static without using | |
410 | // any `#[link]` attributes in the `libc` crate, see #72782 for details. | |
411 | // FIXME: Switch to using `#[link]` attributes in the `libc` crate | |
412 | // similarly to other targets. | |
29967ef6 | 413 | if self.sess.target.os == "vxworks" |
f035d41b XL |
414 | && matches!( |
415 | output_kind, | |
416 | LinkOutputKind::StaticNoPicExe | |
417 | | LinkOutputKind::StaticPicExe | |
418 | | LinkOutputKind::StaticDylib | |
419 | ) | |
420 | { | |
421 | self.cmd.arg("--static-crt"); | |
422 | } | |
f9f354fc XL |
423 | } |
424 | ||
064997fb FG |
425 | fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) { |
426 | if self.sess.target.os == "illumos" && lib == "c" { | |
17df50a5 XL |
427 | // libc will be added via late_link_args on illumos so that it will |
428 | // appear last in the library search order. | |
429 | // FIXME: This should be replaced by a more complete and generic | |
430 | // mechanism for controlling the order of library arguments passed | |
431 | // to the linker. | |
432 | return; | |
433 | } | |
434 | if !as_needed { | |
435 | if self.sess.target.is_like_osx { | |
436 | // FIXME(81490): ld64 doesn't support these flags but macOS 11 | |
437 | // has -needed-l{} / -needed_library {} | |
438 | // but we have no way to detect that here. | |
439 | self.sess.warn("`as-needed` modifier not implemented yet for ld64"); | |
440 | } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { | |
441 | self.linker_arg("--no-as-needed"); | |
442 | } else { | |
443 | self.sess.warn("`as-needed` modifier not supported for current linker"); | |
444 | } | |
445 | } | |
e1599b0c | 446 | self.hint_dynamic(); |
17df50a5 XL |
447 | self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); |
448 | if !as_needed { | |
449 | if self.sess.target.is_like_osx { | |
450 | // See above FIXME comment | |
451 | } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { | |
452 | self.linker_arg("--as-needed"); | |
453 | } | |
454 | } | |
e1599b0c | 455 | } |
064997fb | 456 | fn link_staticlib(&mut self, lib: &str, verbatim: bool) { |
e1599b0c | 457 | self.hint_static(); |
17df50a5 | 458 | self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); |
8faf50e0 | 459 | } |
dfeec247 XL |
460 | fn link_rlib(&mut self, lib: &Path) { |
461 | self.hint_static(); | |
462 | self.cmd.arg(lib); | |
463 | } | |
464 | fn include_path(&mut self, path: &Path) { | |
465 | self.cmd.arg("-L").arg(path); | |
466 | } | |
467 | fn framework_path(&mut self, path: &Path) { | |
468 | self.cmd.arg("-F").arg(path); | |
469 | } | |
470 | fn output_filename(&mut self, path: &Path) { | |
471 | self.cmd.arg("-o").arg(path); | |
472 | } | |
473 | fn add_object(&mut self, path: &Path) { | |
474 | self.cmd.arg(path); | |
475 | } | |
dfeec247 | 476 | fn full_relro(&mut self) { |
3c0e092e | 477 | self.linker_args(&["-zrelro", "-znow"]); |
dfeec247 XL |
478 | } |
479 | fn partial_relro(&mut self) { | |
480 | self.linker_arg("-zrelro"); | |
481 | } | |
482 | fn no_relro(&mut self) { | |
483 | self.linker_arg("-znorelro"); | |
484 | } | |
62682a34 | 485 | |
064997fb | 486 | fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { |
cc61c64b | 487 | self.hint_dynamic(); |
a1dfa0c6 | 488 | self.cmd.arg(format!("-l{}", lib)); |
c1a9b12d SL |
489 | } |
490 | ||
064997fb | 491 | fn link_framework(&mut self, framework: &str, as_needed: bool) { |
cc61c64b | 492 | self.hint_dynamic(); |
17df50a5 XL |
493 | if !as_needed { |
494 | // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework | |
495 | // flag but we have no way to detect that here. | |
064997fb | 496 | // self.cmd.arg("-needed_framework").arg(framework); |
17df50a5 XL |
497 | self.sess.warn("`as-needed` modifier not implemented yet for ld64"); |
498 | } | |
064997fb | 499 | self.cmd.arg("-framework").arg(framework); |
62682a34 SL |
500 | } |
501 | ||
cc61c64b XL |
502 | // Here we explicitly ask that the entire archive is included into the |
503 | // result artifact. For more details see #15460, but the gist is that | |
504 | // the linker will strip away any unused objects in the archive if we | |
505 | // don't otherwise explicitly reference them. This can occur for | |
506 | // libraries which are just providing bindings, libraries with generic | |
507 | // functions, etc. | |
064997fb | 508 | fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { |
cc61c64b | 509 | self.hint_static(); |
29967ef6 XL |
510 | let target = &self.sess.target; |
511 | if !target.is_like_osx { | |
17df50a5 XL |
512 | self.linker_arg("--whole-archive").cmd.arg(format!( |
513 | "-l{}{}", | |
514 | if verbatim { ":" } else { "" }, | |
515 | lib | |
516 | )); | |
cc61c64b | 517 | self.linker_arg("--no-whole-archive"); |
62682a34 | 518 | } else { |
cc61c64b | 519 | // -force_load is the macOS equivalent of --whole-archive, but it |
62682a34 | 520 | // involves passing the full path to the library to link. |
8faf50e0 | 521 | self.linker_arg("-force_load"); |
17df50a5 | 522 | let lib = archive::find_library(lib, verbatim, search_path, &self.sess); |
8faf50e0 | 523 | self.linker_arg(&lib); |
c1a9b12d SL |
524 | } |
525 | } | |
526 | ||
527 | fn link_whole_rlib(&mut self, lib: &Path) { | |
cc61c64b | 528 | self.hint_static(); |
29967ef6 | 529 | if self.sess.target.is_like_osx { |
8faf50e0 XL |
530 | self.linker_arg("-force_load"); |
531 | self.linker_arg(&lib); | |
c1a9b12d | 532 | } else { |
cc61c64b XL |
533 | self.linker_arg("--whole-archive").cmd.arg(lib); |
534 | self.linker_arg("--no-whole-archive"); | |
62682a34 SL |
535 | } |
536 | } | |
537 | ||
a7813a04 | 538 | fn gc_sections(&mut self, keep_metadata: bool) { |
62682a34 SL |
539 | // The dead_strip option to the linker specifies that functions and data |
540 | // unreachable by the entry point will be removed. This is quite useful | |
541 | // with Rust's compilation model of compiling libraries at a time into | |
542 | // one object file. For example, this brings hello world from 1.7MB to | |
543 | // 458K. | |
544 | // | |
545 | // Note that this is done for both executables and dynamic libraries. We | |
546 | // won't get much benefit from dylibs because LLVM will have already | |
547 | // stripped away as much as it could. This has not been seen to impact | |
548 | // link times negatively. | |
549 | // | |
550 | // -dead_strip can't be part of the pre_link_args because it's also used | |
551 | // for partial linking when using multiple codegen units (-r). So we | |
552 | // insert it here. | |
29967ef6 | 553 | if self.sess.target.is_like_osx { |
cc61c64b | 554 | self.linker_arg("-dead_strip"); |
62682a34 SL |
555 | |
556 | // If we're building a dylib, we don't use --gc-sections because LLVM | |
557 | // has already done the best it can do, and we also don't want to | |
558 | // eliminate the metadata. If we're building an executable, however, | |
559 | // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% | |
560 | // reduction. | |
17df50a5 XL |
561 | } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm) |
562 | && !keep_metadata | |
563 | { | |
cc61c64b | 564 | self.linker_arg("--gc-sections"); |
62682a34 SL |
565 | } |
566 | } | |
567 | ||
17df50a5 | 568 | fn no_gc_sections(&mut self) { |
064997fb | 569 | if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm { |
17df50a5 XL |
570 | self.linker_arg("--no-gc-sections"); |
571 | } | |
572 | } | |
573 | ||
62682a34 | 574 | fn optimize(&mut self) { |
17df50a5 | 575 | if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm { |
dfeec247 XL |
576 | return; |
577 | } | |
62682a34 SL |
578 | |
579 | // GNU-style linkers support optimization with -O. GNU ld doesn't | |
580 | // need a numeric argument, but other linkers do. | |
dfeec247 XL |
581 | if self.sess.opts.optimize == config::OptLevel::Default |
582 | || self.sess.opts.optimize == config::OptLevel::Aggressive | |
583 | { | |
cc61c64b | 584 | self.linker_arg("-O1"); |
62682a34 SL |
585 | } |
586 | } | |
587 | ||
0531ce1d | 588 | fn pgo_gen(&mut self) { |
29967ef6 | 589 | if !self.sess.target.linker_is_gnu { |
dfeec247 XL |
590 | return; |
591 | } | |
0531ce1d XL |
592 | |
593 | // If we're doing PGO generation stuff and on a GNU-like linker, use the | |
594 | // "-u" flag to properly pull in the profiler runtime bits. | |
595 | // | |
596 | // This is because LLVM otherwise won't add the needed initialization | |
597 | // for us on Linux (though the extra flag should be harmless if it | |
598 | // does). | |
599 | // | |
600 | // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. | |
601 | // | |
602 | // Though it may be worth to try to revert those changes upstream, since | |
603 | // the overhead of the initialization should be minor. | |
604 | self.cmd.arg("-u"); | |
605 | self.cmd.arg("__llvm_profile_runtime"); | |
606 | } | |
607 | ||
f035d41b | 608 | fn control_flow_guard(&mut self) {} |
74b04a01 | 609 | |
04454e1e | 610 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
17df50a5 XL |
611 | // MacOS linker doesn't support stripping symbols directly anymore. |
612 | if self.sess.target.is_like_osx { | |
613 | return; | |
614 | } | |
615 | ||
f9f354fc XL |
616 | match strip { |
617 | Strip::None => {} | |
618 | Strip::Debuginfo => { | |
17df50a5 | 619 | self.linker_arg("--strip-debug"); |
a1dfa0c6 | 620 | } |
f9f354fc | 621 | Strip::Symbols => { |
17df50a5 | 622 | self.linker_arg("--strip-all"); |
f9f354fc XL |
623 | } |
624 | } | |
c1a9b12d SL |
625 | } |
626 | ||
f9f354fc | 627 | fn no_crt_objects(&mut self) { |
cc61c64b | 628 | if !self.is_ld { |
f9f354fc | 629 | self.cmd.arg("-nostartfiles"); |
cc61c64b | 630 | } |
62682a34 SL |
631 | } |
632 | ||
f9f354fc XL |
633 | fn no_default_libraries(&mut self) { |
634 | if !self.is_ld { | |
635 | self.cmd.arg("-nodefaultlibs"); | |
62682a34 SL |
636 | } |
637 | } | |
638 | ||
136023e0 | 639 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { |
48663c56 | 640 | // Symbol visibility in object files typically takes care of this. |
064997fb FG |
641 | if crate_type == CrateType::Executable { |
642 | let should_export_executable_symbols = | |
643 | self.sess.opts.unstable_opts.export_executable_symbols; | |
644 | if self.sess.target.override_export_symbols.is_none() | |
645 | && !should_export_executable_symbols | |
646 | { | |
647 | return; | |
648 | } | |
48663c56 XL |
649 | } |
650 | ||
dc9dc135 XL |
651 | // We manually create a list of exported symbols to ensure we don't expose any more. |
652 | // The object files have far more public symbols than we actually want to export, | |
653 | // so we hide them all here. | |
a7813a04 | 654 | |
29967ef6 | 655 | if !self.sess.target.limit_rdylib_exports { |
532ac7d7 XL |
656 | return; |
657 | } | |
658 | ||
064997fb | 659 | // FIXME(#99978) hide #[no_mangle] symbols for proc-macros |
dc9dc135 | 660 | |
29967ef6 | 661 | let is_windows = self.sess.target.is_like_windows; |
3dfed10e | 662 | let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); |
9e0c209e | 663 | |
476ff2be SL |
664 | debug!("EXPORTED SYMBOLS:"); |
665 | ||
29967ef6 | 666 | if self.sess.target.is_like_osx { |
476ff2be | 667 | // Write a plain, newline-separated list of symbols |
532ac7d7 | 668 | let res: io::Result<()> = try { |
9e0c209e | 669 | let mut f = BufWriter::new(File::create(&path)?); |
136023e0 | 670 | for sym in symbols { |
476ff2be SL |
671 | debug!(" _{}", sym); |
672 | writeln!(f, "_{}", sym)?; | |
9e0c209e | 673 | } |
532ac7d7 | 674 | }; |
9e0c209e | 675 | if let Err(e) = res { |
476ff2be | 676 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
a7813a04 | 677 | } |
3dfed10e XL |
678 | } else if is_windows { |
679 | let res: io::Result<()> = try { | |
680 | let mut f = BufWriter::new(File::create(&path)?); | |
681 | ||
682 | // .def file similar to MSVC one but without LIBRARY section | |
683 | // because LD doesn't like when it's empty | |
684 | writeln!(f, "EXPORTS")?; | |
136023e0 | 685 | for symbol in symbols { |
3dfed10e XL |
686 | debug!(" _{}", symbol); |
687 | writeln!(f, " {}", symbol)?; | |
688 | } | |
689 | }; | |
690 | if let Err(e) = res { | |
691 | self.sess.fatal(&format!("failed to write list.def file: {}", e)); | |
692 | } | |
a7813a04 | 693 | } else { |
476ff2be | 694 | // Write an LD version script |
532ac7d7 | 695 | let res: io::Result<()> = try { |
9e0c209e | 696 | let mut f = BufWriter::new(File::create(&path)?); |
e1599b0c | 697 | writeln!(f, "{{")?; |
136023e0 | 698 | if !symbols.is_empty() { |
e1599b0c | 699 | writeln!(f, " global:")?; |
136023e0 | 700 | for sym in symbols { |
e1599b0c XL |
701 | debug!(" {};", sym); |
702 | writeln!(f, " {};", sym)?; | |
703 | } | |
9e0c209e | 704 | } |
476ff2be | 705 | writeln!(f, "\n local:\n *;\n}};")?; |
532ac7d7 | 706 | }; |
9e0c209e | 707 | if let Err(e) = res { |
476ff2be | 708 | self.sess.fatal(&format!("failed to write version script: {}", e)); |
9e0c209e | 709 | } |
a7813a04 | 710 | } |
9e0c209e | 711 | |
29967ef6 | 712 | if self.sess.target.is_like_osx { |
3c0e092e | 713 | self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); |
29967ef6 | 714 | } else if self.sess.target.is_like_solaris { |
3c0e092e | 715 | self.linker_args(&[OsString::from("-M"), path.into()]); |
476ff2be | 716 | } else { |
3c0e092e XL |
717 | if is_windows { |
718 | self.linker_arg(path); | |
719 | } else { | |
720 | let mut arg = OsString::from("--version-script="); | |
721 | arg.push(path); | |
722 | self.linker_arg(arg); | |
3dfed10e | 723 | } |
476ff2be | 724 | } |
e9174d1e | 725 | } |
c30ab7b3 SL |
726 | |
727 | fn subsystem(&mut self, subsystem: &str) { | |
8faf50e0 XL |
728 | self.linker_arg("--subsystem"); |
729 | self.linker_arg(&subsystem); | |
cc61c64b XL |
730 | } |
731 | ||
17df50a5 | 732 | fn reset_per_library_state(&mut self) { |
cc61c64b | 733 | self.hint_dynamic(); // Reset to default before returning the composed command line. |
c30ab7b3 | 734 | } |
0531ce1d XL |
735 | |
736 | fn group_start(&mut self) { | |
532ac7d7 | 737 | if self.takes_hints() { |
0531ce1d XL |
738 | self.linker_arg("--start-group"); |
739 | } | |
740 | } | |
741 | ||
742 | fn group_end(&mut self) { | |
532ac7d7 | 743 | if self.takes_hints() { |
0531ce1d XL |
744 | self.linker_arg("--end-group"); |
745 | } | |
746 | } | |
94b46f34 | 747 | |
9fa01778 XL |
748 | fn linker_plugin_lto(&mut self) { |
749 | match self.sess.opts.cg.linker_plugin_lto { | |
750 | LinkerPluginLto::Disabled => { | |
94b46f34 XL |
751 | // Nothing to do |
752 | } | |
9fa01778 XL |
753 | LinkerPluginLto::LinkerPluginAuto => { |
754 | self.push_linker_plugin_lto_args(None); | |
8faf50e0 | 755 | } |
9fa01778 XL |
756 | LinkerPluginLto::LinkerPlugin(ref path) => { |
757 | self.push_linker_plugin_lto_args(Some(path.as_os_str())); | |
94b46f34 XL |
758 | } |
759 | } | |
760 | } | |
f035d41b XL |
761 | |
762 | // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information. | |
763 | // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, | |
764 | // so we just always add it. | |
765 | fn add_eh_frame_header(&mut self) { | |
f9652781 | 766 | self.linker_arg("--eh-frame-hdr"); |
f035d41b | 767 | } |
cdc7bbd5 XL |
768 | |
769 | fn add_no_exec(&mut self) { | |
770 | if self.sess.target.is_like_windows { | |
771 | self.linker_arg("--nxcompat"); | |
772 | } else if self.sess.target.linker_is_gnu { | |
773 | self.linker_arg("-znoexecstack"); | |
774 | } | |
775 | } | |
776 | ||
777 | fn add_as_needed(&mut self) { | |
17df50a5 | 778 | if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { |
cdc7bbd5 | 779 | self.linker_arg("--as-needed"); |
17df50a5 XL |
780 | } else if self.sess.target.is_like_solaris { |
781 | // -z ignore is the Solaris equivalent to the GNU ld --as-needed option | |
3c0e092e | 782 | self.linker_args(&["-z", "ignore"]); |
cdc7bbd5 XL |
783 | } |
784 | } | |
62682a34 SL |
785 | } |
786 | ||
787 | pub struct MsvcLinker<'a> { | |
cc61c64b | 788 | cmd: Command, |
3157f602 | 789 | sess: &'a Session, |
62682a34 SL |
790 | } |
791 | ||
792 | impl<'a> Linker for MsvcLinker<'a> { | |
ba9703b0 XL |
793 | fn cmd(&mut self) -> &mut Command { |
794 | &mut self.cmd | |
795 | } | |
f9f354fc XL |
796 | |
797 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { | |
798 | match output_kind { | |
799 | LinkOutputKind::DynamicNoPicExe | |
800 | | LinkOutputKind::DynamicPicExe | |
801 | | LinkOutputKind::StaticNoPicExe | |
802 | | LinkOutputKind::StaticPicExe => {} | |
803 | LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { | |
804 | self.cmd.arg("/DLL"); | |
805 | let mut arg: OsString = "/IMPLIB:".into(); | |
806 | arg.push(out_filename.with_extension("dll.lib")); | |
807 | self.cmd.arg(arg); | |
808 | } | |
5869c6ff XL |
809 | LinkOutputKind::WasiReactorExe => { |
810 | panic!("can't link as reactor on non-wasi target"); | |
811 | } | |
f9f354fc XL |
812 | } |
813 | } | |
814 | ||
dfeec247 XL |
815 | fn link_rlib(&mut self, lib: &Path) { |
816 | self.cmd.arg(lib); | |
817 | } | |
818 | fn add_object(&mut self, path: &Path) { | |
819 | self.cmd.arg(path); | |
820 | } | |
7453a54e | 821 | |
a7813a04 | 822 | fn gc_sections(&mut self, _keep_metadata: bool) { |
476ff2be SL |
823 | // MSVC's ICF (Identical COMDAT Folding) link optimization is |
824 | // slow for Rust and thus we disable it by default when not in | |
825 | // optimization build. | |
826 | if self.sess.opts.optimize != config::OptLevel::No { | |
827 | self.cmd.arg("/OPT:REF,ICF"); | |
828 | } else { | |
829 | // It is necessary to specify NOICF here, because /OPT:REF | |
830 | // implies ICF by default. | |
831 | self.cmd.arg("/OPT:REF,NOICF"); | |
832 | } | |
a7813a04 | 833 | } |
62682a34 | 834 | |
17df50a5 XL |
835 | fn no_gc_sections(&mut self) { |
836 | self.cmd.arg("/OPT:NOREF,NOICF"); | |
837 | } | |
838 | ||
064997fb | 839 | fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { |
17df50a5 | 840 | self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); |
62682a34 | 841 | } |
c1a9b12d | 842 | |
064997fb | 843 | fn link_rust_dylib(&mut self, lib: &str, path: &Path) { |
c1a9b12d SL |
844 | // When producing a dll, the MSVC linker may not actually emit a |
845 | // `foo.lib` file if the dll doesn't actually export any symbols, so we | |
846 | // check to see if the file is there and just omit linking to it if it's | |
847 | // not present. | |
7453a54e | 848 | let name = format!("{}.dll.lib", lib); |
17df50a5 | 849 | if path.join(&name).exists() { |
c1a9b12d SL |
850 | self.cmd.arg(name); |
851 | } | |
852 | } | |
853 | ||
064997fb | 854 | fn link_staticlib(&mut self, lib: &str, verbatim: bool) { |
17df50a5 | 855 | self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); |
62682a34 SL |
856 | } |
857 | ||
3b2f2976 XL |
858 | fn full_relro(&mut self) { |
859 | // noop | |
860 | } | |
861 | ||
0531ce1d XL |
862 | fn partial_relro(&mut self) { |
863 | // noop | |
864 | } | |
865 | ||
866 | fn no_relro(&mut self) { | |
867 | // noop | |
868 | } | |
869 | ||
f9f354fc XL |
870 | fn no_crt_objects(&mut self) { |
871 | // noop | |
872 | } | |
873 | ||
62682a34 | 874 | fn no_default_libraries(&mut self) { |
ba9703b0 | 875 | self.cmd.arg("/NODEFAULTLIB"); |
62682a34 SL |
876 | } |
877 | ||
878 | fn include_path(&mut self, path: &Path) { | |
879 | let mut arg = OsString::from("/LIBPATH:"); | |
880 | arg.push(path); | |
881 | self.cmd.arg(&arg); | |
882 | } | |
883 | ||
884 | fn output_filename(&mut self, path: &Path) { | |
885 | let mut arg = OsString::from("/OUT:"); | |
886 | arg.push(path); | |
887 | self.cmd.arg(&arg); | |
888 | } | |
889 | ||
890 | fn framework_path(&mut self, _path: &Path) { | |
54a0048b | 891 | bug!("frameworks are not supported on windows") |
62682a34 | 892 | } |
064997fb | 893 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
54a0048b | 894 | bug!("frameworks are not supported on windows") |
62682a34 SL |
895 | } |
896 | ||
064997fb | 897 | fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { |
17df50a5 | 898 | self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); |
62682a34 | 899 | } |
c1a9b12d | 900 | fn link_whole_rlib(&mut self, path: &Path) { |
f035d41b XL |
901 | let mut arg = OsString::from("/WHOLEARCHIVE:"); |
902 | arg.push(path); | |
903 | self.cmd.arg(arg); | |
c1a9b12d | 904 | } |
62682a34 SL |
905 | fn optimize(&mut self) { |
906 | // Needs more investigation of `/OPT` arguments | |
907 | } | |
c1a9b12d | 908 | |
0531ce1d XL |
909 | fn pgo_gen(&mut self) { |
910 | // Nothing needed here. | |
911 | } | |
912 | ||
74b04a01 XL |
913 | fn control_flow_guard(&mut self) { |
914 | self.cmd.arg("/guard:cf"); | |
915 | } | |
916 | ||
923072b8 | 917 | fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { |
f9f354fc XL |
918 | match strip { |
919 | Strip::None => { | |
920 | // This will cause the Microsoft linker to generate a PDB file | |
921 | // from the CodeView line tables in the object files. | |
922 | self.cmd.arg("/DEBUG"); | |
923 | ||
924 | // This will cause the Microsoft linker to embed .natvis info into the PDB file | |
925 | let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); | |
926 | if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { | |
927 | for entry in natvis_dir { | |
928 | match entry { | |
929 | Ok(entry) => { | |
930 | let path = entry.path(); | |
931 | if path.extension() == Some("natvis".as_ref()) { | |
932 | let mut arg = OsString::from("/NATVIS:"); | |
933 | arg.push(path); | |
934 | self.cmd.arg(arg); | |
935 | } | |
936 | } | |
937 | Err(err) => { | |
938 | self.sess | |
939 | .warn(&format!("error enumerating natvis directory: {}", err)); | |
940 | } | |
3b2f2976 | 941 | } |
dfeec247 | 942 | } |
3b2f2976 | 943 | } |
04454e1e FG |
944 | |
945 | // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file | |
923072b8 | 946 | for path in natvis_debugger_visualizers { |
04454e1e FG |
947 | let mut arg = OsString::from("/NATVIS:"); |
948 | arg.push(path); | |
949 | self.cmd.arg(arg); | |
950 | } | |
3b2f2976 | 951 | } |
f9f354fc XL |
952 | Strip::Debuginfo | Strip::Symbols => { |
953 | self.cmd.arg("/DEBUG:NONE"); | |
954 | } | |
3b2f2976 | 955 | } |
c1a9b12d SL |
956 | } |
957 | ||
e9174d1e SL |
958 | // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to |
959 | // export symbols from a dynamic library. When building a dynamic library, | |
960 | // however, we're going to want some symbols exported, so this function | |
961 | // generates a DEF file which lists all the symbols. | |
962 | // | |
963 | // The linker will read this `*.def` file and export all the symbols from | |
964 | // the dynamic library. Note that this is not as simple as just exporting | |
94b46f34 | 965 | // all the symbols in the current crate (as specified by `codegen.reachable`) |
e9174d1e SL |
966 | // but rather we also need to possibly export the symbols of upstream |
967 | // crates. Upstream rlibs may be linked statically to this dynamic library, | |
968 | // in which case they may continue to transitively be used and hence need | |
969 | // their symbols exported. | |
136023e0 | 970 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { |
48663c56 XL |
971 | // Symbol visibility takes care of this typically |
972 | if crate_type == CrateType::Executable { | |
064997fb FG |
973 | let should_export_executable_symbols = |
974 | self.sess.opts.unstable_opts.export_executable_symbols; | |
975 | if !should_export_executable_symbols { | |
976 | return; | |
977 | } | |
48663c56 XL |
978 | } |
979 | ||
e9174d1e | 980 | let path = tmpdir.join("lib.def"); |
532ac7d7 | 981 | let res: io::Result<()> = try { |
54a0048b | 982 | let mut f = BufWriter::new(File::create(&path)?); |
e9174d1e SL |
983 | |
984 | // Start off with the standard module name header and then go | |
985 | // straight to exports. | |
54a0048b SL |
986 | writeln!(f, "LIBRARY")?; |
987 | writeln!(f, "EXPORTS")?; | |
136023e0 | 988 | for symbol in symbols { |
8bb4bdeb | 989 | debug!(" _{}", symbol); |
3157f602 | 990 | writeln!(f, " {}", symbol)?; |
e9174d1e | 991 | } |
532ac7d7 | 992 | }; |
e9174d1e | 993 | if let Err(e) = res { |
3157f602 | 994 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
e9174d1e SL |
995 | } |
996 | let mut arg = OsString::from("/DEF:"); | |
997 | arg.push(path); | |
998 | self.cmd.arg(&arg); | |
999 | } | |
c30ab7b3 SL |
1000 | |
1001 | fn subsystem(&mut self, subsystem: &str) { | |
1002 | // Note that previous passes of the compiler validated this subsystem, | |
1003 | // so we just blindly pass it to the linker. | |
1004 | self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); | |
1005 | ||
1006 | // Windows has two subsystems we're interested in right now, the console | |
1007 | // and windows subsystems. These both implicitly have different entry | |
1008 | // points (starting symbols). The console entry point starts with | |
1009 | // `mainCRTStartup` and the windows entry point starts with | |
1010 | // `WinMainCRTStartup`. These entry points, defined in system libraries, | |
1011 | // will then later probe for either `main` or `WinMain`, respectively to | |
1012 | // start the application. | |
1013 | // | |
1014 | // In Rust we just always generate a `main` function so we want control | |
1015 | // to always start there, so we force the entry point on the windows | |
1016 | // subsystem to be `mainCRTStartup` to get everything booted up | |
1017 | // correctly. | |
1018 | // | |
1019 | // For more information see RFC #1665 | |
1020 | if subsystem == "windows" { | |
1021 | self.cmd.arg("/ENTRY:mainCRTStartup"); | |
1022 | } | |
1023 | } | |
cc61c64b | 1024 | |
0531ce1d XL |
1025 | // MSVC doesn't need group indicators |
1026 | fn group_start(&mut self) {} | |
1027 | fn group_end(&mut self) {} | |
94b46f34 | 1028 | |
9fa01778 | 1029 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1030 | // Do nothing |
1031 | } | |
cdc7bbd5 XL |
1032 | |
1033 | fn add_no_exec(&mut self) { | |
1034 | self.cmd.arg("/NXCOMPAT"); | |
1035 | } | |
62682a34 | 1036 | } |
a7813a04 | 1037 | |
8bb4bdeb | 1038 | pub struct EmLinker<'a> { |
cc61c64b | 1039 | cmd: Command, |
8bb4bdeb | 1040 | sess: &'a Session, |
8bb4bdeb XL |
1041 | } |
1042 | ||
1043 | impl<'a> Linker for EmLinker<'a> { | |
ba9703b0 XL |
1044 | fn cmd(&mut self) -> &mut Command { |
1045 | &mut self.cmd | |
1046 | } | |
f9f354fc XL |
1047 | |
1048 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1049 | ||
8bb4bdeb XL |
1050 | fn include_path(&mut self, path: &Path) { |
1051 | self.cmd.arg("-L").arg(path); | |
1052 | } | |
1053 | ||
064997fb FG |
1054 | fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { |
1055 | self.cmd.arg("-l").arg(lib); | |
8bb4bdeb XL |
1056 | } |
1057 | ||
1058 | fn output_filename(&mut self, path: &Path) { | |
1059 | self.cmd.arg("-o").arg(path); | |
1060 | } | |
1061 | ||
1062 | fn add_object(&mut self, path: &Path) { | |
1063 | self.cmd.arg(path); | |
1064 | } | |
1065 | ||
064997fb | 1066 | fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { |
8bb4bdeb | 1067 | // Emscripten always links statically |
17df50a5 | 1068 | self.link_staticlib(lib, verbatim); |
8bb4bdeb XL |
1069 | } |
1070 | ||
064997fb | 1071 | fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { |
8bb4bdeb | 1072 | // not supported? |
17df50a5 | 1073 | self.link_staticlib(lib, verbatim); |
8bb4bdeb XL |
1074 | } |
1075 | ||
1076 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1077 | // not supported? | |
1078 | self.link_rlib(lib); | |
1079 | } | |
1080 | ||
064997fb | 1081 | fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { |
17df50a5 | 1082 | self.link_dylib(lib, false, true); |
8bb4bdeb XL |
1083 | } |
1084 | ||
1085 | fn link_rlib(&mut self, lib: &Path) { | |
1086 | self.add_object(lib); | |
1087 | } | |
1088 | ||
3b2f2976 XL |
1089 | fn full_relro(&mut self) { |
1090 | // noop | |
1091 | } | |
1092 | ||
0531ce1d XL |
1093 | fn partial_relro(&mut self) { |
1094 | // noop | |
1095 | } | |
1096 | ||
1097 | fn no_relro(&mut self) { | |
1098 | // noop | |
1099 | } | |
1100 | ||
8bb4bdeb XL |
1101 | fn framework_path(&mut self, _path: &Path) { |
1102 | bug!("frameworks are not supported on Emscripten") | |
1103 | } | |
1104 | ||
064997fb | 1105 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
8bb4bdeb XL |
1106 | bug!("frameworks are not supported on Emscripten") |
1107 | } | |
1108 | ||
1109 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
1110 | // noop | |
1111 | } | |
1112 | ||
17df50a5 XL |
1113 | fn no_gc_sections(&mut self) { |
1114 | // noop | |
1115 | } | |
1116 | ||
8bb4bdeb XL |
1117 | fn optimize(&mut self) { |
1118 | // Emscripten performs own optimizations | |
1119 | self.cmd.arg(match self.sess.opts.optimize { | |
1120 | OptLevel::No => "-O0", | |
1121 | OptLevel::Less => "-O1", | |
1122 | OptLevel::Default => "-O2", | |
1123 | OptLevel::Aggressive => "-O3", | |
1124 | OptLevel::Size => "-Os", | |
dfeec247 | 1125 | OptLevel::SizeMin => "-Oz", |
8bb4bdeb | 1126 | }); |
8bb4bdeb XL |
1127 | } |
1128 | ||
0531ce1d XL |
1129 | fn pgo_gen(&mut self) { |
1130 | // noop, but maybe we need something like the gnu linker? | |
1131 | } | |
1132 | ||
f035d41b | 1133 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1134 | |
04454e1e | 1135 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
8bb4bdeb XL |
1136 | // Preserve names or generate source maps depending on debug info |
1137 | self.cmd.arg(match self.sess.opts.debuginfo { | |
b7449926 | 1138 | DebugInfo::None => "-g0", |
923072b8 FG |
1139 | DebugInfo::Limited => "--profiling-funcs", |
1140 | DebugInfo::Full => "-g", | |
8bb4bdeb XL |
1141 | }); |
1142 | } | |
1143 | ||
f9f354fc XL |
1144 | fn no_crt_objects(&mut self) {} |
1145 | ||
8bb4bdeb | 1146 | fn no_default_libraries(&mut self) { |
923072b8 | 1147 | self.cmd.arg("-nodefaultlibs"); |
8bb4bdeb XL |
1148 | } |
1149 | ||
136023e0 | 1150 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
8bb4bdeb XL |
1151 | debug!("EXPORTED SYMBOLS:"); |
1152 | ||
1153 | self.cmd.arg("-s"); | |
1154 | ||
1155 | let mut arg = OsString::from("EXPORTED_FUNCTIONS="); | |
923072b8 FG |
1156 | let encoded = serde_json::to_string( |
1157 | &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(), | |
1158 | ) | |
1159 | .unwrap(); | |
8bb4bdeb | 1160 | debug!("{}", encoded); |
923072b8 | 1161 | |
8bb4bdeb XL |
1162 | arg.push(encoded); |
1163 | ||
1164 | self.cmd.arg(arg); | |
1165 | } | |
1166 | ||
1167 | fn subsystem(&mut self, _subsystem: &str) { | |
1168 | // noop | |
1169 | } | |
cc61c64b | 1170 | |
0531ce1d XL |
1171 | // Appears not necessary on Emscripten |
1172 | fn group_start(&mut self) {} | |
1173 | fn group_end(&mut self) {} | |
94b46f34 | 1174 | |
9fa01778 | 1175 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1176 | // Do nothing |
1177 | } | |
8bb4bdeb XL |
1178 | } |
1179 | ||
8faf50e0 | 1180 | pub struct WasmLd<'a> { |
0531ce1d | 1181 | cmd: Command, |
8faf50e0 | 1182 | sess: &'a Session, |
0531ce1d XL |
1183 | } |
1184 | ||
0731742a | 1185 | impl<'a> WasmLd<'a> { |
136023e0 | 1186 | fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { |
416331ca XL |
1187 | // If the atomics feature is enabled for wasm then we need a whole bunch |
1188 | // of flags: | |
1189 | // | |
1190 | // * `--shared-memory` - the link won't even succeed without this, flags | |
1191 | // the one linear memory as `shared` | |
1192 | // | |
1193 | // * `--max-memory=1G` - when specifying a shared memory this must also | |
1194 | // be specified. We conservatively choose 1GB but users should be able | |
1195 | // to override this with `-C link-arg`. | |
1196 | // | |
1197 | // * `--import-memory` - it doesn't make much sense for memory to be | |
1198 | // exported in a threaded module because typically you're | |
1199 | // sharing memory and instantiating the module multiple times. As a | |
1200 | // result if it were exported then we'd just have no sharing. | |
1201 | // | |
416331ca XL |
1202 | // * `--export=__wasm_init_memory` - when using `--passive-segments` the |
1203 | // linker will synthesize this function, and so we need to make sure | |
1204 | // that our usage of `--export` below won't accidentally cause this | |
1205 | // function to get deleted. | |
1206 | // | |
1207 | // * `--export=*tls*` - when `#[thread_local]` symbols are used these | |
1208 | // symbols are how the TLS segments are initialized and configured. | |
f035d41b | 1209 | if sess.target_features.contains(&sym::atomics) { |
416331ca XL |
1210 | cmd.arg("--shared-memory"); |
1211 | cmd.arg("--max-memory=1073741824"); | |
1212 | cmd.arg("--import-memory"); | |
416331ca XL |
1213 | cmd.arg("--export=__wasm_init_memory"); |
1214 | cmd.arg("--export=__wasm_init_tls"); | |
1215 | cmd.arg("--export=__tls_size"); | |
1216 | cmd.arg("--export=__tls_align"); | |
1217 | cmd.arg("--export=__tls_base"); | |
1218 | } | |
136023e0 | 1219 | WasmLd { cmd, sess } |
0731742a XL |
1220 | } |
1221 | } | |
1222 | ||
8faf50e0 | 1223 | impl<'a> Linker for WasmLd<'a> { |
ba9703b0 XL |
1224 | fn cmd(&mut self) -> &mut Command { |
1225 | &mut self.cmd | |
1226 | } | |
1227 | ||
f9f354fc XL |
1228 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { |
1229 | match output_kind { | |
1230 | LinkOutputKind::DynamicNoPicExe | |
1231 | | LinkOutputKind::DynamicPicExe | |
1232 | | LinkOutputKind::StaticNoPicExe | |
1233 | | LinkOutputKind::StaticPicExe => {} | |
1234 | LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { | |
1235 | self.cmd.arg("--no-entry"); | |
1236 | } | |
5869c6ff XL |
1237 | LinkOutputKind::WasiReactorExe => { |
1238 | self.cmd.arg("--entry"); | |
1239 | self.cmd.arg("_initialize"); | |
1240 | } | |
f9f354fc XL |
1241 | } |
1242 | } | |
1243 | ||
064997fb FG |
1244 | fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { |
1245 | self.cmd.arg("-l").arg(lib); | |
0531ce1d XL |
1246 | } |
1247 | ||
064997fb FG |
1248 | fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { |
1249 | self.cmd.arg("-l").arg(lib); | |
0531ce1d XL |
1250 | } |
1251 | ||
1252 | fn link_rlib(&mut self, lib: &Path) { | |
1253 | self.cmd.arg(lib); | |
1254 | } | |
1255 | ||
1256 | fn include_path(&mut self, path: &Path) { | |
1257 | self.cmd.arg("-L").arg(path); | |
1258 | } | |
1259 | ||
1260 | fn framework_path(&mut self, _path: &Path) { | |
1261 | panic!("frameworks not supported") | |
1262 | } | |
1263 | ||
1264 | fn output_filename(&mut self, path: &Path) { | |
1265 | self.cmd.arg("-o").arg(path); | |
1266 | } | |
1267 | ||
1268 | fn add_object(&mut self, path: &Path) { | |
1269 | self.cmd.arg(path); | |
1270 | } | |
1271 | ||
dfeec247 | 1272 | fn full_relro(&mut self) {} |
0531ce1d | 1273 | |
dfeec247 | 1274 | fn partial_relro(&mut self) {} |
0531ce1d | 1275 | |
dfeec247 | 1276 | fn no_relro(&mut self) {} |
0531ce1d | 1277 | |
064997fb FG |
1278 | fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { |
1279 | self.cmd.arg("-l").arg(lib); | |
0531ce1d XL |
1280 | } |
1281 | ||
064997fb | 1282 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
0531ce1d XL |
1283 | panic!("frameworks not supported") |
1284 | } | |
1285 | ||
064997fb FG |
1286 | fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { |
1287 | self.cmd.arg("-l").arg(lib); | |
0531ce1d XL |
1288 | } |
1289 | ||
1290 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1291 | self.cmd.arg(lib); | |
1292 | } | |
1293 | ||
1294 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
8faf50e0 | 1295 | self.cmd.arg("--gc-sections"); |
0531ce1d XL |
1296 | } |
1297 | ||
17df50a5 XL |
1298 | fn no_gc_sections(&mut self) { |
1299 | self.cmd.arg("--no-gc-sections"); | |
1300 | } | |
1301 | ||
0531ce1d | 1302 | fn optimize(&mut self) { |
8faf50e0 XL |
1303 | self.cmd.arg(match self.sess.opts.optimize { |
1304 | OptLevel::No => "-O0", | |
1305 | OptLevel::Less => "-O1", | |
1306 | OptLevel::Default => "-O2", | |
1307 | OptLevel::Aggressive => "-O3", | |
1308 | // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` | |
1309 | // instead. | |
1310 | OptLevel::Size => "-O2", | |
dfeec247 | 1311 | OptLevel::SizeMin => "-O2", |
8faf50e0 | 1312 | }); |
0531ce1d XL |
1313 | } |
1314 | ||
dfeec247 | 1315 | fn pgo_gen(&mut self) {} |
0531ce1d | 1316 | |
04454e1e | 1317 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
f9f354fc XL |
1318 | match strip { |
1319 | Strip::None => {} | |
1320 | Strip::Debuginfo => { | |
1321 | self.cmd.arg("--strip-debug"); | |
1322 | } | |
1323 | Strip::Symbols => { | |
1324 | self.cmd.arg("--strip-all"); | |
1325 | } | |
1326 | } | |
1327 | } | |
0531ce1d | 1328 | |
f035d41b | 1329 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1330 | |
f9f354fc | 1331 | fn no_crt_objects(&mut self) {} |
0531ce1d | 1332 | |
f9f354fc | 1333 | fn no_default_libraries(&mut self) {} |
0531ce1d | 1334 | |
136023e0 XL |
1335 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
1336 | for sym in symbols { | |
0bf4aa26 XL |
1337 | self.cmd.arg("--export").arg(&sym); |
1338 | } | |
416331ca | 1339 | |
f035d41b | 1340 | // LLD will hide these otherwise-internal symbols since it only exports |
5e7ed085 | 1341 | // symbols explicitly passed via the `--export` flags above and hides all |
f035d41b XL |
1342 | // others. Various bits and pieces of tooling use this, so be sure these |
1343 | // symbols make their way out of the linker as well. | |
416331ca XL |
1344 | self.cmd.arg("--export=__heap_base"); |
1345 | self.cmd.arg("--export=__data_end"); | |
0531ce1d XL |
1346 | } |
1347 | ||
dfeec247 | 1348 | fn subsystem(&mut self, _subsystem: &str) {} |
0531ce1d | 1349 | |
0531ce1d XL |
1350 | // Not needed for now with LLD |
1351 | fn group_start(&mut self) {} | |
1352 | fn group_end(&mut self) {} | |
94b46f34 | 1353 | |
9fa01778 | 1354 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1355 | // Do nothing for now |
1356 | } | |
0531ce1d | 1357 | } |
a1dfa0c6 | 1358 | |
5099ac24 FG |
1359 | /// Linker shepherd script for L4Re (Fiasco) |
1360 | pub struct L4Bender<'a> { | |
1361 | cmd: Command, | |
1362 | sess: &'a Session, | |
1363 | hinted_static: bool, | |
1364 | } | |
1365 | ||
1366 | impl<'a> Linker for L4Bender<'a> { | |
064997fb | 1367 | fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { |
5099ac24 FG |
1368 | bug!("dylibs are not supported on L4Re"); |
1369 | } | |
064997fb | 1370 | fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { |
5099ac24 FG |
1371 | self.hint_static(); |
1372 | self.cmd.arg(format!("-PC{}", lib)); | |
1373 | } | |
1374 | fn link_rlib(&mut self, lib: &Path) { | |
1375 | self.hint_static(); | |
1376 | self.cmd.arg(lib); | |
1377 | } | |
1378 | fn include_path(&mut self, path: &Path) { | |
1379 | self.cmd.arg("-L").arg(path); | |
1380 | } | |
1381 | fn framework_path(&mut self, _: &Path) { | |
1382 | bug!("frameworks are not supported on L4Re"); | |
1383 | } | |
1384 | fn output_filename(&mut self, path: &Path) { | |
1385 | self.cmd.arg("-o").arg(path); | |
1386 | } | |
1387 | ||
1388 | fn add_object(&mut self, path: &Path) { | |
1389 | self.cmd.arg(path); | |
1390 | } | |
1391 | ||
1392 | fn full_relro(&mut self) { | |
1393 | self.cmd.arg("-zrelro"); | |
1394 | self.cmd.arg("-znow"); | |
1395 | } | |
1396 | ||
1397 | fn partial_relro(&mut self) { | |
1398 | self.cmd.arg("-zrelro"); | |
1399 | } | |
1400 | ||
1401 | fn no_relro(&mut self) { | |
1402 | self.cmd.arg("-znorelro"); | |
1403 | } | |
1404 | ||
1405 | fn cmd(&mut self) -> &mut Command { | |
1406 | &mut self.cmd | |
1407 | } | |
1408 | ||
1409 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1410 | ||
064997fb | 1411 | fn link_rust_dylib(&mut self, _: &str, _: &Path) { |
5099ac24 FG |
1412 | panic!("Rust dylibs not supported"); |
1413 | } | |
1414 | ||
064997fb | 1415 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
5099ac24 FG |
1416 | bug!("frameworks not supported on L4Re"); |
1417 | } | |
1418 | ||
064997fb | 1419 | fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { |
5099ac24 FG |
1420 | self.hint_static(); |
1421 | self.cmd.arg("--whole-archive").arg(format!("-l{}", lib)); | |
1422 | self.cmd.arg("--no-whole-archive"); | |
1423 | } | |
1424 | ||
1425 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1426 | self.hint_static(); | |
1427 | self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); | |
1428 | } | |
1429 | ||
1430 | fn gc_sections(&mut self, keep_metadata: bool) { | |
1431 | if !keep_metadata { | |
1432 | self.cmd.arg("--gc-sections"); | |
1433 | } | |
1434 | } | |
1435 | ||
1436 | fn no_gc_sections(&mut self) { | |
1437 | self.cmd.arg("--no-gc-sections"); | |
1438 | } | |
1439 | ||
1440 | fn optimize(&mut self) { | |
1441 | // GNU-style linkers support optimization with -O. GNU ld doesn't | |
1442 | // need a numeric argument, but other linkers do. | |
1443 | if self.sess.opts.optimize == config::OptLevel::Default | |
1444 | || self.sess.opts.optimize == config::OptLevel::Aggressive | |
1445 | { | |
1446 | self.cmd.arg("-O1"); | |
1447 | } | |
1448 | } | |
1449 | ||
1450 | fn pgo_gen(&mut self) {} | |
1451 | ||
04454e1e | 1452 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
5099ac24 FG |
1453 | match strip { |
1454 | Strip::None => {} | |
1455 | Strip::Debuginfo => { | |
1456 | self.cmd().arg("--strip-debug"); | |
1457 | } | |
1458 | Strip::Symbols => { | |
1459 | self.cmd().arg("--strip-all"); | |
1460 | } | |
1461 | } | |
1462 | } | |
1463 | ||
1464 | fn no_default_libraries(&mut self) { | |
1465 | self.cmd.arg("-nostdlib"); | |
1466 | } | |
1467 | ||
1468 | fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { | |
1469 | // ToDo, not implemented, copy from GCC | |
1470 | self.sess.warn("exporting symbols not implemented yet for L4Bender"); | |
1471 | return; | |
1472 | } | |
1473 | ||
1474 | fn subsystem(&mut self, subsystem: &str) { | |
1475 | self.cmd.arg(&format!("--subsystem {}", subsystem)); | |
1476 | } | |
1477 | ||
1478 | fn reset_per_library_state(&mut self) { | |
1479 | self.hint_static(); // Reset to default before returning the composed command line. | |
1480 | } | |
1481 | ||
1482 | fn group_start(&mut self) { | |
1483 | self.cmd.arg("--start-group"); | |
1484 | } | |
1485 | ||
1486 | fn group_end(&mut self) { | |
1487 | self.cmd.arg("--end-group"); | |
1488 | } | |
1489 | ||
1490 | fn linker_plugin_lto(&mut self) {} | |
1491 | ||
1492 | fn control_flow_guard(&mut self) {} | |
1493 | ||
1494 | fn no_crt_objects(&mut self) {} | |
1495 | } | |
1496 | ||
1497 | impl<'a> L4Bender<'a> { | |
1498 | pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { | |
1499 | L4Bender { cmd: cmd, sess: sess, hinted_static: false } | |
1500 | } | |
1501 | ||
1502 | fn hint_static(&mut self) { | |
1503 | if !self.hinted_static { | |
1504 | self.cmd.arg("-static"); | |
1505 | self.hinted_static = true; | |
1506 | } | |
1507 | } | |
1508 | } | |
1509 | ||
04454e1e FG |
1510 | fn for_each_exported_symbols_include_dep<'tcx>( |
1511 | tcx: TyCtxt<'tcx>, | |
1512 | crate_type: CrateType, | |
1513 | mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), | |
1514 | ) { | |
1515 | for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { | |
1516 | callback(symbol, info, LOCAL_CRATE); | |
1517 | } | |
1518 | ||
1519 | let formats = tcx.dependency_formats(()); | |
1520 | let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap(); | |
1521 | ||
1522 | for (index, dep_format) in deps.iter().enumerate() { | |
1523 | let cnum = CrateNum::new(index + 1); | |
1524 | // For each dependency that we are linking to statically ... | |
1525 | if *dep_format == Linkage::Static { | |
1526 | for &(symbol, info) in tcx.exported_symbols(cnum).iter() { | |
1527 | callback(symbol, info, cnum); | |
1528 | } | |
1529 | } | |
1530 | } | |
1531 | } | |
1532 | ||
136023e0 | 1533 | pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { |
29967ef6 | 1534 | if let Some(ref exports) = tcx.sess.target.override_export_symbols { |
5e7ed085 | 1535 | return exports.iter().map(ToString::to_string).collect(); |
a1dfa0c6 XL |
1536 | } |
1537 | ||
1538 | let mut symbols = Vec::new(); | |
1539 | ||
1540 | let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); | |
04454e1e FG |
1541 | for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { |
1542 | if info.level.is_below_threshold(export_threshold) { | |
1543 | symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum)); | |
a1dfa0c6 | 1544 | } |
04454e1e | 1545 | }); |
a1dfa0c6 | 1546 | |
04454e1e FG |
1547 | symbols |
1548 | } | |
e74abb32 | 1549 | |
04454e1e FG |
1550 | pub(crate) fn linked_symbols( |
1551 | tcx: TyCtxt<'_>, | |
1552 | crate_type: CrateType, | |
1553 | ) -> Vec<(String, SymbolExportKind)> { | |
1554 | match crate_type { | |
1555 | CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (), | |
1556 | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { | |
1557 | return Vec::new(); | |
a1dfa0c6 XL |
1558 | } |
1559 | } | |
1560 | ||
04454e1e FG |
1561 | let mut symbols = Vec::new(); |
1562 | ||
1563 | let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); | |
1564 | for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { | |
1565 | if info.level.is_below_threshold(export_threshold) || info.used { | |
1566 | symbols.push(( | |
1567 | symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), | |
1568 | info.kind, | |
1569 | )); | |
1570 | } | |
1571 | }); | |
1572 | ||
a1dfa0c6 XL |
1573 | symbols |
1574 | } | |
9fa01778 XL |
1575 | |
1576 | /// Much simplified and explicit CLI for the NVPTX linker. The linker operates | |
1577 | /// with bitcode and uses LLVM backend to generate a PTX assembly. | |
1578 | pub struct PtxLinker<'a> { | |
1579 | cmd: Command, | |
1580 | sess: &'a Session, | |
1581 | } | |
1582 | ||
1583 | impl<'a> Linker for PtxLinker<'a> { | |
ba9703b0 XL |
1584 | fn cmd(&mut self) -> &mut Command { |
1585 | &mut self.cmd | |
1586 | } | |
1587 | ||
f9f354fc XL |
1588 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} |
1589 | ||
9fa01778 XL |
1590 | fn link_rlib(&mut self, path: &Path) { |
1591 | self.cmd.arg("--rlib").arg(path); | |
1592 | } | |
1593 | ||
1594 | fn link_whole_rlib(&mut self, path: &Path) { | |
1595 | self.cmd.arg("--rlib").arg(path); | |
1596 | } | |
1597 | ||
1598 | fn include_path(&mut self, path: &Path) { | |
1599 | self.cmd.arg("-L").arg(path); | |
1600 | } | |
1601 | ||
04454e1e | 1602 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
9fa01778 XL |
1603 | self.cmd.arg("--debug"); |
1604 | } | |
1605 | ||
1606 | fn add_object(&mut self, path: &Path) { | |
1607 | self.cmd.arg("--bitcode").arg(path); | |
1608 | } | |
1609 | ||
9fa01778 XL |
1610 | fn optimize(&mut self) { |
1611 | match self.sess.lto() { | |
1612 | Lto::Thin | Lto::Fat | Lto::ThinLocal => { | |
1613 | self.cmd.arg("-Olto"); | |
dfeec247 | 1614 | } |
9fa01778 | 1615 | |
dfeec247 | 1616 | Lto::No => {} |
9fa01778 XL |
1617 | }; |
1618 | } | |
1619 | ||
1620 | fn output_filename(&mut self, path: &Path) { | |
1621 | self.cmd.arg("-o").arg(path); | |
1622 | } | |
1623 | ||
064997fb | 1624 | fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { |
17df50a5 XL |
1625 | panic!("external dylibs not supported") |
1626 | } | |
1627 | ||
064997fb | 1628 | fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { |
17df50a5 XL |
1629 | panic!("external dylibs not supported") |
1630 | } | |
1631 | ||
064997fb | 1632 | fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { |
17df50a5 XL |
1633 | panic!("staticlibs not supported") |
1634 | } | |
1635 | ||
064997fb | 1636 | fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { |
17df50a5 XL |
1637 | panic!("staticlibs not supported") |
1638 | } | |
1639 | ||
1640 | fn framework_path(&mut self, _path: &Path) { | |
1641 | panic!("frameworks not supported") | |
1642 | } | |
1643 | ||
064997fb | 1644 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
17df50a5 XL |
1645 | panic!("frameworks not supported") |
1646 | } | |
1647 | ||
1648 | fn full_relro(&mut self) {} | |
1649 | ||
1650 | fn partial_relro(&mut self) {} | |
1651 | ||
1652 | fn no_relro(&mut self) {} | |
1653 | ||
1654 | fn gc_sections(&mut self, _keep_metadata: bool) {} | |
1655 | ||
1656 | fn no_gc_sections(&mut self) {} | |
1657 | ||
1658 | fn pgo_gen(&mut self) {} | |
1659 | ||
1660 | fn no_crt_objects(&mut self) {} | |
1661 | ||
1662 | fn no_default_libraries(&mut self) {} | |
1663 | ||
1664 | fn control_flow_guard(&mut self) {} | |
1665 | ||
136023e0 | 1666 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} |
17df50a5 XL |
1667 | |
1668 | fn subsystem(&mut self, _subsystem: &str) {} | |
1669 | ||
1670 | fn group_start(&mut self) {} | |
1671 | ||
1672 | fn group_end(&mut self) {} | |
1673 | ||
1674 | fn linker_plugin_lto(&mut self) {} | |
1675 | } | |
1676 | ||
1677 | pub struct BpfLinker<'a> { | |
1678 | cmd: Command, | |
1679 | sess: &'a Session, | |
17df50a5 XL |
1680 | } |
1681 | ||
1682 | impl<'a> Linker for BpfLinker<'a> { | |
1683 | fn cmd(&mut self) -> &mut Command { | |
1684 | &mut self.cmd | |
1685 | } | |
1686 | ||
1687 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1688 | ||
1689 | fn link_rlib(&mut self, path: &Path) { | |
1690 | self.cmd.arg(path); | |
1691 | } | |
1692 | ||
1693 | fn link_whole_rlib(&mut self, path: &Path) { | |
1694 | self.cmd.arg(path); | |
1695 | } | |
1696 | ||
1697 | fn include_path(&mut self, path: &Path) { | |
1698 | self.cmd.arg("-L").arg(path); | |
1699 | } | |
1700 | ||
04454e1e | 1701 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
17df50a5 XL |
1702 | self.cmd.arg("--debug"); |
1703 | } | |
1704 | ||
1705 | fn add_object(&mut self, path: &Path) { | |
1706 | self.cmd.arg(path); | |
1707 | } | |
1708 | ||
1709 | fn optimize(&mut self) { | |
1710 | self.cmd.arg(match self.sess.opts.optimize { | |
1711 | OptLevel::No => "-O0", | |
1712 | OptLevel::Less => "-O1", | |
1713 | OptLevel::Default => "-O2", | |
1714 | OptLevel::Aggressive => "-O3", | |
1715 | OptLevel::Size => "-Os", | |
1716 | OptLevel::SizeMin => "-Oz", | |
9fa01778 | 1717 | }); |
9fa01778 XL |
1718 | } |
1719 | ||
17df50a5 XL |
1720 | fn output_filename(&mut self, path: &Path) { |
1721 | self.cmd.arg("-o").arg(path); | |
1722 | } | |
1723 | ||
064997fb | 1724 | fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { |
9fa01778 XL |
1725 | panic!("external dylibs not supported") |
1726 | } | |
1727 | ||
064997fb | 1728 | fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { |
9fa01778 XL |
1729 | panic!("external dylibs not supported") |
1730 | } | |
1731 | ||
064997fb | 1732 | fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { |
9fa01778 XL |
1733 | panic!("staticlibs not supported") |
1734 | } | |
1735 | ||
064997fb | 1736 | fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { |
9fa01778 XL |
1737 | panic!("staticlibs not supported") |
1738 | } | |
1739 | ||
1740 | fn framework_path(&mut self, _path: &Path) { | |
1741 | panic!("frameworks not supported") | |
1742 | } | |
1743 | ||
064997fb | 1744 | fn link_framework(&mut self, _framework: &str, _as_needed: bool) { |
9fa01778 XL |
1745 | panic!("frameworks not supported") |
1746 | } | |
1747 | ||
dfeec247 | 1748 | fn full_relro(&mut self) {} |
9fa01778 | 1749 | |
dfeec247 | 1750 | fn partial_relro(&mut self) {} |
9fa01778 | 1751 | |
dfeec247 | 1752 | fn no_relro(&mut self) {} |
9fa01778 | 1753 | |
dfeec247 | 1754 | fn gc_sections(&mut self, _keep_metadata: bool) {} |
9fa01778 | 1755 | |
17df50a5 XL |
1756 | fn no_gc_sections(&mut self) {} |
1757 | ||
dfeec247 | 1758 | fn pgo_gen(&mut self) {} |
9fa01778 | 1759 | |
f9f354fc XL |
1760 | fn no_crt_objects(&mut self) {} |
1761 | ||
dfeec247 | 1762 | fn no_default_libraries(&mut self) {} |
9fa01778 | 1763 | |
f035d41b | 1764 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1765 | |
136023e0 | 1766 | fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
17df50a5 XL |
1767 | let path = tmpdir.join("symbols"); |
1768 | let res: io::Result<()> = try { | |
1769 | let mut f = BufWriter::new(File::create(&path)?); | |
136023e0 | 1770 | for sym in symbols { |
17df50a5 XL |
1771 | writeln!(f, "{}", sym)?; |
1772 | } | |
1773 | }; | |
1774 | if let Err(e) = res { | |
1775 | self.sess.fatal(&format!("failed to write symbols file: {}", e)); | |
1776 | } else { | |
1777 | self.cmd.arg("--export-symbols").arg(&path); | |
1778 | } | |
1779 | } | |
9fa01778 | 1780 | |
dfeec247 | 1781 | fn subsystem(&mut self, _subsystem: &str) {} |
9fa01778 | 1782 | |
dfeec247 | 1783 | fn group_start(&mut self) {} |
9fa01778 | 1784 | |
dfeec247 | 1785 | fn group_end(&mut self) {} |
9fa01778 | 1786 | |
dfeec247 | 1787 | fn linker_plugin_lto(&mut self) {} |
9fa01778 | 1788 | } |