]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_ssa/src/back/linker.rs
Rollup merge of #87918 - mikebenfield:pr-afdo, r=nikic
[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     /// Argument that must be passed *directly* to the linker
223     ///
224     /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
225     fn linker_arg<S>(&mut self, arg: S) -> &mut Self
226     where
227         S: AsRef<OsStr>,
228     {
229         if !self.is_ld {
230             let mut os = OsString::from("-Wl,");
231             os.push(arg.as_ref());
232             self.cmd.arg(os);
233         } else {
234             self.cmd.arg(arg);
235         }
236         self
237     }
238
239     fn takes_hints(&self) -> bool {
240         // Really this function only returns true if the underlying linker
241         // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We
242         // don't really have a foolproof way to detect that, so rule out some
243         // platforms where currently this is guaranteed to *not* be the case:
244         //
245         // * On OSX they have their own linker, not binutils'
246         // * For WebAssembly the only functional linker is LLD, which doesn't
247         //   support hint flags
248         !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm
249     }
250
251     // Some platforms take hints about whether a library is static or dynamic.
252     // For those that support this, we ensure we pass the option if the library
253     // was flagged "static" (most defaults are dynamic) to ensure that if
254     // libfoo.a and libfoo.so both exist that the right one is chosen.
255     fn hint_static(&mut self) {
256         if !self.takes_hints() {
257             return;
258         }
259         if !self.hinted_static {
260             self.linker_arg("-Bstatic");
261             self.hinted_static = true;
262         }
263     }
264
265     fn hint_dynamic(&mut self) {
266         if !self.takes_hints() {
267             return;
268         }
269         if self.hinted_static {
270             self.linker_arg("-Bdynamic");
271             self.hinted_static = false;
272         }
273     }
274
275     fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
276         if let Some(plugin_path) = plugin_path {
277             let mut arg = OsString::from("-plugin=");
278             arg.push(plugin_path);
279             self.linker_arg(&arg);
280         }
281
282         let opt_level = match self.sess.opts.optimize {
283             config::OptLevel::No => "O0",
284             config::OptLevel::Less => "O1",
285             config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
286             config::OptLevel::Aggressive => "O3",
287         };
288
289         if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
290             self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
291         };
292         self.linker_arg(&format!("-plugin-opt={}", opt_level));
293         self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
294     }
295
296     fn build_dylib(&mut self, out_filename: &Path) {
297         // On mac we need to tell the linker to let this library be rpathed
298         if self.sess.target.is_like_osx {
299             self.cmd.arg("-dynamiclib");
300             self.linker_arg("-dylib");
301
302             // Note that the `osx_rpath_install_name` option here is a hack
303             // purely to support rustbuild right now, we should get a more
304             // principled solution at some point to force the compiler to pass
305             // the right `-Wl,-install_name` with an `@rpath` in it.
306             if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
307                 self.linker_arg("-install_name");
308                 let mut v = OsString::from("@rpath/");
309                 v.push(out_filename.file_name().unwrap());
310                 self.linker_arg(&v);
311             }
312         } else {
313             self.cmd.arg("-shared");
314             if self.sess.target.is_like_windows {
315                 // The output filename already contains `dll_suffix` so
316                 // the resulting import library will have a name in the
317                 // form of libfoo.dll.a
318                 let implib_name =
319                     out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
320                         format!(
321                             "{}{}{}",
322                             self.sess.target.staticlib_prefix,
323                             file,
324                             self.sess.target.staticlib_suffix
325                         )
326                     });
327                 if let Some(implib_name) = implib_name {
328                     let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
329                     if let Some(implib) = implib {
330                         self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap()));
331                     }
332                 }
333             }
334         }
335     }
336 }
337
338 impl<'a> Linker for GccLinker<'a> {
339     fn cmd(&mut self) -> &mut Command {
340         &mut self.cmd
341     }
342
343     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
344         match output_kind {
345             LinkOutputKind::DynamicNoPicExe => {
346                 if !self.is_ld && self.sess.target.linker_is_gnu {
347                     self.cmd.arg("-no-pie");
348                 }
349             }
350             LinkOutputKind::DynamicPicExe => {
351                 // noop on windows w/ gcc & ld, error w/ lld
352                 if !self.sess.target.is_like_windows {
353                     // `-pie` works for both gcc wrapper and ld.
354                     self.cmd.arg("-pie");
355                 }
356             }
357             LinkOutputKind::StaticNoPicExe => {
358                 // `-static` works for both gcc wrapper and ld.
359                 self.cmd.arg("-static");
360                 if !self.is_ld && self.sess.target.linker_is_gnu {
361                     self.cmd.arg("-no-pie");
362                 }
363             }
364             LinkOutputKind::StaticPicExe => {
365                 if !self.is_ld {
366                     // Note that combination `-static -pie` doesn't work as expected
367                     // for the gcc wrapper, `-static` in that case suppresses `-pie`.
368                     self.cmd.arg("-static-pie");
369                 } else {
370                     // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
371                     // a static pie, but currently passed because gcc and clang pass them.
372                     // The former suppresses the `INTERP` ELF header specifying dynamic linker,
373                     // which is otherwise implicitly injected by ld (but not lld).
374                     // The latter doesn't change anything, only ensures that everything is pic.
375                     self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
376                 }
377             }
378             LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
379             LinkOutputKind::StaticDylib => {
380                 self.cmd.arg("-static");
381                 self.build_dylib(out_filename);
382             }
383             LinkOutputKind::WasiReactorExe => {
384                 self.linker_arg("--entry");
385                 self.linker_arg("_initialize");
386             }
387         }
388         // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
389         // it switches linking for libc and similar system libraries to static without using
390         // any `#[link]` attributes in the `libc` crate, see #72782 for details.
391         // FIXME: Switch to using `#[link]` attributes in the `libc` crate
392         // similarly to other targets.
393         if self.sess.target.os == "vxworks"
394             && matches!(
395                 output_kind,
396                 LinkOutputKind::StaticNoPicExe
397                     | LinkOutputKind::StaticPicExe
398                     | LinkOutputKind::StaticDylib
399             )
400         {
401             self.cmd.arg("--static-crt");
402         }
403     }
404
405     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
406         if self.sess.target.os == "illumos" && lib.as_str() == "c" {
407             // libc will be added via late_link_args on illumos so that it will
408             // appear last in the library search order.
409             // FIXME: This should be replaced by a more complete and generic
410             // mechanism for controlling the order of library arguments passed
411             // to the linker.
412             return;
413         }
414         if !as_needed {
415             if self.sess.target.is_like_osx {
416                 // FIXME(81490): ld64 doesn't support these flags but macOS 11
417                 // has -needed-l{} / -needed_library {}
418                 // but we have no way to detect that here.
419                 self.sess.warn("`as-needed` modifier not implemented yet for ld64");
420             } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
421                 self.linker_arg("--no-as-needed");
422             } else {
423                 self.sess.warn("`as-needed` modifier not supported for current linker");
424             }
425         }
426         self.hint_dynamic();
427         self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
428         if !as_needed {
429             if self.sess.target.is_like_osx {
430                 // See above FIXME comment
431             } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
432                 self.linker_arg("--as-needed");
433             }
434         }
435     }
436     fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
437         self.hint_static();
438         self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
439     }
440     fn link_rlib(&mut self, lib: &Path) {
441         self.hint_static();
442         self.cmd.arg(lib);
443     }
444     fn include_path(&mut self, path: &Path) {
445         self.cmd.arg("-L").arg(path);
446     }
447     fn framework_path(&mut self, path: &Path) {
448         self.cmd.arg("-F").arg(path);
449     }
450     fn output_filename(&mut self, path: &Path) {
451         self.cmd.arg("-o").arg(path);
452     }
453     fn add_object(&mut self, path: &Path) {
454         self.cmd.arg(path);
455     }
456     fn full_relro(&mut self) {
457         self.linker_arg("-zrelro");
458         self.linker_arg("-znow");
459     }
460     fn partial_relro(&mut self) {
461         self.linker_arg("-zrelro");
462     }
463     fn no_relro(&mut self) {
464         self.linker_arg("-znorelro");
465     }
466
467     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
468         self.hint_dynamic();
469         self.cmd.arg(format!("-l{}", lib));
470     }
471
472     fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
473         self.hint_dynamic();
474         if !as_needed {
475             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
476             // flag but we have no way to detect that here.
477             // self.cmd.arg("-needed_framework").sym_arg(framework);
478             self.sess.warn("`as-needed` modifier not implemented yet for ld64");
479         }
480         self.cmd.arg("-framework").sym_arg(framework);
481     }
482
483     // Here we explicitly ask that the entire archive is included into the
484     // result artifact. For more details see #15460, but the gist is that
485     // the linker will strip away any unused objects in the archive if we
486     // don't otherwise explicitly reference them. This can occur for
487     // libraries which are just providing bindings, libraries with generic
488     // functions, etc.
489     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
490         self.hint_static();
491         let target = &self.sess.target;
492         if !target.is_like_osx {
493             self.linker_arg("--whole-archive").cmd.arg(format!(
494                 "-l{}{}",
495                 if verbatim { ":" } else { "" },
496                 lib
497             ));
498             self.linker_arg("--no-whole-archive");
499         } else {
500             // -force_load is the macOS equivalent of --whole-archive, but it
501             // involves passing the full path to the library to link.
502             self.linker_arg("-force_load");
503             let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
504             self.linker_arg(&lib);
505         }
506     }
507
508     fn link_whole_rlib(&mut self, lib: &Path) {
509         self.hint_static();
510         if self.sess.target.is_like_osx {
511             self.linker_arg("-force_load");
512             self.linker_arg(&lib);
513         } else {
514             self.linker_arg("--whole-archive").cmd.arg(lib);
515             self.linker_arg("--no-whole-archive");
516         }
517     }
518
519     fn gc_sections(&mut self, keep_metadata: bool) {
520         // The dead_strip option to the linker specifies that functions and data
521         // unreachable by the entry point will be removed. This is quite useful
522         // with Rust's compilation model of compiling libraries at a time into
523         // one object file. For example, this brings hello world from 1.7MB to
524         // 458K.
525         //
526         // Note that this is done for both executables and dynamic libraries. We
527         // won't get much benefit from dylibs because LLVM will have already
528         // stripped away as much as it could. This has not been seen to impact
529         // link times negatively.
530         //
531         // -dead_strip can't be part of the pre_link_args because it's also used
532         // for partial linking when using multiple codegen units (-r).  So we
533         // insert it here.
534         if self.sess.target.is_like_osx {
535             self.linker_arg("-dead_strip");
536
537         // If we're building a dylib, we don't use --gc-sections because LLVM
538         // has already done the best it can do, and we also don't want to
539         // eliminate the metadata. If we're building an executable, however,
540         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
541         // reduction.
542         } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
543             && !keep_metadata
544         {
545             self.linker_arg("--gc-sections");
546         }
547     }
548
549     fn no_gc_sections(&mut self) {
550         if self.sess.target.is_like_osx {
551             self.linker_arg("-no_dead_strip");
552         } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
553             self.linker_arg("--no-gc-sections");
554         }
555     }
556
557     fn optimize(&mut self) {
558         if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
559             return;
560         }
561
562         // GNU-style linkers support optimization with -O. GNU ld doesn't
563         // need a numeric argument, but other linkers do.
564         if self.sess.opts.optimize == config::OptLevel::Default
565             || self.sess.opts.optimize == config::OptLevel::Aggressive
566         {
567             self.linker_arg("-O1");
568         }
569     }
570
571     fn pgo_gen(&mut self) {
572         if !self.sess.target.linker_is_gnu {
573             return;
574         }
575
576         // If we're doing PGO generation stuff and on a GNU-like linker, use the
577         // "-u" flag to properly pull in the profiler runtime bits.
578         //
579         // This is because LLVM otherwise won't add the needed initialization
580         // for us on Linux (though the extra flag should be harmless if it
581         // does).
582         //
583         // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
584         //
585         // Though it may be worth to try to revert those changes upstream, since
586         // the overhead of the initialization should be minor.
587         self.cmd.arg("-u");
588         self.cmd.arg("__llvm_profile_runtime");
589     }
590
591     fn control_flow_guard(&mut self) {}
592
593     fn debuginfo(&mut self, strip: Strip) {
594         // MacOS linker doesn't support stripping symbols directly anymore.
595         if self.sess.target.is_like_osx {
596             return;
597         }
598
599         match strip {
600             Strip::None => {}
601             Strip::Debuginfo => {
602                 self.linker_arg("--strip-debug");
603             }
604             Strip::Symbols => {
605                 self.linker_arg("--strip-all");
606             }
607         }
608     }
609
610     fn no_crt_objects(&mut self) {
611         if !self.is_ld {
612             self.cmd.arg("-nostartfiles");
613         }
614     }
615
616     fn no_default_libraries(&mut self) {
617         if !self.is_ld {
618             self.cmd.arg("-nodefaultlibs");
619         }
620     }
621
622     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
623         // Symbol visibility in object files typically takes care of this.
624         if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
625         {
626             return;
627         }
628
629         // We manually create a list of exported symbols to ensure we don't expose any more.
630         // The object files have far more public symbols than we actually want to export,
631         // so we hide them all here.
632
633         if !self.sess.target.limit_rdylib_exports {
634             return;
635         }
636
637         if crate_type == CrateType::ProcMacro {
638             return;
639         }
640
641         let is_windows = self.sess.target.is_like_windows;
642         let mut arg = OsString::new();
643         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
644
645         debug!("EXPORTED SYMBOLS:");
646
647         if self.sess.target.is_like_osx {
648             // Write a plain, newline-separated list of symbols
649             let res: io::Result<()> = try {
650                 let mut f = BufWriter::new(File::create(&path)?);
651                 for sym in symbols {
652                     debug!("  _{}", sym);
653                     writeln!(f, "_{}", sym)?;
654                 }
655             };
656             if let Err(e) = res {
657                 self.sess.fatal(&format!("failed to write lib.def file: {}", e));
658             }
659         } else if is_windows {
660             let res: io::Result<()> = try {
661                 let mut f = BufWriter::new(File::create(&path)?);
662
663                 // .def file similar to MSVC one but without LIBRARY section
664                 // because LD doesn't like when it's empty
665                 writeln!(f, "EXPORTS")?;
666                 for symbol in symbols {
667                     debug!("  _{}", symbol);
668                     writeln!(f, "  {}", symbol)?;
669                 }
670             };
671             if let Err(e) = res {
672                 self.sess.fatal(&format!("failed to write list.def file: {}", e));
673             }
674         } else {
675             // Write an LD version script
676             let res: io::Result<()> = try {
677                 let mut f = BufWriter::new(File::create(&path)?);
678                 writeln!(f, "{{")?;
679                 if !symbols.is_empty() {
680                     writeln!(f, "  global:")?;
681                     for sym in symbols {
682                         debug!("    {};", sym);
683                         writeln!(f, "    {};", sym)?;
684                     }
685                 }
686                 writeln!(f, "\n  local:\n    *;\n}};")?;
687             };
688             if let Err(e) = res {
689                 self.sess.fatal(&format!("failed to write version script: {}", e));
690             }
691         }
692
693         if self.sess.target.is_like_osx {
694             if !self.is_ld {
695                 arg.push("-Wl,")
696             }
697             arg.push("-exported_symbols_list,");
698         } else if self.sess.target.is_like_solaris {
699             if !self.is_ld {
700                 arg.push("-Wl,")
701             }
702             arg.push("-M,");
703         } else {
704             if !self.is_ld {
705                 arg.push("-Wl,")
706             }
707             // Both LD and LLD accept export list in *.def file form, there are no flags required
708             if !is_windows {
709                 arg.push("--version-script=")
710             }
711         }
712
713         arg.push(&path);
714         self.cmd.arg(arg);
715     }
716
717     fn subsystem(&mut self, subsystem: &str) {
718         self.linker_arg("--subsystem");
719         self.linker_arg(&subsystem);
720     }
721
722     fn reset_per_library_state(&mut self) {
723         self.hint_dynamic(); // Reset to default before returning the composed command line.
724     }
725
726     fn group_start(&mut self) {
727         if self.takes_hints() {
728             self.linker_arg("--start-group");
729         }
730     }
731
732     fn group_end(&mut self) {
733         if self.takes_hints() {
734             self.linker_arg("--end-group");
735         }
736     }
737
738     fn linker_plugin_lto(&mut self) {
739         match self.sess.opts.cg.linker_plugin_lto {
740             LinkerPluginLto::Disabled => {
741                 // Nothing to do
742             }
743             LinkerPluginLto::LinkerPluginAuto => {
744                 self.push_linker_plugin_lto_args(None);
745             }
746             LinkerPluginLto::LinkerPlugin(ref path) => {
747                 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
748             }
749         }
750     }
751
752     // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information.
753     // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
754     // so we just always add it.
755     fn add_eh_frame_header(&mut self) {
756         self.linker_arg("--eh-frame-hdr");
757     }
758
759     fn add_no_exec(&mut self) {
760         if self.sess.target.is_like_windows {
761             self.linker_arg("--nxcompat");
762         } else if self.sess.target.linker_is_gnu {
763             self.linker_arg("-znoexecstack");
764         }
765     }
766
767     fn add_as_needed(&mut self) {
768         if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
769             self.linker_arg("--as-needed");
770         } else if self.sess.target.is_like_solaris {
771             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
772             self.linker_arg("-z");
773             self.linker_arg("ignore");
774         }
775     }
776 }
777
778 pub struct MsvcLinker<'a> {
779     cmd: Command,
780     sess: &'a Session,
781 }
782
783 impl<'a> Linker for MsvcLinker<'a> {
784     fn cmd(&mut self) -> &mut Command {
785         &mut self.cmd
786     }
787
788     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
789         match output_kind {
790             LinkOutputKind::DynamicNoPicExe
791             | LinkOutputKind::DynamicPicExe
792             | LinkOutputKind::StaticNoPicExe
793             | LinkOutputKind::StaticPicExe => {}
794             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
795                 self.cmd.arg("/DLL");
796                 let mut arg: OsString = "/IMPLIB:".into();
797                 arg.push(out_filename.with_extension("dll.lib"));
798                 self.cmd.arg(arg);
799             }
800             LinkOutputKind::WasiReactorExe => {
801                 panic!("can't link as reactor on non-wasi target");
802             }
803         }
804     }
805
806     fn link_rlib(&mut self, lib: &Path) {
807         self.cmd.arg(lib);
808     }
809     fn add_object(&mut self, path: &Path) {
810         self.cmd.arg(path);
811     }
812
813     fn gc_sections(&mut self, _keep_metadata: bool) {
814         // MSVC's ICF (Identical COMDAT Folding) link optimization is
815         // slow for Rust and thus we disable it by default when not in
816         // optimization build.
817         if self.sess.opts.optimize != config::OptLevel::No {
818             self.cmd.arg("/OPT:REF,ICF");
819         } else {
820             // It is necessary to specify NOICF here, because /OPT:REF
821             // implies ICF by default.
822             self.cmd.arg("/OPT:REF,NOICF");
823         }
824     }
825
826     fn no_gc_sections(&mut self) {
827         self.cmd.arg("/OPT:NOREF,NOICF");
828     }
829
830     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
831         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
832     }
833
834     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
835         // When producing a dll, the MSVC linker may not actually emit a
836         // `foo.lib` file if the dll doesn't actually export any symbols, so we
837         // check to see if the file is there and just omit linking to it if it's
838         // not present.
839         let name = format!("{}.dll.lib", lib);
840         if path.join(&name).exists() {
841             self.cmd.arg(name);
842         }
843     }
844
845     fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
846         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
847     }
848
849     fn full_relro(&mut self) {
850         // noop
851     }
852
853     fn partial_relro(&mut self) {
854         // noop
855     }
856
857     fn no_relro(&mut self) {
858         // noop
859     }
860
861     fn no_crt_objects(&mut self) {
862         // noop
863     }
864
865     fn no_default_libraries(&mut self) {
866         self.cmd.arg("/NODEFAULTLIB");
867     }
868
869     fn include_path(&mut self, path: &Path) {
870         let mut arg = OsString::from("/LIBPATH:");
871         arg.push(path);
872         self.cmd.arg(&arg);
873     }
874
875     fn output_filename(&mut self, path: &Path) {
876         let mut arg = OsString::from("/OUT:");
877         arg.push(path);
878         self.cmd.arg(&arg);
879     }
880
881     fn framework_path(&mut self, _path: &Path) {
882         bug!("frameworks are not supported on windows")
883     }
884     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
885         bug!("frameworks are not supported on windows")
886     }
887
888     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
889         self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
890     }
891     fn link_whole_rlib(&mut self, path: &Path) {
892         let mut arg = OsString::from("/WHOLEARCHIVE:");
893         arg.push(path);
894         self.cmd.arg(arg);
895     }
896     fn optimize(&mut self) {
897         // Needs more investigation of `/OPT` arguments
898     }
899
900     fn pgo_gen(&mut self) {
901         // Nothing needed here.
902     }
903
904     fn control_flow_guard(&mut self) {
905         self.cmd.arg("/guard:cf");
906     }
907
908     fn debuginfo(&mut self, strip: Strip) {
909         match strip {
910             Strip::None => {
911                 // This will cause the Microsoft linker to generate a PDB file
912                 // from the CodeView line tables in the object files.
913                 self.cmd.arg("/DEBUG");
914
915                 // This will cause the Microsoft linker to embed .natvis info into the PDB file
916                 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
917                 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
918                     for entry in natvis_dir {
919                         match entry {
920                             Ok(entry) => {
921                                 let path = entry.path();
922                                 if path.extension() == Some("natvis".as_ref()) {
923                                     let mut arg = OsString::from("/NATVIS:");
924                                     arg.push(path);
925                                     self.cmd.arg(arg);
926                                 }
927                             }
928                             Err(err) => {
929                                 self.sess
930                                     .warn(&format!("error enumerating natvis directory: {}", err));
931                             }
932                         }
933                     }
934                 }
935             }
936             Strip::Debuginfo | Strip::Symbols => {
937                 self.cmd.arg("/DEBUG:NONE");
938             }
939         }
940     }
941
942     // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
943     // export symbols from a dynamic library. When building a dynamic library,
944     // however, we're going to want some symbols exported, so this function
945     // generates a DEF file which lists all the symbols.
946     //
947     // The linker will read this `*.def` file and export all the symbols from
948     // the dynamic library. Note that this is not as simple as just exporting
949     // all the symbols in the current crate (as specified by `codegen.reachable`)
950     // but rather we also need to possibly export the symbols of upstream
951     // crates. Upstream rlibs may be linked statically to this dynamic library,
952     // in which case they may continue to transitively be used and hence need
953     // their symbols exported.
954     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
955         // Symbol visibility takes care of this typically
956         if crate_type == CrateType::Executable {
957             return;
958         }
959
960         let path = tmpdir.join("lib.def");
961         let res: io::Result<()> = try {
962             let mut f = BufWriter::new(File::create(&path)?);
963
964             // Start off with the standard module name header and then go
965             // straight to exports.
966             writeln!(f, "LIBRARY")?;
967             writeln!(f, "EXPORTS")?;
968             for symbol in symbols {
969                 debug!("  _{}", symbol);
970                 writeln!(f, "  {}", symbol)?;
971             }
972         };
973         if let Err(e) = res {
974             self.sess.fatal(&format!("failed to write lib.def file: {}", e));
975         }
976         let mut arg = OsString::from("/DEF:");
977         arg.push(path);
978         self.cmd.arg(&arg);
979     }
980
981     fn subsystem(&mut self, subsystem: &str) {
982         // Note that previous passes of the compiler validated this subsystem,
983         // so we just blindly pass it to the linker.
984         self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
985
986         // Windows has two subsystems we're interested in right now, the console
987         // and windows subsystems. These both implicitly have different entry
988         // points (starting symbols). The console entry point starts with
989         // `mainCRTStartup` and the windows entry point starts with
990         // `WinMainCRTStartup`. These entry points, defined in system libraries,
991         // will then later probe for either `main` or `WinMain`, respectively to
992         // start the application.
993         //
994         // In Rust we just always generate a `main` function so we want control
995         // to always start there, so we force the entry point on the windows
996         // subsystem to be `mainCRTStartup` to get everything booted up
997         // correctly.
998         //
999         // For more information see RFC #1665
1000         if subsystem == "windows" {
1001             self.cmd.arg("/ENTRY:mainCRTStartup");
1002         }
1003     }
1004
1005     // MSVC doesn't need group indicators
1006     fn group_start(&mut self) {}
1007     fn group_end(&mut self) {}
1008
1009     fn linker_plugin_lto(&mut self) {
1010         // Do nothing
1011     }
1012
1013     fn add_no_exec(&mut self) {
1014         self.cmd.arg("/NXCOMPAT");
1015     }
1016 }
1017
1018 pub struct EmLinker<'a> {
1019     cmd: Command,
1020     sess: &'a Session,
1021 }
1022
1023 impl<'a> Linker for EmLinker<'a> {
1024     fn cmd(&mut self) -> &mut Command {
1025         &mut self.cmd
1026     }
1027
1028     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1029
1030     fn include_path(&mut self, path: &Path) {
1031         self.cmd.arg("-L").arg(path);
1032     }
1033
1034     fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
1035         self.cmd.arg("-l").sym_arg(lib);
1036     }
1037
1038     fn output_filename(&mut self, path: &Path) {
1039         self.cmd.arg("-o").arg(path);
1040     }
1041
1042     fn add_object(&mut self, path: &Path) {
1043         self.cmd.arg(path);
1044     }
1045
1046     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
1047         // Emscripten always links statically
1048         self.link_staticlib(lib, verbatim);
1049     }
1050
1051     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
1052         // not supported?
1053         self.link_staticlib(lib, verbatim);
1054     }
1055
1056     fn link_whole_rlib(&mut self, lib: &Path) {
1057         // not supported?
1058         self.link_rlib(lib);
1059     }
1060
1061     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
1062         self.link_dylib(lib, false, true);
1063     }
1064
1065     fn link_rlib(&mut self, lib: &Path) {
1066         self.add_object(lib);
1067     }
1068
1069     fn full_relro(&mut self) {
1070         // noop
1071     }
1072
1073     fn partial_relro(&mut self) {
1074         // noop
1075     }
1076
1077     fn no_relro(&mut self) {
1078         // noop
1079     }
1080
1081     fn framework_path(&mut self, _path: &Path) {
1082         bug!("frameworks are not supported on Emscripten")
1083     }
1084
1085     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1086         bug!("frameworks are not supported on Emscripten")
1087     }
1088
1089     fn gc_sections(&mut self, _keep_metadata: bool) {
1090         // noop
1091     }
1092
1093     fn no_gc_sections(&mut self) {
1094         // noop
1095     }
1096
1097     fn optimize(&mut self) {
1098         // Emscripten performs own optimizations
1099         self.cmd.arg(match self.sess.opts.optimize {
1100             OptLevel::No => "-O0",
1101             OptLevel::Less => "-O1",
1102             OptLevel::Default => "-O2",
1103             OptLevel::Aggressive => "-O3",
1104             OptLevel::Size => "-Os",
1105             OptLevel::SizeMin => "-Oz",
1106         });
1107         // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
1108         self.cmd.args(&["--memory-init-file", "0"]);
1109     }
1110
1111     fn pgo_gen(&mut self) {
1112         // noop, but maybe we need something like the gnu linker?
1113     }
1114
1115     fn control_flow_guard(&mut self) {}
1116
1117     fn debuginfo(&mut self, _strip: Strip) {
1118         // Preserve names or generate source maps depending on debug info
1119         self.cmd.arg(match self.sess.opts.debuginfo {
1120             DebugInfo::None => "-g0",
1121             DebugInfo::Limited => "-g3",
1122             DebugInfo::Full => "-g4",
1123         });
1124     }
1125
1126     fn no_crt_objects(&mut self) {}
1127
1128     fn no_default_libraries(&mut self) {
1129         self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
1130     }
1131
1132     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1133         debug!("EXPORTED SYMBOLS:");
1134
1135         self.cmd.arg("-s");
1136
1137         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1138         let mut encoded = String::new();
1139
1140         {
1141             let mut encoder = json::Encoder::new(&mut encoded);
1142             let res = encoder.emit_seq(symbols.len(), |encoder| {
1143                 for (i, sym) in symbols.iter().enumerate() {
1144                     encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
1145                 }
1146                 Ok(())
1147             });
1148             if let Err(e) = res {
1149                 self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
1150             }
1151         }
1152         debug!("{}", encoded);
1153         arg.push(encoded);
1154
1155         self.cmd.arg(arg);
1156     }
1157
1158     fn subsystem(&mut self, _subsystem: &str) {
1159         // noop
1160     }
1161
1162     // Appears not necessary on Emscripten
1163     fn group_start(&mut self) {}
1164     fn group_end(&mut self) {}
1165
1166     fn linker_plugin_lto(&mut self) {
1167         // Do nothing
1168     }
1169 }
1170
1171 pub struct WasmLd<'a> {
1172     cmd: Command,
1173     sess: &'a Session,
1174 }
1175
1176 impl<'a> WasmLd<'a> {
1177     fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1178         // If the atomics feature is enabled for wasm then we need a whole bunch
1179         // of flags:
1180         //
1181         // * `--shared-memory` - the link won't even succeed without this, flags
1182         //   the one linear memory as `shared`
1183         //
1184         // * `--max-memory=1G` - when specifying a shared memory this must also
1185         //   be specified. We conservatively choose 1GB but users should be able
1186         //   to override this with `-C link-arg`.
1187         //
1188         // * `--import-memory` - it doesn't make much sense for memory to be
1189         //   exported in a threaded module because typically you're
1190         //   sharing memory and instantiating the module multiple times. As a
1191         //   result if it were exported then we'd just have no sharing.
1192         //
1193         // * `--export=__wasm_init_memory` - when using `--passive-segments` the
1194         //   linker will synthesize this function, and so we need to make sure
1195         //   that our usage of `--export` below won't accidentally cause this
1196         //   function to get deleted.
1197         //
1198         // * `--export=*tls*` - when `#[thread_local]` symbols are used these
1199         //   symbols are how the TLS segments are initialized and configured.
1200         if sess.target_features.contains(&sym::atomics) {
1201             cmd.arg("--shared-memory");
1202             cmd.arg("--max-memory=1073741824");
1203             cmd.arg("--import-memory");
1204             cmd.arg("--export=__wasm_init_memory");
1205             cmd.arg("--export=__wasm_init_tls");
1206             cmd.arg("--export=__tls_size");
1207             cmd.arg("--export=__tls_align");
1208             cmd.arg("--export=__tls_base");
1209         }
1210         WasmLd { cmd, sess }
1211     }
1212 }
1213
1214 impl<'a> Linker for WasmLd<'a> {
1215     fn cmd(&mut self) -> &mut Command {
1216         &mut self.cmd
1217     }
1218
1219     fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
1220         match output_kind {
1221             LinkOutputKind::DynamicNoPicExe
1222             | LinkOutputKind::DynamicPicExe
1223             | LinkOutputKind::StaticNoPicExe
1224             | LinkOutputKind::StaticPicExe => {}
1225             LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1226                 self.cmd.arg("--no-entry");
1227             }
1228             LinkOutputKind::WasiReactorExe => {
1229                 self.cmd.arg("--entry");
1230                 self.cmd.arg("_initialize");
1231             }
1232         }
1233     }
1234
1235     fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
1236         self.cmd.arg("-l").sym_arg(lib);
1237     }
1238
1239     fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
1240         self.cmd.arg("-l").sym_arg(lib);
1241     }
1242
1243     fn link_rlib(&mut self, lib: &Path) {
1244         self.cmd.arg(lib);
1245     }
1246
1247     fn include_path(&mut self, path: &Path) {
1248         self.cmd.arg("-L").arg(path);
1249     }
1250
1251     fn framework_path(&mut self, _path: &Path) {
1252         panic!("frameworks not supported")
1253     }
1254
1255     fn output_filename(&mut self, path: &Path) {
1256         self.cmd.arg("-o").arg(path);
1257     }
1258
1259     fn add_object(&mut self, path: &Path) {
1260         self.cmd.arg(path);
1261     }
1262
1263     fn full_relro(&mut self) {}
1264
1265     fn partial_relro(&mut self) {}
1266
1267     fn no_relro(&mut self) {}
1268
1269     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
1270         self.cmd.arg("-l").sym_arg(lib);
1271     }
1272
1273     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1274         panic!("frameworks not supported")
1275     }
1276
1277     fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1278         self.cmd.arg("-l").sym_arg(lib);
1279     }
1280
1281     fn link_whole_rlib(&mut self, lib: &Path) {
1282         self.cmd.arg(lib);
1283     }
1284
1285     fn gc_sections(&mut self, _keep_metadata: bool) {
1286         self.cmd.arg("--gc-sections");
1287     }
1288
1289     fn no_gc_sections(&mut self) {
1290         self.cmd.arg("--no-gc-sections");
1291     }
1292
1293     fn optimize(&mut self) {
1294         self.cmd.arg(match self.sess.opts.optimize {
1295             OptLevel::No => "-O0",
1296             OptLevel::Less => "-O1",
1297             OptLevel::Default => "-O2",
1298             OptLevel::Aggressive => "-O3",
1299             // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
1300             // instead.
1301             OptLevel::Size => "-O2",
1302             OptLevel::SizeMin => "-O2",
1303         });
1304     }
1305
1306     fn pgo_gen(&mut self) {}
1307
1308     fn debuginfo(&mut self, strip: Strip) {
1309         match strip {
1310             Strip::None => {}
1311             Strip::Debuginfo => {
1312                 self.cmd.arg("--strip-debug");
1313             }
1314             Strip::Symbols => {
1315                 self.cmd.arg("--strip-all");
1316             }
1317         }
1318     }
1319
1320     fn control_flow_guard(&mut self) {}
1321
1322     fn no_crt_objects(&mut self) {}
1323
1324     fn no_default_libraries(&mut self) {}
1325
1326     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1327         for sym in symbols {
1328             self.cmd.arg("--export").arg(&sym);
1329         }
1330
1331         // LLD will hide these otherwise-internal symbols since it only exports
1332         // symbols explicity passed via the `--export` flags above and hides all
1333         // others. Various bits and pieces of tooling use this, so be sure these
1334         // symbols make their way out of the linker as well.
1335         self.cmd.arg("--export=__heap_base");
1336         self.cmd.arg("--export=__data_end");
1337     }
1338
1339     fn subsystem(&mut self, _subsystem: &str) {}
1340
1341     // Not needed for now with LLD
1342     fn group_start(&mut self) {}
1343     fn group_end(&mut self) {}
1344
1345     fn linker_plugin_lto(&mut self) {
1346         // Do nothing for now
1347     }
1348 }
1349
1350 pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1351     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1352         return exports.clone();
1353     }
1354
1355     let mut symbols = Vec::new();
1356
1357     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1358     for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
1359         if level.is_below_threshold(export_threshold) {
1360             symbols.push(symbol_export::symbol_name_for_instance_in_crate(
1361                 tcx,
1362                 symbol,
1363                 LOCAL_CRATE,
1364             ));
1365         }
1366     }
1367
1368     let formats = tcx.dependency_formats(());
1369     let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
1370
1371     for (index, dep_format) in deps.iter().enumerate() {
1372         let cnum = CrateNum::new(index + 1);
1373         // For each dependency that we are linking to statically ...
1374         if *dep_format == Linkage::Static {
1375             // ... we add its symbol list to our export list.
1376             for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
1377                 if !level.is_below_threshold(export_threshold) {
1378                     continue;
1379                 }
1380
1381                 symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
1382             }
1383         }
1384     }
1385
1386     symbols
1387 }
1388
1389 /// Much simplified and explicit CLI for the NVPTX linker. The linker operates
1390 /// with bitcode and uses LLVM backend to generate a PTX assembly.
1391 pub struct PtxLinker<'a> {
1392     cmd: Command,
1393     sess: &'a Session,
1394 }
1395
1396 impl<'a> Linker for PtxLinker<'a> {
1397     fn cmd(&mut self) -> &mut Command {
1398         &mut self.cmd
1399     }
1400
1401     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1402
1403     fn link_rlib(&mut self, path: &Path) {
1404         self.cmd.arg("--rlib").arg(path);
1405     }
1406
1407     fn link_whole_rlib(&mut self, path: &Path) {
1408         self.cmd.arg("--rlib").arg(path);
1409     }
1410
1411     fn include_path(&mut self, path: &Path) {
1412         self.cmd.arg("-L").arg(path);
1413     }
1414
1415     fn debuginfo(&mut self, _strip: Strip) {
1416         self.cmd.arg("--debug");
1417     }
1418
1419     fn add_object(&mut self, path: &Path) {
1420         self.cmd.arg("--bitcode").arg(path);
1421     }
1422
1423     fn optimize(&mut self) {
1424         match self.sess.lto() {
1425             Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1426                 self.cmd.arg("-Olto");
1427             }
1428
1429             Lto::No => {}
1430         };
1431     }
1432
1433     fn output_filename(&mut self, path: &Path) {
1434         self.cmd.arg("-o").arg(path);
1435     }
1436
1437     fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
1438         panic!("external dylibs not supported")
1439     }
1440
1441     fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
1442         panic!("external dylibs not supported")
1443     }
1444
1445     fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
1446         panic!("staticlibs not supported")
1447     }
1448
1449     fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1450         panic!("staticlibs not supported")
1451     }
1452
1453     fn framework_path(&mut self, _path: &Path) {
1454         panic!("frameworks not supported")
1455     }
1456
1457     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1458         panic!("frameworks not supported")
1459     }
1460
1461     fn full_relro(&mut self) {}
1462
1463     fn partial_relro(&mut self) {}
1464
1465     fn no_relro(&mut self) {}
1466
1467     fn gc_sections(&mut self, _keep_metadata: bool) {}
1468
1469     fn no_gc_sections(&mut self) {}
1470
1471     fn pgo_gen(&mut self) {}
1472
1473     fn no_crt_objects(&mut self) {}
1474
1475     fn no_default_libraries(&mut self) {}
1476
1477     fn control_flow_guard(&mut self) {}
1478
1479     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1480
1481     fn subsystem(&mut self, _subsystem: &str) {}
1482
1483     fn group_start(&mut self) {}
1484
1485     fn group_end(&mut self) {}
1486
1487     fn linker_plugin_lto(&mut self) {}
1488 }
1489
1490 pub struct BpfLinker<'a> {
1491     cmd: Command,
1492     sess: &'a Session,
1493 }
1494
1495 impl<'a> Linker for BpfLinker<'a> {
1496     fn cmd(&mut self) -> &mut Command {
1497         &mut self.cmd
1498     }
1499
1500     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1501
1502     fn link_rlib(&mut self, path: &Path) {
1503         self.cmd.arg(path);
1504     }
1505
1506     fn link_whole_rlib(&mut self, path: &Path) {
1507         self.cmd.arg(path);
1508     }
1509
1510     fn include_path(&mut self, path: &Path) {
1511         self.cmd.arg("-L").arg(path);
1512     }
1513
1514     fn debuginfo(&mut self, _strip: Strip) {
1515         self.cmd.arg("--debug");
1516     }
1517
1518     fn add_object(&mut self, path: &Path) {
1519         self.cmd.arg(path);
1520     }
1521
1522     fn optimize(&mut self) {
1523         self.cmd.arg(match self.sess.opts.optimize {
1524             OptLevel::No => "-O0",
1525             OptLevel::Less => "-O1",
1526             OptLevel::Default => "-O2",
1527             OptLevel::Aggressive => "-O3",
1528             OptLevel::Size => "-Os",
1529             OptLevel::SizeMin => "-Oz",
1530         });
1531     }
1532
1533     fn output_filename(&mut self, path: &Path) {
1534         self.cmd.arg("-o").arg(path);
1535     }
1536
1537     fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
1538         panic!("external dylibs not supported")
1539     }
1540
1541     fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
1542         panic!("external dylibs not supported")
1543     }
1544
1545     fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
1546         panic!("staticlibs not supported")
1547     }
1548
1549     fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
1550         panic!("staticlibs not supported")
1551     }
1552
1553     fn framework_path(&mut self, _path: &Path) {
1554         panic!("frameworks not supported")
1555     }
1556
1557     fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
1558         panic!("frameworks not supported")
1559     }
1560
1561     fn full_relro(&mut self) {}
1562
1563     fn partial_relro(&mut self) {}
1564
1565     fn no_relro(&mut self) {}
1566
1567     fn gc_sections(&mut self, _keep_metadata: bool) {}
1568
1569     fn no_gc_sections(&mut self) {}
1570
1571     fn pgo_gen(&mut self) {}
1572
1573     fn no_crt_objects(&mut self) {}
1574
1575     fn no_default_libraries(&mut self) {}
1576
1577     fn control_flow_guard(&mut self) {}
1578
1579     fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1580         let path = tmpdir.join("symbols");
1581         let res: io::Result<()> = try {
1582             let mut f = BufWriter::new(File::create(&path)?);
1583             for sym in symbols {
1584                 writeln!(f, "{}", sym)?;
1585             }
1586         };
1587         if let Err(e) = res {
1588             self.sess.fatal(&format!("failed to write symbols file: {}", e));
1589         } else {
1590             self.cmd.arg("--export-symbols").arg(&path);
1591         }
1592     }
1593
1594     fn subsystem(&mut self, _subsystem: &str) {}
1595
1596     fn group_start(&mut self) {}
1597
1598     fn group_end(&mut self) {}
1599
1600     fn linker_plugin_lto(&mut self) {}
1601 }