]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_ssa/src/back/linker.rs
Only use the -dynamiclib flag when the linker is not ld
[rust.git] / compiler / rustc_codegen_ssa / src / back / linker.rs
1 use super::archive;
2 use super::command::Command;
3 use super::symbol_export;
4 use rustc_span::symbol::sym;
5
6 use std::ffi::{OsStr, OsString};
7 use std::fs::{self, File};
8 use std::io::prelude::*;
9 use std::io::{self, BufWriter};
10 use std::path::{Path, PathBuf};
11 use std::{env, mem, str};
12
13 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
14 use rustc_middle::middle::dependency_format::Linkage;
15 use rustc_middle::ty::TyCtxt;
16 use rustc_serialize::{json, Encoder};
17 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
18 use rustc_session::Session;
19 use rustc_span::symbol::Symbol;
20 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
21
22 use cc::windows_registry;
23
24 /// Disables non-English messages from localized linkers.
25 /// Such messages may cause issues with text encoding on Windows (#35785)
26 /// and prevent inspection of linker output in case of errors, which we occasionally do.
27 /// This should be acceptable because other messages from rustc are in English anyway,
28 /// and may also be desirable to improve searchability of the linker diagnostics.
29 pub fn disable_localization(linker: &mut Command) {
30     // No harm in setting both env vars simultaneously.
31     // Unix-style linkers.
32     linker.env("LC_ALL", "C");
33     // MSVC's `link.exe`.
34     linker.env("VSLANG", "1033");
35 }
36
37 // The third parameter is for env vars, used on windows to set up the
38 // path for MSVC to find its DLLs, and gcc to find its bundled
39 // toolchain
40 pub fn get_linker<'a>(
41     sess: &'a Session,
42     linker: &Path,
43     flavor: LinkerFlavor,
44     self_contained: bool,
45     target_cpu: &'a str,
46 ) -> Box<dyn Linker + 'a> {
47     let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
48
49     // If our linker looks like a batch script on Windows then to execute this
50     // we'll need to spawn `cmd` explicitly. This is primarily done to handle
51     // emscripten where the linker is `emcc.bat` and needs to be spawned as
52     // `cmd /c emcc.bat ...`.
53     //
54     // This worked historically but is needed manually since #42436 (regression
55     // was tagged as #42791) and some more info can be found on #44443 for
56     // emscripten itself.
57     let mut cmd = match linker.to_str() {
58         Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
59         _ => match flavor {
60             LinkerFlavor::Lld(f) => Command::lld(linker, f),
61             LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
62                 Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
63             }
64             _ => Command::new(linker),
65         },
66     };
67
68     // UWP apps have API restrictions enforced during Store submissions.
69     // To comply with the Windows App Certification Kit,
70     // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
71     let t = &sess.target;
72     if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
73         && t.vendor == "uwp"
74     {
75         if let Some(ref tool) = msvc_tool {
76             let original_path = tool.path();
77             if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
78                 let arch = match t.arch.as_str() {
79                     "x86_64" => Some("x64"),
80                     "x86" => Some("x86"),
81                     "aarch64" => Some("arm64"),
82                     "arm" => Some("arm"),
83                     _ => None,
84                 };
85                 if let Some(ref a) = arch {
86                     // FIXME: Move this to `fn linker_with_args`.
87                     let mut arg = OsString::from("/LIBPATH:");
88                     arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
89                     cmd.arg(&arg);
90                 } else {
91                     warn!("arch is not supported");
92                 }
93             } else {
94                 warn!("MSVC root path lib location not found");
95             }
96         } else {
97             warn!("link.exe not found");
98         }
99     }
100
101     // The compiler's sysroot often has some bundled tools, so add it to the
102     // PATH for the child.
103     let mut new_path = sess.get_tools_search_paths(self_contained);
104     let mut msvc_changed_path = false;
105     if sess.target.is_like_msvc {
106         if let Some(ref tool) = msvc_tool {
107             cmd.args(tool.args());
108             for &(ref k, ref v) in tool.env() {
109                 if k == "PATH" {
110                     new_path.extend(env::split_paths(v));
111                     msvc_changed_path = true;
112                 } else {
113                     cmd.env(k, v);
114                 }
115             }
116         }
117     }
118
119     if !msvc_changed_path {
120         if let Some(path) = env::var_os("PATH") {
121             new_path.extend(env::split_paths(&path));
122         }
123     }
124     cmd.env("PATH", env::join_paths(new_path).unwrap());
125
126     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
127     // to the linker args construction.
128     assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
129
130     match flavor {
131         LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
132             Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
133         }
134         LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
135         LinkerFlavor::Gcc => {
136             Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false })
137                 as Box<dyn Linker>
138         }
139
140         LinkerFlavor::Lld(LldFlavor::Ld)
141         | LinkerFlavor::Lld(LldFlavor::Ld64)
142         | LinkerFlavor::Ld => {
143             Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true })
144                 as Box<dyn Linker>
145         }
146
147         LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
148
149         LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
150
151         LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
152     }
153 }
154
155 /// Linker abstraction used by `back::link` to build up the command to invoke a
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
161 /// MSVC linker (e.g., `link.exe`) is being used.
162 pub trait Linker {
163     fn cmd(&mut self) -> &mut Command;
164     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
165     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
166     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
167     fn link_framework(&mut self, framework: Symbol, as_needed: bool);
168     fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
169     fn link_rlib(&mut self, lib: &Path);
170     fn link_whole_rlib(&mut self, lib: &Path);
171     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
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);
176     fn gc_sections(&mut self, keep_metadata: bool);
177     fn no_gc_sections(&mut self);
178     fn full_relro(&mut self);
179     fn partial_relro(&mut self);
180     fn no_relro(&mut self);
181     fn optimize(&mut self);
182     fn pgo_gen(&mut self);
183     fn control_flow_guard(&mut self);
184     fn debuginfo(&mut self, strip: Strip);
185     fn no_crt_objects(&mut self);
186     fn no_default_libraries(&mut self);
187     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
188     fn subsystem(&mut self, subsystem: &str);
189     fn group_start(&mut self);
190     fn group_end(&mut self);
191     fn linker_plugin_lto(&mut self);
192     fn add_eh_frame_header(&mut self) {}
193     fn add_no_exec(&mut self) {}
194     fn add_as_needed(&mut self) {}
195     fn reset_per_library_state(&mut self) {}
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     }
210 }
211
212 pub struct GccLinker<'a> {
213     cmd: Command,
214     sess: &'a Session,
215     target_cpu: &'a str,
216     hinted_static: bool, // Keeps track of the current hinting mode.
217     // Link as ld
218     is_ld: bool,
219 }
220
221 impl<'a> GccLinker<'a> {
222     /// Passes an argument directly to the linker.
223     ///
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             });
243         } else {
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             }
252         }
253         self
254     }
255
256     fn takes_hints(&self) -> bool {
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
265         !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm
266     }
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) {
273         if !self.takes_hints() {
274             return;
275         }
276         if !self.hinted_static {
277             self.linker_arg("-Bstatic");
278             self.hinted_static = true;
279         }
280     }
281
282     fn hint_dynamic(&mut self) {
283         if !self.takes_hints() {
284             return;
285         }
286         if self.hinted_static {
287             self.linker_arg("-Bdynamic");
288             self.hinted_static = false;
289         }
290     }
291
292     fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
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",
302             config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
303             config::OptLevel::Aggressive => "O3",
304         };
305
306         if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
307             self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
308         };
309         self.linker_args(&[
310             &format!("-plugin-opt={}", opt_level),
311             &format!("-plugin-opt=mcpu={}", self.target_cpu),
312         ]);
313     }
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
317         if self.sess.target.is_like_osx {
318             if !self.is_ld {
319                 self.cmd.arg("-dynamiclib");
320             }
321
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.
328             if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
329                 let mut rpath = OsString::from("@rpath/");
330                 rpath.push(out_filename.file_name().unwrap());
331                 self.linker_args(&[OsString::from("-install_name"), rpath]);
332             }
333         } else {
334             self.cmd.arg("-shared");
335             if self.sess.target.is_like_windows {
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                             "{}{}{}",
343                             self.sess.target.staticlib_prefix,
344                             file,
345                             self.sess.target.staticlib_suffix
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 {
351                         self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap()));
352                     }
353                 }
354             }
355         }
356     }
357 }
358
359 impl<'a> Linker for GccLinker<'a> {
360     fn cmd(&mut self) -> &mut Command {
361         &mut self.cmd
362     }
363
364     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
365         match output_kind {
366             LinkOutputKind::DynamicNoPicExe => {
367                 if !self.is_ld && self.sess.target.linker_is_gnu {
368                     self.cmd.arg("-no-pie");
369                 }
370             }
371             LinkOutputKind::DynamicPicExe => {
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                 }
377             }
378             LinkOutputKind::StaticNoPicExe => {
379                 // `-static` works for both gcc wrapper and ld.
380                 self.cmd.arg("-static");
381                 if !self.is_ld && self.sess.target.linker_is_gnu {
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             }
404             LinkOutputKind::WasiReactorExe => {
405                 self.linker_args(&["--entry", "_initialize"]);
406             }
407         }
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.
413         if self.sess.target.os == "vxworks"
414             && matches!(
415                 output_kind,
416                 LinkOutputKind::StaticNoPicExe
417                     | LinkOutputKind::StaticPicExe
418                     | LinkOutputKind::StaticDylib
419             )
420         {
421             self.cmd.arg("--static-crt");
422         }
423     }
424
425     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
426         if self.sess.target.os == "illumos" && lib.as_str() == "c" {
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         }
446         self.hint_dynamic();
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         }
455     }
456     fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
457         self.hint_static();
458         self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
459     }
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     }
476     fn full_relro(&mut self) {
477         self.linker_args(&["-zrelro", "-znow"]);
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     }
485
486     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
487         self.hint_dynamic();
488         self.cmd.arg(format!("-l{}", lib));
489     }
490
491     fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
492         self.hint_dynamic();
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.
496             // self.cmd.arg("-needed_framework").sym_arg(framework);
497             self.sess.warn("`as-needed` modifier not implemented yet for ld64");
498         }
499         self.cmd.arg("-framework").sym_arg(framework);
500     }
501
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.
508     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
509         self.hint_static();
510         let target = &self.sess.target;
511         if !target.is_like_osx {
512             self.linker_arg("--whole-archive").cmd.arg(format!(
513                 "-l{}{}",
514                 if verbatim { ":" } else { "" },
515                 lib
516             ));
517             self.linker_arg("--no-whole-archive");
518         } else {
519             // -force_load is the macOS equivalent of --whole-archive, but it
520             // involves passing the full path to the library to link.
521             self.linker_arg("-force_load");
522             let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
523             self.linker_arg(&lib);
524         }
525     }
526
527     fn link_whole_rlib(&mut self, lib: &Path) {
528         self.hint_static();
529         if self.sess.target.is_like_osx {
530             self.linker_arg("-force_load");
531             self.linker_arg(&lib);
532         } else {
533             self.linker_arg("--whole-archive").cmd.arg(lib);
534             self.linker_arg("--no-whole-archive");
535         }
536     }
537
538     fn gc_sections(&mut self, keep_metadata: bool) {
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.
553         if self.sess.target.is_like_osx {
554             self.linker_arg("-dead_strip");
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.
561         } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
562             && !keep_metadata
563         {
564             self.linker_arg("--gc-sections");
565         }
566     }
567
568     fn no_gc_sections(&mut self) {
569         if self.sess.target.is_like_osx {
570             self.linker_arg("-no_dead_strip");
571         } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
572             self.linker_arg("--no-gc-sections");
573         }
574     }
575
576     fn optimize(&mut self) {
577         if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
578             return;
579         }
580
581         // GNU-style linkers support optimization with -O. GNU ld doesn't
582         // need a numeric argument, but other linkers do.
583         if self.sess.opts.optimize == config::OptLevel::Default
584             || self.sess.opts.optimize == config::OptLevel::Aggressive
585         {
586             self.linker_arg("-O1");
587         }
588     }
589
590     fn pgo_gen(&mut self) {
591         if !self.sess.target.linker_is_gnu {
592             return;
593         }
594
595         // If we're doing PGO generation stuff and on a GNU-like linker, use the
596         // "-u" flag to properly pull in the profiler runtime bits.
597         //
598         // This is because LLVM otherwise won't add the needed initialization
599         // for us on Linux (though the extra flag should be harmless if it
600         // does).
601         //
602         // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
603         //
604         // Though it may be worth to try to revert those changes upstream, since
605         // the overhead of the initialization should be minor.
606         self.cmd.arg("-u");
607         self.cmd.arg("__llvm_profile_runtime");
608     }
609
610     fn control_flow_guard(&mut self) {}
611
612     fn debuginfo(&mut self, strip: Strip) {
613         // MacOS linker doesn't support stripping symbols directly anymore.
614         if self.sess.target.is_like_osx {
615             return;
616         }
617
618         match strip {
619             Strip::None => {}
620             Strip::Debuginfo => {
621                 self.linker_arg("--strip-debug");
622             }
623             Strip::Symbols => {
624                 self.linker_arg("--strip-all");
625             }
626         }
627     }
628
629     fn no_crt_objects(&mut self) {
630         if !self.is_ld {
631             self.cmd.arg("-nostartfiles");
632         }
633     }
634
635     fn no_default_libraries(&mut self) {
636         if !self.is_ld {
637             self.cmd.arg("-nodefaultlibs");
638         }
639     }
640
641     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
642         // Symbol visibility in object files typically takes care of this.
643         if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
644         {
645             return;
646         }
647
648         // We manually create a list of exported symbols to ensure we don't expose any more.
649         // The object files have far more public symbols than we actually want to export,
650         // so we hide them all here.
651
652         if !self.sess.target.limit_rdylib_exports {
653             return;
654         }
655
656         if crate_type == CrateType::ProcMacro {
657             return;
658         }
659
660         let is_windows = self.sess.target.is_like_windows;
661         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
662
663         debug!("EXPORTED SYMBOLS:");
664
665         if self.sess.target.is_like_osx {
666             // Write a plain, newline-separated list of symbols
667             let res: io::Result<()> = try {
668                 let mut f = BufWriter::new(File::create(&path)?);
669                 for sym in symbols {
670                     debug!("  _{}", sym);
671                     writeln!(f, "_{}", sym)?;
672                 }
673             };
674             if let Err(e) = res {
675                 self.sess.fatal(&format!("failed to write lib.def file: {}", e));
676             }
677         } else if is_windows {
678             let res: io::Result<()> = try {
679                 let mut f = BufWriter::new(File::create(&path)?);
680
681                 // .def file similar to MSVC one but without LIBRARY section
682                 // because LD doesn't like when it's empty
683                 writeln!(f, "EXPORTS")?;
684                 for symbol in symbols {
685                     debug!("  _{}", symbol);
686                     writeln!(f, "  {}", symbol)?;
687                 }
688             };
689             if let Err(e) = res {
690                 self.sess.fatal(&format!("failed to write list.def file: {}", e));
691             }
692         } else {
693             // Write an LD version script
694             let res: io::Result<()> = try {
695                 let mut f = BufWriter::new(File::create(&path)?);
696                 writeln!(f, "{{")?;
697                 if !symbols.is_empty() {
698                     writeln!(f, "  global:")?;
699                     for sym in symbols {
700                         debug!("    {};", sym);
701                         writeln!(f, "    {};", sym)?;
702                     }
703                 }
704                 writeln!(f, "\n  local:\n    *;\n}};")?;
705             };
706             if let Err(e) = res {
707                 self.sess.fatal(&format!("failed to write version script: {}", e));
708             }
709         }
710
711         if self.sess.target.is_like_osx {
712             self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
713         } else if self.sess.target.is_like_solaris {
714             self.linker_args(&[OsString::from("-M"), path.into()]);
715         } else {
716             if is_windows {
717                 self.linker_arg(path);
718             } else {
719                 let mut arg = OsString::from("--version-script=");
720                 arg.push(path);
721                 self.linker_arg(arg);
722             }
723         }
724     }
725
726     fn subsystem(&mut self, subsystem: &str) {
727         self.linker_arg("--subsystem");
728         self.linker_arg(&subsystem);
729     }
730
731     fn reset_per_library_state(&mut self) {
732         self.hint_dynamic(); // Reset to default before returning the composed command line.
733     }
734
735     fn group_start(&mut self) {
736         if self.takes_hints() {
737             self.linker_arg("--start-group");
738         }
739     }
740
741     fn group_end(&mut self) {
742         if self.takes_hints() {
743             self.linker_arg("--end-group");
744         }
745     }
746
747     fn linker_plugin_lto(&mut self) {
748         match self.sess.opts.cg.linker_plugin_lto {
749             LinkerPluginLto::Disabled => {
750                 // Nothing to do
751             }
752             LinkerPluginLto::LinkerPluginAuto => {
753                 self.push_linker_plugin_lto_args(None);
754             }
755             LinkerPluginLto::LinkerPlugin(ref path) => {
756                 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
757             }
758         }
759     }
760
761     // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information.
762     // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
763     // so we just always add it.
764     fn add_eh_frame_header(&mut self) {
765         self.linker_arg("--eh-frame-hdr");
766     }
767
768     fn add_no_exec(&mut self) {
769         if self.sess.target.is_like_windows {
770             self.linker_arg("--nxcompat");
771         } else if self.sess.target.linker_is_gnu {
772             self.linker_arg("-znoexecstack");
773         }
774     }
775
776     fn add_as_needed(&mut self) {
777         if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
778             self.linker_arg("--as-needed");
779         } else if self.sess.target.is_like_solaris {
780             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
781             self.linker_args(&["-z", "ignore"]);
782         }
783     }
784 }
785
786 pub struct MsvcLinker<'a> {
787     cmd: Command,
788     sess: &'a Session,
789 }
790
791 impl<'a> Linker for MsvcLinker<'a> {
792     fn cmd(&mut self) -> &mut Command {
793         &mut self.cmd
794     }
795
796     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
797         match output_kind {
798             LinkOutputKind::DynamicNoPicExe
799             | LinkOutputKind::DynamicPicExe
800             | LinkOutputKind::StaticNoPicExe
801             | LinkOutputKind::StaticPicExe => {}
802             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
803                 self.cmd.arg("/DLL");
804                 let mut arg: OsString = "/IMPLIB:".into();
805                 arg.push(out_filename.with_extension("dll.lib"));
806                 self.cmd.arg(arg);
807             }
808             LinkOutputKind::WasiReactorExe => {
809                 panic!("can't link as reactor on non-wasi target");
810             }
811         }
812     }
813
814     fn link_rlib(&mut self, lib: &Path) {
815         self.cmd.arg(lib);
816     }
817     fn add_object(&mut self, path: &Path) {
818         self.cmd.arg(path);
819     }
820
821     fn gc_sections(&mut self, _keep_metadata: bool) {
822         // MSVC's ICF (Identical COMDAT Folding) link optimization is
823         // slow for Rust and thus we disable it by default when not in
824         // optimization build.
825         if self.sess.opts.optimize != config::OptLevel::No {
826             self.cmd.arg("/OPT:REF,ICF");
827         } else {
828             // It is necessary to specify NOICF here, because /OPT:REF
829             // implies ICF by default.
830             self.cmd.arg("/OPT:REF,NOICF");
831         }
832     }
833
834     fn no_gc_sections(&mut self) {
835         self.cmd.arg("/OPT:NOREF,NOICF");
836     }
837
838     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
839         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
840     }
841
842     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
843         // When producing a dll, the MSVC linker may not actually emit a
844         // `foo.lib` file if the dll doesn't actually export any symbols, so we
845         // check to see if the file is there and just omit linking to it if it's
846         // not present.
847         let name = format!("{}.dll.lib", lib);
848         if path.join(&name).exists() {
849             self.cmd.arg(name);
850         }
851     }
852
853     fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
854         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
855     }
856
857     fn full_relro(&mut self) {
858         // noop
859     }
860
861     fn partial_relro(&mut self) {
862         // noop
863     }
864
865     fn no_relro(&mut self) {
866         // noop
867     }
868
869     fn no_crt_objects(&mut self) {
870         // noop
871     }
872
873     fn no_default_libraries(&mut self) {
874         self.cmd.arg("/NODEFAULTLIB");
875     }
876
877     fn include_path(&mut self, path: &Path) {
878         let mut arg = OsString::from("/LIBPATH:");
879         arg.push(path);
880         self.cmd.arg(&arg);
881     }
882
883     fn output_filename(&mut self, path: &Path) {
884         let mut arg = OsString::from("/OUT:");
885         arg.push(path);
886         self.cmd.arg(&arg);
887     }
888
889     fn framework_path(&mut self, _path: &Path) {
890         bug!("frameworks are not supported on windows")
891     }
892     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
893         bug!("frameworks are not supported on windows")
894     }
895
896     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
897         self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
898     }
899     fn link_whole_rlib(&mut self, path: &Path) {
900         let mut arg = OsString::from("/WHOLEARCHIVE:");
901         arg.push(path);
902         self.cmd.arg(arg);
903     }
904     fn optimize(&mut self) {
905         // Needs more investigation of `/OPT` arguments
906     }
907
908     fn pgo_gen(&mut self) {
909         // Nothing needed here.
910     }
911
912     fn control_flow_guard(&mut self) {
913         self.cmd.arg("/guard:cf");
914     }
915
916     fn debuginfo(&mut self, strip: Strip) {
917         match strip {
918             Strip::None => {
919                 // This will cause the Microsoft linker to generate a PDB file
920                 // from the CodeView line tables in the object files.
921                 self.cmd.arg("/DEBUG");
922
923                 // This will cause the Microsoft linker to embed .natvis info into the PDB file
924                 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
925                 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
926                     for entry in natvis_dir {
927                         match entry {
928                             Ok(entry) => {
929                                 let path = entry.path();
930                                 if path.extension() == Some("natvis".as_ref()) {
931                                     let mut arg = OsString::from("/NATVIS:");
932                                     arg.push(path);
933                                     self.cmd.arg(arg);
934                                 }
935                             }
936                             Err(err) => {
937                                 self.sess
938                                     .warn(&format!("error enumerating natvis directory: {}", err));
939                             }
940                         }
941                     }
942                 }
943             }
944             Strip::Debuginfo | Strip::Symbols => {
945                 self.cmd.arg("/DEBUG:NONE");
946             }
947         }
948     }
949
950     // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
951     // export symbols from a dynamic library. When building a dynamic library,
952     // however, we're going to want some symbols exported, so this function
953     // generates a DEF file which lists all the symbols.
954     //
955     // The linker will read this `*.def` file and export all the symbols from
956     // the dynamic library. Note that this is not as simple as just exporting
957     // all the symbols in the current crate (as specified by `codegen.reachable`)
958     // but rather we also need to possibly export the symbols of upstream
959     // crates. Upstream rlibs may be linked statically to this dynamic library,
960     // in which case they may continue to transitively be used and hence need
961     // their symbols exported.
962     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
963         // Symbol visibility takes care of this typically
964         if crate_type == CrateType::Executable {
965             return;
966         }
967
968         let path = tmpdir.join("lib.def");
969         let res: io::Result<()> = try {
970             let mut f = BufWriter::new(File::create(&path)?);
971
972             // Start off with the standard module name header and then go
973             // straight to exports.
974             writeln!(f, "LIBRARY")?;
975             writeln!(f, "EXPORTS")?;
976             for symbol in symbols {
977                 debug!("  _{}", symbol);
978                 writeln!(f, "  {}", symbol)?;
979             }
980         };
981         if let Err(e) = res {
982             self.sess.fatal(&format!("failed to write lib.def file: {}", e));
983         }
984         let mut arg = OsString::from("/DEF:");
985         arg.push(path);
986         self.cmd.arg(&arg);
987     }
988
989     fn subsystem(&mut self, subsystem: &str) {
990         // Note that previous passes of the compiler validated this subsystem,
991         // so we just blindly pass it to the linker.
992         self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
993
994         // Windows has two subsystems we're interested in right now, the console
995         // and windows subsystems. These both implicitly have different entry
996         // points (starting symbols). The console entry point starts with
997         // `mainCRTStartup` and the windows entry point starts with
998         // `WinMainCRTStartup`. These entry points, defined in system libraries,
999         // will then later probe for either `main` or `WinMain`, respectively to
1000         // start the application.
1001         //
1002         // In Rust we just always generate a `main` function so we want control
1003         // to always start there, so we force the entry point on the windows
1004         // subsystem to be `mainCRTStartup` to get everything booted up
1005         // correctly.
1006         //
1007         // For more information see RFC #1665
1008         if subsystem == "windows" {
1009             self.cmd.arg("/ENTRY:mainCRTStartup");
1010         }
1011     }
1012
1013     // MSVC doesn't need group indicators
1014     fn group_start(&mut self) {}
1015     fn group_end(&mut self) {}
1016
1017     fn linker_plugin_lto(&mut self) {
1018         // Do nothing
1019     }
1020
1021     fn add_no_exec(&mut self) {
1022         self.cmd.arg("/NXCOMPAT");
1023     }
1024 }
1025
1026 pub struct EmLinker<'a> {
1027     cmd: Command,
1028     sess: &'a Session,
1029 }
1030
1031 impl<'a> Linker for EmLinker<'a> {
1032     fn cmd(&mut self) -> &mut Command {
1033         &mut self.cmd
1034     }
1035
1036     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1037
1038     fn include_path(&mut self, path: &Path) {
1039         self.cmd.arg("-L").arg(path);
1040     }
1041
1042     fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
1043         self.cmd.arg("-l").sym_arg(lib);
1044     }
1045
1046     fn output_filename(&mut self, path: &Path) {
1047         self.cmd.arg("-o").arg(path);
1048     }
1049
1050     fn add_object(&mut self, path: &Path) {
1051         self.cmd.arg(path);
1052     }
1053
1054     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
1055         // Emscripten always links statically
1056         self.link_staticlib(lib, verbatim);
1057     }
1058
1059     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
1060         // not supported?
1061         self.link_staticlib(lib, verbatim);
1062     }
1063
1064     fn link_whole_rlib(&mut self, lib: &Path) {
1065         // not supported?
1066         self.link_rlib(lib);
1067     }
1068
1069     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
1070         self.link_dylib(lib, false, true);
1071     }
1072
1073     fn link_rlib(&mut self, lib: &Path) {
1074         self.add_object(lib);
1075     }
1076
1077     fn full_relro(&mut self) {
1078         // noop
1079     }
1080
1081     fn partial_relro(&mut self) {
1082         // noop
1083     }
1084
1085     fn no_relro(&mut self) {
1086         // noop
1087     }
1088
1089     fn framework_path(&mut self, _path: &Path) {
1090         bug!("frameworks are not supported on Emscripten")
1091     }
1092
1093     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1094         bug!("frameworks are not supported on Emscripten")
1095     }
1096
1097     fn gc_sections(&mut self, _keep_metadata: bool) {
1098         // noop
1099     }
1100
1101     fn no_gc_sections(&mut self) {
1102         // noop
1103     }
1104
1105     fn optimize(&mut self) {
1106         // Emscripten performs own optimizations
1107         self.cmd.arg(match self.sess.opts.optimize {
1108             OptLevel::No => "-O0",
1109             OptLevel::Less => "-O1",
1110             OptLevel::Default => "-O2",
1111             OptLevel::Aggressive => "-O3",
1112             OptLevel::Size => "-Os",
1113             OptLevel::SizeMin => "-Oz",
1114         });
1115         // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
1116         self.cmd.args(&["--memory-init-file", "0"]);
1117     }
1118
1119     fn pgo_gen(&mut self) {
1120         // noop, but maybe we need something like the gnu linker?
1121     }
1122
1123     fn control_flow_guard(&mut self) {}
1124
1125     fn debuginfo(&mut self, _strip: Strip) {
1126         // Preserve names or generate source maps depending on debug info
1127         self.cmd.arg(match self.sess.opts.debuginfo {
1128             DebugInfo::None => "-g0",
1129             DebugInfo::Limited => "-g3",
1130             DebugInfo::Full => "-g4",
1131         });
1132     }
1133
1134     fn no_crt_objects(&mut self) {}
1135
1136     fn no_default_libraries(&mut self) {
1137         self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
1138     }
1139
1140     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1141         debug!("EXPORTED SYMBOLS:");
1142
1143         self.cmd.arg("-s");
1144
1145         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1146         let mut encoded = String::new();
1147
1148         {
1149             let mut encoder = json::Encoder::new(&mut encoded);
1150             let res = encoder.emit_seq(symbols.len(), |encoder| {
1151                 for (i, sym) in symbols.iter().enumerate() {
1152                     encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
1153                 }
1154                 Ok(())
1155             });
1156             if let Err(e) = res {
1157                 self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
1158             }
1159         }
1160         debug!("{}", encoded);
1161         arg.push(encoded);
1162
1163         self.cmd.arg(arg);
1164     }
1165
1166     fn subsystem(&mut self, _subsystem: &str) {
1167         // noop
1168     }
1169
1170     // Appears not necessary on Emscripten
1171     fn group_start(&mut self) {}
1172     fn group_end(&mut self) {}
1173
1174     fn linker_plugin_lto(&mut self) {
1175         // Do nothing
1176     }
1177 }
1178
1179 pub struct WasmLd<'a> {
1180     cmd: Command,
1181     sess: &'a Session,
1182 }
1183
1184 impl<'a> WasmLd<'a> {
1185     fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1186         // If the atomics feature is enabled for wasm then we need a whole bunch
1187         // of flags:
1188         //
1189         // * `--shared-memory` - the link won't even succeed without this, flags
1190         //   the one linear memory as `shared`
1191         //
1192         // * `--max-memory=1G` - when specifying a shared memory this must also
1193         //   be specified. We conservatively choose 1GB but users should be able
1194         //   to override this with `-C link-arg`.
1195         //
1196         // * `--import-memory` - it doesn't make much sense for memory to be
1197         //   exported in a threaded module because typically you're
1198         //   sharing memory and instantiating the module multiple times. As a
1199         //   result if it were exported then we'd just have no sharing.
1200         //
1201         // * `--export=__wasm_init_memory` - when using `--passive-segments` the
1202         //   linker will synthesize this function, and so we need to make sure
1203         //   that our usage of `--export` below won't accidentally cause this
1204         //   function to get deleted.
1205         //
1206         // * `--export=*tls*` - when `#[thread_local]` symbols are used these
1207         //   symbols are how the TLS segments are initialized and configured.
1208         if sess.target_features.contains(&sym::atomics) {
1209             cmd.arg("--shared-memory");
1210             cmd.arg("--max-memory=1073741824");
1211             cmd.arg("--import-memory");
1212             cmd.arg("--export=__wasm_init_memory");
1213             cmd.arg("--export=__wasm_init_tls");
1214             cmd.arg("--export=__tls_size");
1215             cmd.arg("--export=__tls_align");
1216             cmd.arg("--export=__tls_base");
1217         }
1218         WasmLd { cmd, sess }
1219     }
1220 }
1221
1222 impl<'a> Linker for WasmLd<'a> {
1223     fn cmd(&mut self) -> &mut Command {
1224         &mut self.cmd
1225     }
1226
1227     fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
1228         match output_kind {
1229             LinkOutputKind::DynamicNoPicExe
1230             | LinkOutputKind::DynamicPicExe
1231             | LinkOutputKind::StaticNoPicExe
1232             | LinkOutputKind::StaticPicExe => {}
1233             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1234                 self.cmd.arg("--no-entry");
1235             }
1236             LinkOutputKind::WasiReactorExe => {
1237                 self.cmd.arg("--entry");
1238                 self.cmd.arg("_initialize");
1239             }
1240         }
1241     }
1242
1243     fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
1244         self.cmd.arg("-l").sym_arg(lib);
1245     }
1246
1247     fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
1248         self.cmd.arg("-l").sym_arg(lib);
1249     }
1250
1251     fn link_rlib(&mut self, lib: &Path) {
1252         self.cmd.arg(lib);
1253     }
1254
1255     fn include_path(&mut self, path: &Path) {
1256         self.cmd.arg("-L").arg(path);
1257     }
1258
1259     fn framework_path(&mut self, _path: &Path) {
1260         panic!("frameworks not supported")
1261     }
1262
1263     fn output_filename(&mut self, path: &Path) {
1264         self.cmd.arg("-o").arg(path);
1265     }
1266
1267     fn add_object(&mut self, path: &Path) {
1268         self.cmd.arg(path);
1269     }
1270
1271     fn full_relro(&mut self) {}
1272
1273     fn partial_relro(&mut self) {}
1274
1275     fn no_relro(&mut self) {}
1276
1277     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
1278         self.cmd.arg("-l").sym_arg(lib);
1279     }
1280
1281     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1282         panic!("frameworks not supported")
1283     }
1284
1285     fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1286         self.cmd.arg("-l").sym_arg(lib);
1287     }
1288
1289     fn link_whole_rlib(&mut self, lib: &Path) {
1290         self.cmd.arg(lib);
1291     }
1292
1293     fn gc_sections(&mut self, _keep_metadata: bool) {
1294         self.cmd.arg("--gc-sections");
1295     }
1296
1297     fn no_gc_sections(&mut self) {
1298         self.cmd.arg("--no-gc-sections");
1299     }
1300
1301     fn optimize(&mut self) {
1302         self.cmd.arg(match self.sess.opts.optimize {
1303             OptLevel::No => "-O0",
1304             OptLevel::Less => "-O1",
1305             OptLevel::Default => "-O2",
1306             OptLevel::Aggressive => "-O3",
1307             // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
1308             // instead.
1309             OptLevel::Size => "-O2",
1310             OptLevel::SizeMin => "-O2",
1311         });
1312     }
1313
1314     fn pgo_gen(&mut self) {}
1315
1316     fn debuginfo(&mut self, strip: Strip) {
1317         match strip {
1318             Strip::None => {}
1319             Strip::Debuginfo => {
1320                 self.cmd.arg("--strip-debug");
1321             }
1322             Strip::Symbols => {
1323                 self.cmd.arg("--strip-all");
1324             }
1325         }
1326     }
1327
1328     fn control_flow_guard(&mut self) {}
1329
1330     fn no_crt_objects(&mut self) {}
1331
1332     fn no_default_libraries(&mut self) {}
1333
1334     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1335         for sym in symbols {
1336             self.cmd.arg("--export").arg(&sym);
1337         }
1338
1339         // LLD will hide these otherwise-internal symbols since it only exports
1340         // symbols explicity passed via the `--export` flags above and hides all
1341         // others. Various bits and pieces of tooling use this, so be sure these
1342         // symbols make their way out of the linker as well.
1343         self.cmd.arg("--export=__heap_base");
1344         self.cmd.arg("--export=__data_end");
1345     }
1346
1347     fn subsystem(&mut self, _subsystem: &str) {}
1348
1349     // Not needed for now with LLD
1350     fn group_start(&mut self) {}
1351     fn group_end(&mut self) {}
1352
1353     fn linker_plugin_lto(&mut self) {
1354         // Do nothing for now
1355     }
1356 }
1357
1358 pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1359     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1360         return exports.clone();
1361     }
1362
1363     let mut symbols = Vec::new();
1364
1365     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1366     for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
1367         if level.is_below_threshold(export_threshold) {
1368             symbols.push(symbol_export::symbol_name_for_instance_in_crate(
1369                 tcx,
1370                 symbol,
1371                 LOCAL_CRATE,
1372             ));
1373         }
1374     }
1375
1376     let formats = tcx.dependency_formats(());
1377     let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
1378
1379     for (index, dep_format) in deps.iter().enumerate() {
1380         let cnum = CrateNum::new(index + 1);
1381         // For each dependency that we are linking to statically ...
1382         if *dep_format == Linkage::Static {
1383             // ... we add its symbol list to our export list.
1384             for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
1385                 if !level.is_below_threshold(export_threshold) {
1386                     continue;
1387                 }
1388
1389                 symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
1390             }
1391         }
1392     }
1393
1394     symbols
1395 }
1396
1397 /// Much simplified and explicit CLI for the NVPTX linker. The linker operates
1398 /// with bitcode and uses LLVM backend to generate a PTX assembly.
1399 pub struct PtxLinker<'a> {
1400     cmd: Command,
1401     sess: &'a Session,
1402 }
1403
1404 impl<'a> Linker for PtxLinker<'a> {
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
1411     fn link_rlib(&mut self, path: &Path) {
1412         self.cmd.arg("--rlib").arg(path);
1413     }
1414
1415     fn link_whole_rlib(&mut self, path: &Path) {
1416         self.cmd.arg("--rlib").arg(path);
1417     }
1418
1419     fn include_path(&mut self, path: &Path) {
1420         self.cmd.arg("-L").arg(path);
1421     }
1422
1423     fn debuginfo(&mut self, _strip: Strip) {
1424         self.cmd.arg("--debug");
1425     }
1426
1427     fn add_object(&mut self, path: &Path) {
1428         self.cmd.arg("--bitcode").arg(path);
1429     }
1430
1431     fn optimize(&mut self) {
1432         match self.sess.lto() {
1433             Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1434                 self.cmd.arg("-Olto");
1435             }
1436
1437             Lto::No => {}
1438         };
1439     }
1440
1441     fn output_filename(&mut self, path: &Path) {
1442         self.cmd.arg("-o").arg(path);
1443     }
1444
1445     fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
1446         panic!("external dylibs not supported")
1447     }
1448
1449     fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
1450         panic!("external dylibs not supported")
1451     }
1452
1453     fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
1454         panic!("staticlibs not supported")
1455     }
1456
1457     fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1458         panic!("staticlibs not supported")
1459     }
1460
1461     fn framework_path(&mut self, _path: &Path) {
1462         panic!("frameworks not supported")
1463     }
1464
1465     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1466         panic!("frameworks not supported")
1467     }
1468
1469     fn full_relro(&mut self) {}
1470
1471     fn partial_relro(&mut self) {}
1472
1473     fn no_relro(&mut self) {}
1474
1475     fn gc_sections(&mut self, _keep_metadata: bool) {}
1476
1477     fn no_gc_sections(&mut self) {}
1478
1479     fn pgo_gen(&mut self) {}
1480
1481     fn no_crt_objects(&mut self) {}
1482
1483     fn no_default_libraries(&mut self) {}
1484
1485     fn control_flow_guard(&mut self) {}
1486
1487     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1488
1489     fn subsystem(&mut self, _subsystem: &str) {}
1490
1491     fn group_start(&mut self) {}
1492
1493     fn group_end(&mut self) {}
1494
1495     fn linker_plugin_lto(&mut self) {}
1496 }
1497
1498 pub struct BpfLinker<'a> {
1499     cmd: Command,
1500     sess: &'a Session,
1501 }
1502
1503 impl<'a> Linker for BpfLinker<'a> {
1504     fn cmd(&mut self) -> &mut Command {
1505         &mut self.cmd
1506     }
1507
1508     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1509
1510     fn link_rlib(&mut self, path: &Path) {
1511         self.cmd.arg(path);
1512     }
1513
1514     fn link_whole_rlib(&mut self, path: &Path) {
1515         self.cmd.arg(path);
1516     }
1517
1518     fn include_path(&mut self, path: &Path) {
1519         self.cmd.arg("-L").arg(path);
1520     }
1521
1522     fn debuginfo(&mut self, _strip: Strip) {
1523         self.cmd.arg("--debug");
1524     }
1525
1526     fn add_object(&mut self, path: &Path) {
1527         self.cmd.arg(path);
1528     }
1529
1530     fn optimize(&mut self) {
1531         self.cmd.arg(match self.sess.opts.optimize {
1532             OptLevel::No => "-O0",
1533             OptLevel::Less => "-O1",
1534             OptLevel::Default => "-O2",
1535             OptLevel::Aggressive => "-O3",
1536             OptLevel::Size => "-Os",
1537             OptLevel::SizeMin => "-Oz",
1538         });
1539     }
1540
1541     fn output_filename(&mut self, path: &Path) {
1542         self.cmd.arg("-o").arg(path);
1543     }
1544
1545     fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
1546         panic!("external dylibs not supported")
1547     }
1548
1549     fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
1550         panic!("external dylibs not supported")
1551     }
1552
1553     fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
1554         panic!("staticlibs not supported")
1555     }
1556
1557     fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1558         panic!("staticlibs not supported")
1559     }
1560
1561     fn framework_path(&mut self, _path: &Path) {
1562         panic!("frameworks not supported")
1563     }
1564
1565     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1566         panic!("frameworks not supported")
1567     }
1568
1569     fn full_relro(&mut self) {}
1570
1571     fn partial_relro(&mut self) {}
1572
1573     fn no_relro(&mut self) {}
1574
1575     fn gc_sections(&mut self, _keep_metadata: bool) {}
1576
1577     fn no_gc_sections(&mut self) {}
1578
1579     fn pgo_gen(&mut self) {}
1580
1581     fn no_crt_objects(&mut self) {}
1582
1583     fn no_default_libraries(&mut self) {}
1584
1585     fn control_flow_guard(&mut self) {}
1586
1587     fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1588         let path = tmpdir.join("symbols");
1589         let res: io::Result<()> = try {
1590             let mut f = BufWriter::new(File::create(&path)?);
1591             for sym in symbols {
1592                 writeln!(f, "{}", sym)?;
1593             }
1594         };
1595         if let Err(e) = res {
1596             self.sess.fatal(&format!("failed to write symbols file: {}", e));
1597         } else {
1598             self.cmd.arg("--export-symbols").arg(&path);
1599         }
1600     }
1601
1602     fn subsystem(&mut self, _subsystem: &str) {}
1603
1604     fn group_start(&mut self) {}
1605
1606     fn group_end(&mut self) {}
1607
1608     fn linker_plugin_lto(&mut self) {}
1609 }