1use std::ffi::{OsStr, OsString};
2use std::fs::{self, File};
3use std::io::prelude::*;
4use std::path::{Path, PathBuf};
5use std::{env, io, iter, mem, str};
6
7use cc::windows_registry;
8use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
9use rustc_metadata::{
10 find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
11};
12use rustc_middle::bug;
13use rustc_middle::middle::dependency_format::Linkage;
14use rustc_middle::middle::exported_symbols;
15use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
16use rustc_middle::ty::TyCtxt;
17use rustc_session::Session;
18use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
19use rustc_span::sym;
20use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
21use tracing::{debug, warn};
22
23use super::command::Command;
24use super::symbol_export;
25use crate::errors;
26
27#[cfg(test)]
28mod tests;
29
30pub(crate) fn disable_localization(linker: &mut Command) {
36 linker.env("LC_ALL", "C");
39 linker.env("VSLANG", "1033");
41}
42
43pub(crate) fn get_linker<'a>(
47 sess: &'a Session,
48 linker: &Path,
49 flavor: LinkerFlavor,
50 self_contained: bool,
51 target_cpu: &'a str,
52) -> Box<dyn Linker + 'a> {
53 let msvc_tool = windows_registry::find_tool(&sess.target.arch, "link.exe");
54
55 let mut cmd = match linker.to_str() {
64 Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
65 _ => match flavor {
66 LinkerFlavor::Gnu(Cc::No, Lld::Yes)
67 | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
68 | LinkerFlavor::WasmLld(Cc::No)
69 | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
70 LinkerFlavor::Msvc(Lld::No)
71 if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
72 {
73 Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
74 }
75 _ => Command::new(linker),
76 },
77 };
78
79 let t = &sess.target;
83 if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
84 if let Some(ref tool) = msvc_tool {
85 let original_path = tool.path();
86 if let Some(root_lib_path) = original_path.ancestors().nth(4) {
87 let arch = match t.arch.as_ref() {
88 "x86_64" => Some("x64"),
89 "x86" => Some("x86"),
90 "aarch64" => Some("arm64"),
91 "arm" => Some("arm"),
92 _ => None,
93 };
94 if let Some(ref a) = arch {
95 let mut arg = OsString::from("/LIBPATH:");
97 arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
98 cmd.arg(&arg);
99 } else {
100 warn!("arch is not supported");
101 }
102 } else {
103 warn!("MSVC root path lib location not found");
104 }
105 } else {
106 warn!("link.exe not found");
107 }
108 }
109
110 let mut new_path = sess.get_tools_search_paths(self_contained);
113 let mut msvc_changed_path = false;
114 if sess.target.is_like_msvc
115 && let Some(ref tool) = msvc_tool
116 {
117 cmd.args(tool.args());
118 for (k, v) in tool.env() {
119 if k == "PATH" {
120 new_path.extend(env::split_paths(v));
121 msvc_changed_path = true;
122 } else {
123 cmd.env(k, v);
124 }
125 }
126 }
127
128 if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
129 new_path.extend(env::split_paths(&path));
130 }
131 cmd.env("PATH", env::join_paths(new_path).unwrap());
132
133 assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
136 match flavor {
137 LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
138 Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
139 }
140 LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
141 Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
142 }
143 LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
144 LinkerFlavor::Gnu(cc, _)
145 | LinkerFlavor::Darwin(cc, _)
146 | LinkerFlavor::WasmLld(cc)
147 | LinkerFlavor::Unix(cc) => Box::new(GccLinker {
148 cmd,
149 sess,
150 target_cpu,
151 hinted_static: None,
152 is_ld: cc == Cc::No,
153 is_gnu: flavor.is_gnu(),
154 uses_lld: flavor.uses_lld(),
155 }) as Box<dyn Linker>,
156 LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
157 LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
158 LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
159 LinkerFlavor::Llbc => Box::new(LlbcLinker { cmd, sess }) as Box<dyn Linker>,
160 LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
161 }
162}
163
164fn verbatim_args<L: Linker + ?Sized>(
174 l: &mut L,
175 args: impl IntoIterator<Item: AsRef<OsStr>>,
176) -> &mut L {
177 for arg in args {
178 l.cmd().arg(arg);
179 }
180 l
181}
182fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
185 let mut combined_arg = OsString::from("-Wl");
186 for arg in args {
187 if arg.as_ref().as_encoded_bytes().contains(&b',') {
190 if combined_arg != OsStr::new("-Wl") {
192 cmd.arg(combined_arg);
193 combined_arg = OsString::from("-Wl");
195 }
196
197 cmd.arg("-Xlinker");
199 cmd.arg(arg);
200 } else {
201 combined_arg.push(",");
203 combined_arg.push(arg);
204 }
205 }
206 if combined_arg != OsStr::new("-Wl") {
208 cmd.arg(combined_arg);
209 }
210}
211fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
214 if !l.is_cc() {
215 verbatim_args(l, args);
216 } else {
217 convert_link_args_to_cc_args(l.cmd(), args);
218 }
219 l
220}
221fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
224 assert!(l.is_cc());
225 verbatim_args(l, args)
226}
227fn link_or_cc_args<L: Linker + ?Sized>(
229 l: &mut L,
230 args: impl IntoIterator<Item: AsRef<OsStr>>,
231) -> &mut L {
232 verbatim_args(l, args)
233}
234
235macro_rules! generate_arg_methods {
236 ($($ty:ty)*) => { $(
237 impl $ty {
238 #[allow(unused)]
239 pub(crate) fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
240 verbatim_args(self, args)
241 }
242 #[allow(unused)]
243 pub(crate) fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
244 verbatim_args(self, iter::once(arg))
245 }
246 #[allow(unused)]
247 pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
248 link_args(self, args)
249 }
250 #[allow(unused)]
251 pub(crate) fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
252 link_args(self, iter::once(arg))
253 }
254 #[allow(unused)]
255 pub(crate) fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
256 cc_args(self, args)
257 }
258 #[allow(unused)]
259 pub(crate) fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
260 cc_args(self, iter::once(arg))
261 }
262 #[allow(unused)]
263 pub(crate) fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
264 link_or_cc_args(self, args)
265 }
266 #[allow(unused)]
267 pub(crate) fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
268 link_or_cc_args(self, iter::once(arg))
269 }
270 }
271 )* }
272}
273
274generate_arg_methods! {
275 GccLinker<'_>
276 MsvcLinker<'_>
277 EmLinker<'_>
278 WasmLd<'_>
279 L4Bender<'_>
280 AixLinker<'_>
281 LlbcLinker<'_>
282 PtxLinker<'_>
283 BpfLinker<'_>
284 dyn Linker + '_
285}
286
287pub(crate) trait Linker {
295 fn cmd(&mut self) -> &mut Command;
296 fn is_cc(&self) -> bool {
297 false
298 }
299 fn set_output_kind(
300 &mut self,
301 output_kind: LinkOutputKind,
302 crate_type: CrateType,
303 out_filename: &Path,
304 );
305 fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
306 bug!("dylib linked with unsupported linker")
307 }
308 fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
309 bug!("dylib linked with unsupported linker")
310 }
311 fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
312 bug!("framework linked with unsupported linker")
313 }
314 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
315 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
316 fn include_path(&mut self, path: &Path) {
317 link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]);
318 }
319 fn framework_path(&mut self, _path: &Path) {
320 bug!("framework path set with unsupported linker")
321 }
322 fn output_filename(&mut self, path: &Path) {
323 link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]);
324 }
325 fn add_object(&mut self, path: &Path) {
326 link_or_cc_args(self, &[path]);
327 }
328 fn gc_sections(&mut self, keep_metadata: bool);
329 fn no_gc_sections(&mut self);
330 fn full_relro(&mut self);
331 fn partial_relro(&mut self);
332 fn no_relro(&mut self);
333 fn optimize(&mut self);
334 fn pgo_gen(&mut self);
335 fn control_flow_guard(&mut self);
336 fn ehcont_guard(&mut self);
337 fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
338 fn no_crt_objects(&mut self);
339 fn no_default_libraries(&mut self);
340 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
341 fn subsystem(&mut self, subsystem: &str);
342 fn linker_plugin_lto(&mut self);
343 fn add_eh_frame_header(&mut self) {}
344 fn add_no_exec(&mut self) {}
345 fn add_as_needed(&mut self) {}
346 fn reset_per_library_state(&mut self) {}
347}
348
349impl dyn Linker + '_ {
350 pub(crate) fn take_cmd(&mut self) -> Command {
351 mem::replace(self.cmd(), Command::new(""))
352 }
353}
354
355struct GccLinker<'a> {
356 cmd: Command,
357 sess: &'a Session,
358 target_cpu: &'a str,
359 hinted_static: Option<bool>, is_ld: bool,
362 is_gnu: bool,
363 uses_lld: bool,
364}
365
366impl<'a> GccLinker<'a> {
367 fn takes_hints(&self) -> bool {
368 !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm
377 }
378
379 fn hint_static(&mut self) {
384 if !self.takes_hints() {
385 return;
386 }
387 if self.hinted_static != Some(true) {
388 self.link_arg("-Bstatic");
389 self.hinted_static = Some(true);
390 }
391 }
392
393 fn hint_dynamic(&mut self) {
394 if !self.takes_hints() {
395 return;
396 }
397 if self.hinted_static != Some(false) {
398 self.link_arg("-Bdynamic");
399 self.hinted_static = Some(false);
400 }
401 }
402
403 fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
404 if let Some(plugin_path) = plugin_path {
405 let mut arg = OsString::from("-plugin=");
406 arg.push(plugin_path);
407 self.link_arg(&arg);
408 }
409
410 let opt_level = match self.sess.opts.optimize {
411 config::OptLevel::No => "O0",
412 config::OptLevel::Less => "O1",
413 config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
414 config::OptLevel::Aggressive => "O3",
415 };
416
417 if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
418 self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
419 };
420 self.link_args(&[
421 &format!("-plugin-opt={opt_level}"),
422 &format!("-plugin-opt=mcpu={}", self.target_cpu),
423 ]);
424 }
425
426 fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
427 if self.sess.target.is_like_osx {
429 if self.is_cc() {
430 self.cc_arg("-dynamiclib");
432 } else {
433 self.link_arg("-dylib");
434 }
436
437 if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
442 let mut rpath = OsString::from("@rpath/");
443 rpath.push(out_filename.file_name().unwrap());
444 self.link_arg("-install_name").link_arg(rpath);
445 }
446 } else {
447 self.link_or_cc_arg("-shared");
448 if let Some(name) = out_filename.file_name() {
449 if self.sess.target.is_like_windows {
450 let (prefix, suffix) = self.sess.staticlib_components(false);
454 let mut implib_name = OsString::from(prefix);
455 implib_name.push(name);
456 implib_name.push(suffix);
457 let mut out_implib = OsString::from("--out-implib=");
458 out_implib.push(out_filename.with_file_name(implib_name));
459 self.link_arg(out_implib);
460 } else if crate_type == CrateType::Dylib {
461 let mut soname = OsString::from("-soname=");
465 soname.push(name);
466 self.link_arg(soname);
467 }
468 }
469 }
470 }
471
472 fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
473 if !as_needed {
474 if self.sess.target.is_like_osx {
475 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
479 } else if self.is_gnu && !self.sess.target.is_like_windows {
480 self.link_arg("--no-as-needed");
481 } else {
482 self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
483 }
484 }
485
486 f(self);
487
488 if !as_needed {
489 if self.sess.target.is_like_osx {
490 } else if self.is_gnu && !self.sess.target.is_like_windows {
492 self.link_arg("--as-needed");
493 }
494 }
495 }
496}
497
498impl<'a> Linker for GccLinker<'a> {
499 fn cmd(&mut self) -> &mut Command {
500 &mut self.cmd
501 }
502
503 fn is_cc(&self) -> bool {
504 !self.is_ld
505 }
506
507 fn set_output_kind(
508 &mut self,
509 output_kind: LinkOutputKind,
510 crate_type: CrateType,
511 out_filename: &Path,
512 ) {
513 match output_kind {
514 LinkOutputKind::DynamicNoPicExe => {
515 if !self.is_ld && self.is_gnu {
516 self.cc_arg("-no-pie");
517 }
518 }
519 LinkOutputKind::DynamicPicExe => {
520 if !self.sess.target.is_like_windows {
522 self.link_or_cc_arg("-pie");
524 }
525 }
526 LinkOutputKind::StaticNoPicExe => {
527 self.link_or_cc_arg("-static");
529 if !self.is_ld && self.is_gnu {
530 self.cc_arg("-no-pie");
531 }
532 }
533 LinkOutputKind::StaticPicExe => {
534 if !self.is_ld {
535 self.cc_arg("-static-pie");
538 } else {
539 self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
545 }
546 }
547 LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
548 LinkOutputKind::StaticDylib => {
549 self.link_or_cc_arg("-static");
550 self.build_dylib(crate_type, out_filename);
551 }
552 LinkOutputKind::WasiReactorExe => {
553 self.link_args(&["--entry", "_initialize"]);
554 }
555 }
556
557 if self.sess.target.os == "vxworks"
563 && matches!(
564 output_kind,
565 LinkOutputKind::StaticNoPicExe
566 | LinkOutputKind::StaticPicExe
567 | LinkOutputKind::StaticDylib
568 )
569 {
570 self.cc_arg("--static-crt");
571 }
572
573 if self.sess.target.arch == "avr" && !self.uses_lld {
579 self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
580 }
581 }
582
583 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
584 if self.sess.target.os == "illumos" && name == "c" {
585 return;
591 }
592 self.hint_dynamic();
593 self.with_as_needed(as_needed, |this| {
594 let colon = if verbatim && this.is_gnu { ":" } else { "" };
595 this.link_or_cc_arg(format!("-l{colon}{name}"));
596 });
597 }
598
599 fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
600 self.hint_dynamic();
601 self.with_as_needed(as_needed, |this| {
602 this.link_or_cc_arg(path);
603 })
604 }
605
606 fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
607 self.hint_dynamic();
608 if !as_needed {
609 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
613 }
614 self.link_or_cc_args(&["-framework", name]);
615 }
616
617 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
618 self.hint_static();
619 let colon = if verbatim && self.is_gnu { ":" } else { "" };
620 if !whole_archive {
621 self.link_or_cc_arg(format!("-l{colon}{name}"));
622 } else if self.sess.target.is_like_osx {
623 self.link_arg("-force_load");
626 self.link_arg(find_native_static_library(name, verbatim, self.sess));
627 } else {
628 self.link_arg("--whole-archive")
629 .link_or_cc_arg(format!("-l{colon}{name}"))
630 .link_arg("--no-whole-archive");
631 }
632 }
633
634 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
635 self.hint_static();
636 if !whole_archive {
637 self.link_or_cc_arg(path);
638 } else if self.sess.target.is_like_osx {
639 self.link_arg("-force_load").link_arg(path);
640 } else {
641 self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
642 }
643 }
644
645 fn framework_path(&mut self, path: &Path) {
646 self.link_or_cc_arg("-F").link_or_cc_arg(path);
647 }
648 fn full_relro(&mut self) {
649 self.link_args(&["-z", "relro", "-z", "now"]);
650 }
651 fn partial_relro(&mut self) {
652 self.link_args(&["-z", "relro"]);
653 }
654 fn no_relro(&mut self) {
655 self.link_args(&["-z", "norelro"]);
656 }
657
658 fn gc_sections(&mut self, keep_metadata: bool) {
659 if self.sess.target.is_like_osx {
674 self.link_arg("-dead_strip");
675
676 } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
682 self.link_arg("--gc-sections");
683 }
684 }
685
686 fn no_gc_sections(&mut self) {
687 if self.is_gnu || self.sess.target.is_like_wasm {
688 self.link_arg("--no-gc-sections");
689 }
690 }
691
692 fn optimize(&mut self) {
693 if !self.is_gnu && !self.sess.target.is_like_wasm {
694 return;
695 }
696
697 if self.sess.opts.optimize == config::OptLevel::More
700 || self.sess.opts.optimize == config::OptLevel::Aggressive
701 {
702 self.link_arg("-O1");
703 }
704 }
705
706 fn pgo_gen(&mut self) {
707 if !self.is_gnu {
708 return;
709 }
710
711 self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
723 }
724
725 fn control_flow_guard(&mut self) {}
726
727 fn ehcont_guard(&mut self) {}
728
729 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
730 if self.sess.target.is_like_osx {
732 return;
733 }
734
735 match strip {
736 Strip::None => {}
737 Strip::Debuginfo => {
738 if !self.sess.target.is_like_solaris {
743 self.link_arg("--strip-debug");
744 }
745 }
746 Strip::Symbols => {
747 self.link_arg("--strip-all");
748 }
749 }
750 match self.sess.opts.unstable_opts.debuginfo_compression {
751 config::DebugInfoCompression::None => {}
752 config::DebugInfoCompression::Zlib => {
753 self.link_arg("--compress-debug-sections=zlib");
754 }
755 config::DebugInfoCompression::Zstd => {
756 self.link_arg("--compress-debug-sections=zstd");
757 }
758 }
759 }
760
761 fn no_crt_objects(&mut self) {
762 if !self.is_ld {
763 self.cc_arg("-nostartfiles");
764 }
765 }
766
767 fn no_default_libraries(&mut self) {
768 if !self.is_ld {
769 self.cc_arg("-nodefaultlibs");
770 }
771 }
772
773 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
774 if crate_type == CrateType::Executable {
776 let should_export_executable_symbols =
777 self.sess.opts.unstable_opts.export_executable_symbols;
778 if self.sess.target.override_export_symbols.is_none()
779 && !should_export_executable_symbols
780 {
781 return;
782 }
783 }
784
785 if !self.sess.target.limit_rdylib_exports {
790 return;
791 }
792
793 let is_windows = self.sess.target.is_like_windows;
794 let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
795
796 debug!("EXPORTED SYMBOLS:");
797
798 if self.sess.target.is_like_osx {
799 let res: io::Result<()> = try {
801 let mut f = File::create_buffered(&path)?;
802 for sym in symbols {
803 debug!(" _{sym}");
804 writeln!(f, "_{sym}")?;
805 }
806 };
807 if let Err(error) = res {
808 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
809 }
810 } else if is_windows {
811 let res: io::Result<()> = try {
812 let mut f = File::create_buffered(&path)?;
813
814 writeln!(f, "EXPORTS")?;
817 for symbol in symbols {
818 debug!(" _{symbol}");
819 writeln!(f, " {symbol}")?;
820 }
821 };
822 if let Err(error) = res {
823 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
824 }
825 } else {
826 let res: io::Result<()> = try {
828 let mut f = File::create_buffered(&path)?;
829 writeln!(f, "{{")?;
830 if !symbols.is_empty() {
831 writeln!(f, " global:")?;
832 for sym in symbols {
833 debug!(" {sym};");
834 writeln!(f, " {sym};")?;
835 }
836 }
837 writeln!(f, "\n local:\n *;\n}};")?;
838 };
839 if let Err(error) = res {
840 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
841 }
842 }
843
844 if self.sess.target.is_like_osx {
845 self.link_arg("-exported_symbols_list").link_arg(path);
846 } else if self.sess.target.is_like_solaris {
847 self.link_arg("-M").link_arg(path);
848 } else if is_windows {
849 self.link_arg(path);
850 } else {
851 let mut arg = OsString::from("--version-script=");
852 arg.push(path);
853 self.link_arg(arg).link_arg("--no-undefined-version");
854 }
855 }
856
857 fn subsystem(&mut self, subsystem: &str) {
858 self.link_args(&["--subsystem", subsystem]);
859 }
860
861 fn reset_per_library_state(&mut self) {
862 self.hint_dynamic(); }
864
865 fn linker_plugin_lto(&mut self) {
866 match self.sess.opts.cg.linker_plugin_lto {
867 LinkerPluginLto::Disabled => {
868 }
870 LinkerPluginLto::LinkerPluginAuto => {
871 self.push_linker_plugin_lto_args(None);
872 }
873 LinkerPluginLto::LinkerPlugin(ref path) => {
874 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
875 }
876 }
877 }
878
879 fn add_eh_frame_header(&mut self) {
883 self.link_arg("--eh-frame-hdr");
884 }
885
886 fn add_no_exec(&mut self) {
887 if self.sess.target.is_like_windows {
888 self.link_arg("--nxcompat");
889 } else if self.is_gnu {
890 self.link_args(&["-z", "noexecstack"]);
891 }
892 }
893
894 fn add_as_needed(&mut self) {
895 if self.is_gnu && !self.sess.target.is_like_windows {
896 self.link_arg("--as-needed");
897 } else if self.sess.target.is_like_solaris {
898 self.link_args(&["-z", "ignore"]);
900 }
901 }
902}
903
904struct MsvcLinker<'a> {
905 cmd: Command,
906 sess: &'a Session,
907}
908
909impl<'a> Linker for MsvcLinker<'a> {
910 fn cmd(&mut self) -> &mut Command {
911 &mut self.cmd
912 }
913
914 fn set_output_kind(
915 &mut self,
916 output_kind: LinkOutputKind,
917 _crate_type: CrateType,
918 out_filename: &Path,
919 ) {
920 match output_kind {
921 LinkOutputKind::DynamicNoPicExe
922 | LinkOutputKind::DynamicPicExe
923 | LinkOutputKind::StaticNoPicExe
924 | LinkOutputKind::StaticPicExe => {}
925 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
926 self.link_arg("/DLL");
927 let mut arg: OsString = "/IMPLIB:".into();
928 arg.push(out_filename.with_extension("dll.lib"));
929 self.link_arg(arg);
930 }
931 LinkOutputKind::WasiReactorExe => {
932 panic!("can't link as reactor on non-wasi target");
933 }
934 }
935 }
936
937 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
938 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
941 self.link_arg(path);
942 } else {
943 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
944 }
945 }
946
947 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
948 let implib_path = path.with_extension("dll.lib");
951 if implib_path.exists() {
952 self.link_or_cc_arg(implib_path);
953 }
954 }
955
956 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
957 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
960 self.link_staticlib_by_path(&path, whole_archive);
961 } else {
962 let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
963 let (prefix, suffix) = self.sess.staticlib_components(verbatim);
964 self.link_arg(format!("{opts}{prefix}{name}{suffix}"));
965 }
966 }
967
968 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
969 if !whole_archive {
970 self.link_arg(path);
971 } else {
972 let mut arg = OsString::from("/WHOLEARCHIVE:");
973 arg.push(path);
974 self.link_arg(arg);
975 }
976 }
977
978 fn gc_sections(&mut self, _keep_metadata: bool) {
979 if self.sess.opts.optimize != config::OptLevel::No {
983 self.link_arg("/OPT:REF,ICF");
984 } else {
985 self.link_arg("/OPT:REF,NOICF");
988 }
989 }
990
991 fn no_gc_sections(&mut self) {
992 self.link_arg("/OPT:NOREF,NOICF");
993 }
994
995 fn full_relro(&mut self) {
996 }
998
999 fn partial_relro(&mut self) {
1000 }
1002
1003 fn no_relro(&mut self) {
1004 }
1006
1007 fn no_crt_objects(&mut self) {
1008 }
1010
1011 fn no_default_libraries(&mut self) {
1012 self.link_arg("/NODEFAULTLIB");
1013 }
1014
1015 fn include_path(&mut self, path: &Path) {
1016 let mut arg = OsString::from("/LIBPATH:");
1017 arg.push(path);
1018 self.link_arg(&arg);
1019 }
1020
1021 fn output_filename(&mut self, path: &Path) {
1022 let mut arg = OsString::from("/OUT:");
1023 arg.push(path);
1024 self.link_arg(&arg);
1025 }
1026
1027 fn optimize(&mut self) {
1028 }
1030
1031 fn pgo_gen(&mut self) {
1032 }
1034
1035 fn control_flow_guard(&mut self) {
1036 self.link_arg("/guard:cf");
1037 }
1038
1039 fn ehcont_guard(&mut self) {
1040 if self.sess.target.pointer_width == 64 {
1041 self.link_arg("/guard:ehcont");
1042 }
1043 }
1044
1045 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1046 self.link_arg("/DEBUG");
1049
1050 self.link_arg("/PDBALTPATH:%_PDB%");
1058
1059 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
1061 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1062 for entry in natvis_dir {
1063 match entry {
1064 Ok(entry) => {
1065 let path = entry.path();
1066 if path.extension() == Some("natvis".as_ref()) {
1067 let mut arg = OsString::from("/NATVIS:");
1068 arg.push(path);
1069 self.link_arg(arg);
1070 }
1071 }
1072 Err(error) => {
1073 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1074 }
1075 }
1076 }
1077 }
1078
1079 for path in natvis_debugger_visualizers {
1081 let mut arg = OsString::from("/NATVIS:");
1082 arg.push(path);
1083 self.link_arg(arg);
1084 }
1085 }
1086
1087 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
1100 if crate_type == CrateType::Executable {
1102 let should_export_executable_symbols =
1103 self.sess.opts.unstable_opts.export_executable_symbols;
1104 if !should_export_executable_symbols {
1105 return;
1106 }
1107 }
1108
1109 let path = tmpdir.join("lib.def");
1110 let res: io::Result<()> = try {
1111 let mut f = File::create_buffered(&path)?;
1112
1113 writeln!(f, "LIBRARY")?;
1116 writeln!(f, "EXPORTS")?;
1117 for symbol in symbols {
1118 debug!(" _{symbol}");
1119 writeln!(f, " {symbol}")?;
1120 }
1121 };
1122 if let Err(error) = res {
1123 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1124 }
1125 let mut arg = OsString::from("/DEF:");
1126 arg.push(path);
1127 self.link_arg(&arg);
1128 }
1129
1130 fn subsystem(&mut self, subsystem: &str) {
1131 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1134
1135 if subsystem == "windows" {
1150 self.link_arg("/ENTRY:mainCRTStartup");
1151 }
1152 }
1153
1154 fn linker_plugin_lto(&mut self) {
1155 }
1157
1158 fn add_no_exec(&mut self) {
1159 self.link_arg("/NXCOMPAT");
1160 }
1161}
1162
1163struct EmLinker<'a> {
1164 cmd: Command,
1165 sess: &'a Session,
1166}
1167
1168impl<'a> Linker for EmLinker<'a> {
1169 fn cmd(&mut self) -> &mut Command {
1170 &mut self.cmd
1171 }
1172
1173 fn is_cc(&self) -> bool {
1174 true
1175 }
1176
1177 fn set_output_kind(
1178 &mut self,
1179 _output_kind: LinkOutputKind,
1180 _crate_type: CrateType,
1181 _out_filename: &Path,
1182 ) {
1183 }
1184
1185 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1186 self.link_or_cc_args(&["-l", name]);
1188 }
1189
1190 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1191 self.link_or_cc_arg(path);
1192 }
1193
1194 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1195 self.link_or_cc_args(&["-l", name]);
1196 }
1197
1198 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1199 self.link_or_cc_arg(path);
1200 }
1201
1202 fn full_relro(&mut self) {
1203 }
1205
1206 fn partial_relro(&mut self) {
1207 }
1209
1210 fn no_relro(&mut self) {
1211 }
1213
1214 fn gc_sections(&mut self, _keep_metadata: bool) {
1215 }
1217
1218 fn no_gc_sections(&mut self) {
1219 }
1221
1222 fn optimize(&mut self) {
1223 self.cc_arg(match self.sess.opts.optimize {
1225 OptLevel::No => "-O0",
1226 OptLevel::Less => "-O1",
1227 OptLevel::More => "-O2",
1228 OptLevel::Aggressive => "-O3",
1229 OptLevel::Size => "-Os",
1230 OptLevel::SizeMin => "-Oz",
1231 });
1232 }
1233
1234 fn pgo_gen(&mut self) {
1235 }
1237
1238 fn control_flow_guard(&mut self) {}
1239
1240 fn ehcont_guard(&mut self) {}
1241
1242 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1243 self.cc_arg(match self.sess.opts.debuginfo {
1246 DebugInfo::None => "-g0",
1247 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1248 "--profiling-funcs"
1249 }
1250 DebugInfo::Full => "-g",
1251 });
1252 }
1253
1254 fn no_crt_objects(&mut self) {}
1255
1256 fn no_default_libraries(&mut self) {
1257 self.cc_arg("-nodefaultlibs");
1258 }
1259
1260 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1261 debug!("EXPORTED SYMBOLS:");
1262
1263 self.cc_arg("-s");
1264
1265 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1266 let encoded = serde_json::to_string(
1267 &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
1268 )
1269 .unwrap();
1270 debug!("{encoded}");
1271
1272 arg.push(encoded);
1273
1274 self.cc_arg(arg);
1275 }
1276
1277 fn subsystem(&mut self, _subsystem: &str) {
1278 }
1280
1281 fn linker_plugin_lto(&mut self) {
1282 }
1284}
1285
1286struct WasmLd<'a> {
1287 cmd: Command,
1288 sess: &'a Session,
1289}
1290
1291impl<'a> WasmLd<'a> {
1292 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1293 let mut wasm_ld = WasmLd { cmd, sess };
1312 if sess.target_features.contains(&sym::atomics) {
1313 wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1314 if sess.target.os == "unknown" || sess.target.os == "none" {
1315 wasm_ld.link_args(&[
1316 "--export=__wasm_init_tls",
1317 "--export=__tls_size",
1318 "--export=__tls_align",
1319 "--export=__tls_base",
1320 ]);
1321 }
1322 }
1323 wasm_ld
1324 }
1325}
1326
1327impl<'a> Linker for WasmLd<'a> {
1328 fn cmd(&mut self) -> &mut Command {
1329 &mut self.cmd
1330 }
1331
1332 fn set_output_kind(
1333 &mut self,
1334 output_kind: LinkOutputKind,
1335 _crate_type: CrateType,
1336 _out_filename: &Path,
1337 ) {
1338 match output_kind {
1339 LinkOutputKind::DynamicNoPicExe
1340 | LinkOutputKind::DynamicPicExe
1341 | LinkOutputKind::StaticNoPicExe
1342 | LinkOutputKind::StaticPicExe => {}
1343 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1344 self.link_arg("--no-entry");
1345 }
1346 LinkOutputKind::WasiReactorExe => {
1347 self.link_args(&["--entry", "_initialize"]);
1348 }
1349 }
1350 }
1351
1352 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1353 self.link_or_cc_args(&["-l", name]);
1354 }
1355
1356 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1357 self.link_or_cc_arg(path);
1358 }
1359
1360 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1361 if !whole_archive {
1362 self.link_or_cc_args(&["-l", name]);
1363 } else {
1364 self.link_arg("--whole-archive")
1365 .link_or_cc_args(&["-l", name])
1366 .link_arg("--no-whole-archive");
1367 }
1368 }
1369
1370 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1371 if !whole_archive {
1372 self.link_or_cc_arg(path);
1373 } else {
1374 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1375 }
1376 }
1377
1378 fn full_relro(&mut self) {}
1379
1380 fn partial_relro(&mut self) {}
1381
1382 fn no_relro(&mut self) {}
1383
1384 fn gc_sections(&mut self, _keep_metadata: bool) {
1385 self.link_arg("--gc-sections");
1386 }
1387
1388 fn no_gc_sections(&mut self) {
1389 self.link_arg("--no-gc-sections");
1390 }
1391
1392 fn optimize(&mut self) {
1393 self.link_arg(match self.sess.opts.optimize {
1396 OptLevel::No => "-O0",
1397 OptLevel::Less => "-O1",
1398 OptLevel::More => "-O2",
1399 OptLevel::Aggressive => "-O3",
1400 OptLevel::Size => "-O2",
1403 OptLevel::SizeMin => "-O2",
1404 });
1405 }
1406
1407 fn pgo_gen(&mut self) {}
1408
1409 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1410 match strip {
1411 Strip::None => {}
1412 Strip::Debuginfo => {
1413 self.link_arg("--strip-debug");
1414 }
1415 Strip::Symbols => {
1416 self.link_arg("--strip-all");
1417 }
1418 }
1419 }
1420
1421 fn control_flow_guard(&mut self) {}
1422
1423 fn ehcont_guard(&mut self) {}
1424
1425 fn no_crt_objects(&mut self) {}
1426
1427 fn no_default_libraries(&mut self) {}
1428
1429 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1430 for sym in symbols {
1431 self.link_args(&["--export", sym]);
1432 }
1433
1434 if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
1439 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1440 }
1441 }
1442
1443 fn subsystem(&mut self, _subsystem: &str) {}
1444
1445 fn linker_plugin_lto(&mut self) {
1446 match self.sess.opts.cg.linker_plugin_lto {
1447 LinkerPluginLto::Disabled => {
1448 }
1450 LinkerPluginLto::LinkerPluginAuto => {
1451 self.push_linker_plugin_lto_args();
1452 }
1453 LinkerPluginLto::LinkerPlugin(_) => {
1454 self.push_linker_plugin_lto_args();
1455 }
1456 }
1457 }
1458}
1459
1460impl<'a> WasmLd<'a> {
1461 fn push_linker_plugin_lto_args(&mut self) {
1462 let opt_level = match self.sess.opts.optimize {
1463 config::OptLevel::No => "O0",
1464 config::OptLevel::Less => "O1",
1465 config::OptLevel::More => "O2",
1466 config::OptLevel::Aggressive => "O3",
1467 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1469 };
1470 self.link_arg(&format!("--lto-{opt_level}"));
1471 }
1472}
1473
1474struct L4Bender<'a> {
1476 cmd: Command,
1477 sess: &'a Session,
1478 hinted_static: bool,
1479}
1480
1481impl<'a> Linker for L4Bender<'a> {
1482 fn cmd(&mut self) -> &mut Command {
1483 &mut self.cmd
1484 }
1485
1486 fn set_output_kind(
1487 &mut self,
1488 _output_kind: LinkOutputKind,
1489 _crate_type: CrateType,
1490 _out_filename: &Path,
1491 ) {
1492 }
1493
1494 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1495 self.hint_static();
1496 if !whole_archive {
1497 self.link_arg(format!("-PC{name}"));
1498 } else {
1499 self.link_arg("--whole-archive")
1500 .link_or_cc_arg(format!("-l{name}"))
1501 .link_arg("--no-whole-archive");
1502 }
1503 }
1504
1505 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1506 self.hint_static();
1507 if !whole_archive {
1508 self.link_or_cc_arg(path);
1509 } else {
1510 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1511 }
1512 }
1513
1514 fn full_relro(&mut self) {
1515 self.link_args(&["-z", "relro", "-z", "now"]);
1516 }
1517
1518 fn partial_relro(&mut self) {
1519 self.link_args(&["-z", "relro"]);
1520 }
1521
1522 fn no_relro(&mut self) {
1523 self.link_args(&["-z", "norelro"]);
1524 }
1525
1526 fn gc_sections(&mut self, keep_metadata: bool) {
1527 if !keep_metadata {
1528 self.link_arg("--gc-sections");
1529 }
1530 }
1531
1532 fn no_gc_sections(&mut self) {
1533 self.link_arg("--no-gc-sections");
1534 }
1535
1536 fn optimize(&mut self) {
1537 if self.sess.opts.optimize == config::OptLevel::More
1540 || self.sess.opts.optimize == config::OptLevel::Aggressive
1541 {
1542 self.link_arg("-O1");
1543 }
1544 }
1545
1546 fn pgo_gen(&mut self) {}
1547
1548 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1549 match strip {
1550 Strip::None => {}
1551 Strip::Debuginfo => {
1552 self.link_arg("--strip-debug");
1553 }
1554 Strip::Symbols => {
1555 self.link_arg("--strip-all");
1556 }
1557 }
1558 }
1559
1560 fn no_default_libraries(&mut self) {
1561 self.cc_arg("-nostdlib");
1562 }
1563
1564 fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
1565 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1567 }
1568
1569 fn subsystem(&mut self, subsystem: &str) {
1570 self.link_arg(&format!("--subsystem {subsystem}"));
1571 }
1572
1573 fn reset_per_library_state(&mut self) {
1574 self.hint_static(); }
1576
1577 fn linker_plugin_lto(&mut self) {}
1578
1579 fn control_flow_guard(&mut self) {}
1580
1581 fn ehcont_guard(&mut self) {}
1582
1583 fn no_crt_objects(&mut self) {}
1584}
1585
1586impl<'a> L4Bender<'a> {
1587 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1588 L4Bender { cmd, sess, hinted_static: false }
1589 }
1590
1591 fn hint_static(&mut self) {
1592 if !self.hinted_static {
1593 self.link_or_cc_arg("-static");
1594 self.hinted_static = true;
1595 }
1596 }
1597}
1598
1599struct AixLinker<'a> {
1601 cmd: Command,
1602 sess: &'a Session,
1603 hinted_static: Option<bool>,
1604}
1605
1606impl<'a> AixLinker<'a> {
1607 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1608 AixLinker { cmd, sess, hinted_static: None }
1609 }
1610
1611 fn hint_static(&mut self) {
1612 if self.hinted_static != Some(true) {
1613 self.link_arg("-bstatic");
1614 self.hinted_static = Some(true);
1615 }
1616 }
1617
1618 fn hint_dynamic(&mut self) {
1619 if self.hinted_static != Some(false) {
1620 self.link_arg("-bdynamic");
1621 self.hinted_static = Some(false);
1622 }
1623 }
1624
1625 fn build_dylib(&mut self, _out_filename: &Path) {
1626 self.link_args(&["-bM:SRE", "-bnoentry"]);
1627 self.link_arg("-bexpfull");
1630 }
1631}
1632
1633impl<'a> Linker for AixLinker<'a> {
1634 fn cmd(&mut self) -> &mut Command {
1635 &mut self.cmd
1636 }
1637
1638 fn set_output_kind(
1639 &mut self,
1640 output_kind: LinkOutputKind,
1641 _crate_type: CrateType,
1642 out_filename: &Path,
1643 ) {
1644 match output_kind {
1645 LinkOutputKind::DynamicDylib => {
1646 self.hint_dynamic();
1647 self.build_dylib(out_filename);
1648 }
1649 LinkOutputKind::StaticDylib => {
1650 self.hint_static();
1651 self.build_dylib(out_filename);
1652 }
1653 _ => {}
1654 }
1655 }
1656
1657 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1658 self.hint_dynamic();
1659 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1660 }
1661
1662 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1663 self.hint_dynamic();
1664 self.link_or_cc_arg(path);
1665 }
1666
1667 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1668 self.hint_static();
1669 if !whole_archive {
1670 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1671 } else {
1672 let mut arg = OsString::from("-bkeepfile:");
1673 arg.push(find_native_static_library(name, verbatim, self.sess));
1674 self.link_or_cc_arg(arg);
1675 }
1676 }
1677
1678 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1679 self.hint_static();
1680 if !whole_archive {
1681 self.link_or_cc_arg(path);
1682 } else {
1683 let mut arg = OsString::from("-bkeepfile:");
1684 arg.push(path);
1685 self.link_arg(arg);
1686 }
1687 }
1688
1689 fn full_relro(&mut self) {}
1690
1691 fn partial_relro(&mut self) {}
1692
1693 fn no_relro(&mut self) {}
1694
1695 fn gc_sections(&mut self, _keep_metadata: bool) {
1696 self.link_arg("-bgc");
1697 }
1698
1699 fn no_gc_sections(&mut self) {
1700 self.link_arg("-bnogc");
1701 }
1702
1703 fn optimize(&mut self) {}
1704
1705 fn pgo_gen(&mut self) {
1706 self.link_arg("-bdbg:namedsects:ss");
1707 self.link_arg("-u");
1708 self.link_arg("__llvm_profile_runtime");
1709 }
1710
1711 fn control_flow_guard(&mut self) {}
1712
1713 fn ehcont_guard(&mut self) {}
1714
1715 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1716
1717 fn no_crt_objects(&mut self) {}
1718
1719 fn no_default_libraries(&mut self) {}
1720
1721 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1722 let path = tmpdir.join("list.exp");
1723 let res: io::Result<()> = try {
1724 let mut f = File::create_buffered(&path)?;
1725 for symbol in symbols {
1727 debug!(" _{symbol}");
1728 writeln!(f, " {symbol}")?;
1729 }
1730 };
1731 if let Err(e) = res {
1732 self.sess.dcx().fatal(format!("failed to write export file: {e}"));
1733 }
1734 self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
1735 }
1736
1737 fn subsystem(&mut self, _subsystem: &str) {}
1738
1739 fn reset_per_library_state(&mut self) {
1740 self.hint_dynamic();
1741 }
1742
1743 fn linker_plugin_lto(&mut self) {}
1744
1745 fn add_eh_frame_header(&mut self) {}
1746
1747 fn add_no_exec(&mut self) {}
1748
1749 fn add_as_needed(&mut self) {}
1750}
1751
1752fn for_each_exported_symbols_include_dep<'tcx>(
1753 tcx: TyCtxt<'tcx>,
1754 crate_type: CrateType,
1755 mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
1756) {
1757 let formats = tcx.dependency_formats(());
1758 let deps = &formats[&crate_type];
1759
1760 for (cnum, dep_format) in deps.iter_enumerated() {
1761 if *dep_format == Linkage::Static {
1763 for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
1764 callback(symbol, info, cnum);
1765 }
1766 }
1767 }
1768}
1769
1770pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1771 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1772 return exports.iter().map(ToString::to_string).collect();
1773 }
1774
1775 if let CrateType::ProcMacro = crate_type {
1776 exported_symbols_for_proc_macro_crate(tcx)
1777 } else {
1778 exported_symbols_for_non_proc_macro(tcx, crate_type)
1779 }
1780}
1781
1782fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1783 let mut symbols = Vec::new();
1784 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1785 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1786 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1790 symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1791 tcx, symbol, cnum,
1792 ));
1793 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1794 }
1795 });
1796
1797 symbols
1798}
1799
1800fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
1801 if !tcx.sess.opts.output_types.should_codegen() {
1803 return Vec::new();
1804 }
1805
1806 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1807 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1808 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1809
1810 vec![proc_macro_decls_name, metadata_symbol_name]
1811}
1812
1813pub(crate) fn linked_symbols(
1814 tcx: TyCtxt<'_>,
1815 crate_type: CrateType,
1816) -> Vec<(String, SymbolExportKind)> {
1817 match crate_type {
1818 CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
1819 CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
1820 return Vec::new();
1821 }
1822 }
1823
1824 let mut symbols = Vec::new();
1825
1826 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1827 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1828 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
1829 || info.used
1830 {
1831 symbols.push((
1832 symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1833 info.kind,
1834 ));
1835 }
1836 });
1837
1838 symbols
1839}
1840
1841struct PtxLinker<'a> {
1844 cmd: Command,
1845 sess: &'a Session,
1846}
1847
1848impl<'a> Linker for PtxLinker<'a> {
1849 fn cmd(&mut self) -> &mut Command {
1850 &mut self.cmd
1851 }
1852
1853 fn set_output_kind(
1854 &mut self,
1855 _output_kind: LinkOutputKind,
1856 _crate_type: CrateType,
1857 _out_filename: &Path,
1858 ) {
1859 }
1860
1861 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1862 panic!("staticlibs not supported")
1863 }
1864
1865 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1866 self.link_arg("--rlib").link_arg(path);
1867 }
1868
1869 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1870 self.link_arg("--debug");
1871 }
1872
1873 fn add_object(&mut self, path: &Path) {
1874 self.link_arg("--bitcode").link_arg(path);
1875 }
1876
1877 fn optimize(&mut self) {
1878 match self.sess.lto() {
1879 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1880 self.link_arg("-Olto");
1881 }
1882
1883 Lto::No => {}
1884 }
1885 }
1886
1887 fn full_relro(&mut self) {}
1888
1889 fn partial_relro(&mut self) {}
1890
1891 fn no_relro(&mut self) {}
1892
1893 fn gc_sections(&mut self, _keep_metadata: bool) {}
1894
1895 fn no_gc_sections(&mut self) {}
1896
1897 fn pgo_gen(&mut self) {}
1898
1899 fn no_crt_objects(&mut self) {}
1900
1901 fn no_default_libraries(&mut self) {}
1902
1903 fn control_flow_guard(&mut self) {}
1904
1905 fn ehcont_guard(&mut self) {}
1906
1907 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1908
1909 fn subsystem(&mut self, _subsystem: &str) {}
1910
1911 fn linker_plugin_lto(&mut self) {}
1912}
1913
1914struct LlbcLinker<'a> {
1916 cmd: Command,
1917 sess: &'a Session,
1918}
1919
1920impl<'a> Linker for LlbcLinker<'a> {
1921 fn cmd(&mut self) -> &mut Command {
1922 &mut self.cmd
1923 }
1924
1925 fn set_output_kind(
1926 &mut self,
1927 _output_kind: LinkOutputKind,
1928 _crate_type: CrateType,
1929 _out_filename: &Path,
1930 ) {
1931 }
1932
1933 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1934 panic!("staticlibs not supported")
1935 }
1936
1937 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1938 self.link_or_cc_arg(path);
1939 }
1940
1941 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1942 self.link_arg("--debug");
1943 }
1944
1945 fn optimize(&mut self) {
1946 self.link_arg(match self.sess.opts.optimize {
1947 OptLevel::No => "-O0",
1948 OptLevel::Less => "-O1",
1949 OptLevel::More => "-O2",
1950 OptLevel::Aggressive => "-O3",
1951 OptLevel::Size => "-Os",
1952 OptLevel::SizeMin => "-Oz",
1953 });
1954 }
1955
1956 fn full_relro(&mut self) {}
1957
1958 fn partial_relro(&mut self) {}
1959
1960 fn no_relro(&mut self) {}
1961
1962 fn gc_sections(&mut self, _keep_metadata: bool) {}
1963
1964 fn no_gc_sections(&mut self) {}
1965
1966 fn pgo_gen(&mut self) {}
1967
1968 fn no_crt_objects(&mut self) {}
1969
1970 fn no_default_libraries(&mut self) {}
1971
1972 fn control_flow_guard(&mut self) {}
1973
1974 fn ehcont_guard(&mut self) {}
1975
1976 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1977 match _crate_type {
1978 CrateType::Cdylib => {
1979 for sym in symbols {
1980 self.link_args(&["--export-symbol", sym]);
1981 }
1982 }
1983 _ => (),
1984 }
1985 }
1986
1987 fn subsystem(&mut self, _subsystem: &str) {}
1988
1989 fn linker_plugin_lto(&mut self) {}
1990}
1991
1992struct BpfLinker<'a> {
1993 cmd: Command,
1994 sess: &'a Session,
1995}
1996
1997impl<'a> Linker for BpfLinker<'a> {
1998 fn cmd(&mut self) -> &mut Command {
1999 &mut self.cmd
2000 }
2001
2002 fn set_output_kind(
2003 &mut self,
2004 _output_kind: LinkOutputKind,
2005 _crate_type: CrateType,
2006 _out_filename: &Path,
2007 ) {
2008 }
2009
2010 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2011 panic!("staticlibs not supported")
2012 }
2013
2014 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2015 self.link_or_cc_arg(path);
2016 }
2017
2018 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2019 self.link_arg("--debug");
2020 }
2021
2022 fn optimize(&mut self) {
2023 self.link_arg(match self.sess.opts.optimize {
2024 OptLevel::No => "-O0",
2025 OptLevel::Less => "-O1",
2026 OptLevel::More => "-O2",
2027 OptLevel::Aggressive => "-O3",
2028 OptLevel::Size => "-Os",
2029 OptLevel::SizeMin => "-Oz",
2030 });
2031 }
2032
2033 fn full_relro(&mut self) {}
2034
2035 fn partial_relro(&mut self) {}
2036
2037 fn no_relro(&mut self) {}
2038
2039 fn gc_sections(&mut self, _keep_metadata: bool) {}
2040
2041 fn no_gc_sections(&mut self) {}
2042
2043 fn pgo_gen(&mut self) {}
2044
2045 fn no_crt_objects(&mut self) {}
2046
2047 fn no_default_libraries(&mut self) {}
2048
2049 fn control_flow_guard(&mut self) {}
2050
2051 fn ehcont_guard(&mut self) {}
2052
2053 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2054 let path = tmpdir.join("symbols");
2055 let res: io::Result<()> = try {
2056 let mut f = File::create_buffered(&path)?;
2057 for sym in symbols {
2058 writeln!(f, "{sym}")?;
2059 }
2060 };
2061 if let Err(error) = res {
2062 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2063 } else {
2064 self.link_arg("--export-symbols").link_arg(&path);
2065 }
2066 }
2067
2068 fn subsystem(&mut self, _subsystem: &str) {}
2069
2070 fn linker_plugin_lto(&mut self) {}
2071}