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_darwin && !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_darwin {
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_darwin {
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_darwin {
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_darwin {
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_darwin {
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_darwin {
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_darwin {
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_darwin {
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}\"")?;
822 }
823 };
824 if let Err(error) = res {
825 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
826 }
827 } else {
828 let res: io::Result<()> = try {
830 let mut f = File::create_buffered(&path)?;
831 writeln!(f, "{{")?;
832 if !symbols.is_empty() {
833 writeln!(f, " global:")?;
834 for sym in symbols {
835 debug!(" {sym};");
836 writeln!(f, " {sym};")?;
837 }
838 }
839 writeln!(f, "\n local:\n *;\n}};")?;
840 };
841 if let Err(error) = res {
842 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
843 }
844 }
845
846 if self.sess.target.is_like_darwin {
847 self.link_arg("-exported_symbols_list").link_arg(path);
848 } else if self.sess.target.is_like_solaris {
849 self.link_arg("-M").link_arg(path);
850 } else if is_windows {
851 self.link_arg(path);
852 } else {
853 let mut arg = OsString::from("--version-script=");
854 arg.push(path);
855 self.link_arg(arg).link_arg("--no-undefined-version");
856 }
857 }
858
859 fn subsystem(&mut self, subsystem: &str) {
860 self.link_args(&["--subsystem", subsystem]);
861 }
862
863 fn reset_per_library_state(&mut self) {
864 self.hint_dynamic(); }
866
867 fn linker_plugin_lto(&mut self) {
868 match self.sess.opts.cg.linker_plugin_lto {
869 LinkerPluginLto::Disabled => {
870 }
872 LinkerPluginLto::LinkerPluginAuto => {
873 self.push_linker_plugin_lto_args(None);
874 }
875 LinkerPluginLto::LinkerPlugin(ref path) => {
876 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
877 }
878 }
879 }
880
881 fn add_eh_frame_header(&mut self) {
885 self.link_arg("--eh-frame-hdr");
886 }
887
888 fn add_no_exec(&mut self) {
889 if self.sess.target.is_like_windows {
890 self.link_arg("--nxcompat");
891 } else if self.is_gnu {
892 self.link_args(&["-z", "noexecstack"]);
893 }
894 }
895
896 fn add_as_needed(&mut self) {
897 if self.is_gnu && !self.sess.target.is_like_windows {
898 self.link_arg("--as-needed");
899 } else if self.sess.target.is_like_solaris {
900 self.link_args(&["-z", "ignore"]);
902 }
903 }
904}
905
906struct MsvcLinker<'a> {
907 cmd: Command,
908 sess: &'a Session,
909}
910
911impl<'a> Linker for MsvcLinker<'a> {
912 fn cmd(&mut self) -> &mut Command {
913 &mut self.cmd
914 }
915
916 fn set_output_kind(
917 &mut self,
918 output_kind: LinkOutputKind,
919 _crate_type: CrateType,
920 out_filename: &Path,
921 ) {
922 match output_kind {
923 LinkOutputKind::DynamicNoPicExe
924 | LinkOutputKind::DynamicPicExe
925 | LinkOutputKind::StaticNoPicExe
926 | LinkOutputKind::StaticPicExe => {}
927 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
928 self.link_arg("/DLL");
929 let mut arg: OsString = "/IMPLIB:".into();
930 arg.push(out_filename.with_extension("dll.lib"));
931 self.link_arg(arg);
932 }
933 LinkOutputKind::WasiReactorExe => {
934 panic!("can't link as reactor on non-wasi target");
935 }
936 }
937 }
938
939 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
940 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
943 self.link_arg(path);
944 } else {
945 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
946 }
947 }
948
949 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
950 let implib_path = path.with_extension("dll.lib");
953 if implib_path.exists() {
954 self.link_or_cc_arg(implib_path);
955 }
956 }
957
958 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
959 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
962 self.link_staticlib_by_path(&path, whole_archive);
963 } else {
964 let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
965 let (prefix, suffix) = self.sess.staticlib_components(verbatim);
966 self.link_arg(format!("{opts}{prefix}{name}{suffix}"));
967 }
968 }
969
970 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
971 if !whole_archive {
972 self.link_arg(path);
973 } else {
974 let mut arg = OsString::from("/WHOLEARCHIVE:");
975 arg.push(path);
976 self.link_arg(arg);
977 }
978 }
979
980 fn gc_sections(&mut self, _keep_metadata: bool) {
981 if self.sess.opts.optimize != config::OptLevel::No {
985 self.link_arg("/OPT:REF,ICF");
986 } else {
987 self.link_arg("/OPT:REF,NOICF");
990 }
991 }
992
993 fn no_gc_sections(&mut self) {
994 self.link_arg("/OPT:NOREF,NOICF");
995 }
996
997 fn full_relro(&mut self) {
998 }
1000
1001 fn partial_relro(&mut self) {
1002 }
1004
1005 fn no_relro(&mut self) {
1006 }
1008
1009 fn no_crt_objects(&mut self) {
1010 }
1012
1013 fn no_default_libraries(&mut self) {
1014 self.link_arg("/NODEFAULTLIB");
1015 }
1016
1017 fn include_path(&mut self, path: &Path) {
1018 let mut arg = OsString::from("/LIBPATH:");
1019 arg.push(path);
1020 self.link_arg(&arg);
1021 }
1022
1023 fn output_filename(&mut self, path: &Path) {
1024 let mut arg = OsString::from("/OUT:");
1025 arg.push(path);
1026 self.link_arg(&arg);
1027 }
1028
1029 fn optimize(&mut self) {
1030 }
1032
1033 fn pgo_gen(&mut self) {
1034 }
1036
1037 fn control_flow_guard(&mut self) {
1038 self.link_arg("/guard:cf");
1039 }
1040
1041 fn ehcont_guard(&mut self) {
1042 if self.sess.target.pointer_width == 64 {
1043 self.link_arg("/guard:ehcont");
1044 }
1045 }
1046
1047 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1048 self.link_arg("/DEBUG");
1051
1052 self.link_arg("/PDBALTPATH:%_PDB%");
1060
1061 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
1063 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1064 for entry in natvis_dir {
1065 match entry {
1066 Ok(entry) => {
1067 let path = entry.path();
1068 if path.extension() == Some("natvis".as_ref()) {
1069 let mut arg = OsString::from("/NATVIS:");
1070 arg.push(path);
1071 self.link_arg(arg);
1072 }
1073 }
1074 Err(error) => {
1075 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1076 }
1077 }
1078 }
1079 }
1080
1081 for path in natvis_debugger_visualizers {
1083 let mut arg = OsString::from("/NATVIS:");
1084 arg.push(path);
1085 self.link_arg(arg);
1086 }
1087 }
1088
1089 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
1102 if crate_type == CrateType::Executable {
1104 let should_export_executable_symbols =
1105 self.sess.opts.unstable_opts.export_executable_symbols;
1106 if !should_export_executable_symbols {
1107 return;
1108 }
1109 }
1110
1111 let path = tmpdir.join("lib.def");
1112 let res: io::Result<()> = try {
1113 let mut f = File::create_buffered(&path)?;
1114
1115 writeln!(f, "LIBRARY")?;
1118 writeln!(f, "EXPORTS")?;
1119 for symbol in symbols {
1120 debug!(" _{symbol}");
1121 writeln!(f, " {symbol}")?;
1122 }
1123 };
1124 if let Err(error) = res {
1125 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1126 }
1127 let mut arg = OsString::from("/DEF:");
1128 arg.push(path);
1129 self.link_arg(&arg);
1130 }
1131
1132 fn subsystem(&mut self, subsystem: &str) {
1133 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1136
1137 if subsystem == "windows" {
1152 self.link_arg("/ENTRY:mainCRTStartup");
1153 }
1154 }
1155
1156 fn linker_plugin_lto(&mut self) {
1157 }
1159
1160 fn add_no_exec(&mut self) {
1161 self.link_arg("/NXCOMPAT");
1162 }
1163}
1164
1165struct EmLinker<'a> {
1166 cmd: Command,
1167 sess: &'a Session,
1168}
1169
1170impl<'a> Linker for EmLinker<'a> {
1171 fn cmd(&mut self) -> &mut Command {
1172 &mut self.cmd
1173 }
1174
1175 fn is_cc(&self) -> bool {
1176 true
1177 }
1178
1179 fn set_output_kind(
1180 &mut self,
1181 _output_kind: LinkOutputKind,
1182 _crate_type: CrateType,
1183 _out_filename: &Path,
1184 ) {
1185 }
1186
1187 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1188 self.link_or_cc_args(&["-l", name]);
1190 }
1191
1192 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1193 self.link_or_cc_arg(path);
1194 }
1195
1196 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1197 self.link_or_cc_args(&["-l", name]);
1198 }
1199
1200 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1201 self.link_or_cc_arg(path);
1202 }
1203
1204 fn full_relro(&mut self) {
1205 }
1207
1208 fn partial_relro(&mut self) {
1209 }
1211
1212 fn no_relro(&mut self) {
1213 }
1215
1216 fn gc_sections(&mut self, _keep_metadata: bool) {
1217 }
1219
1220 fn no_gc_sections(&mut self) {
1221 }
1223
1224 fn optimize(&mut self) {
1225 self.cc_arg(match self.sess.opts.optimize {
1227 OptLevel::No => "-O0",
1228 OptLevel::Less => "-O1",
1229 OptLevel::More => "-O2",
1230 OptLevel::Aggressive => "-O3",
1231 OptLevel::Size => "-Os",
1232 OptLevel::SizeMin => "-Oz",
1233 });
1234 }
1235
1236 fn pgo_gen(&mut self) {
1237 }
1239
1240 fn control_flow_guard(&mut self) {}
1241
1242 fn ehcont_guard(&mut self) {}
1243
1244 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1245 self.cc_arg(match self.sess.opts.debuginfo {
1248 DebugInfo::None => "-g0",
1249 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1250 "--profiling-funcs"
1251 }
1252 DebugInfo::Full => "-g",
1253 });
1254 }
1255
1256 fn no_crt_objects(&mut self) {}
1257
1258 fn no_default_libraries(&mut self) {
1259 self.cc_arg("-nodefaultlibs");
1260 }
1261
1262 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1263 debug!("EXPORTED SYMBOLS:");
1264
1265 self.cc_arg("-s");
1266
1267 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1268 let encoded = serde_json::to_string(
1269 &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
1270 )
1271 .unwrap();
1272 debug!("{encoded}");
1273
1274 arg.push(encoded);
1275
1276 self.cc_arg(arg);
1277 }
1278
1279 fn subsystem(&mut self, _subsystem: &str) {
1280 }
1282
1283 fn linker_plugin_lto(&mut self) {
1284 }
1286}
1287
1288struct WasmLd<'a> {
1289 cmd: Command,
1290 sess: &'a Session,
1291}
1292
1293impl<'a> WasmLd<'a> {
1294 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1295 let mut wasm_ld = WasmLd { cmd, sess };
1314 if sess.target_features.contains(&sym::atomics) {
1315 wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1316 if sess.target.os == "unknown" || sess.target.os == "none" {
1317 wasm_ld.link_args(&[
1318 "--export=__wasm_init_tls",
1319 "--export=__tls_size",
1320 "--export=__tls_align",
1321 "--export=__tls_base",
1322 ]);
1323 }
1324 }
1325 wasm_ld
1326 }
1327}
1328
1329impl<'a> Linker for WasmLd<'a> {
1330 fn cmd(&mut self) -> &mut Command {
1331 &mut self.cmd
1332 }
1333
1334 fn set_output_kind(
1335 &mut self,
1336 output_kind: LinkOutputKind,
1337 _crate_type: CrateType,
1338 _out_filename: &Path,
1339 ) {
1340 match output_kind {
1341 LinkOutputKind::DynamicNoPicExe
1342 | LinkOutputKind::DynamicPicExe
1343 | LinkOutputKind::StaticNoPicExe
1344 | LinkOutputKind::StaticPicExe => {}
1345 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1346 self.link_arg("--no-entry");
1347 }
1348 LinkOutputKind::WasiReactorExe => {
1349 self.link_args(&["--entry", "_initialize"]);
1350 }
1351 }
1352 }
1353
1354 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1355 self.link_or_cc_args(&["-l", name]);
1356 }
1357
1358 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1359 self.link_or_cc_arg(path);
1360 }
1361
1362 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1363 if !whole_archive {
1364 self.link_or_cc_args(&["-l", name]);
1365 } else {
1366 self.link_arg("--whole-archive")
1367 .link_or_cc_args(&["-l", name])
1368 .link_arg("--no-whole-archive");
1369 }
1370 }
1371
1372 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1373 if !whole_archive {
1374 self.link_or_cc_arg(path);
1375 } else {
1376 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1377 }
1378 }
1379
1380 fn full_relro(&mut self) {}
1381
1382 fn partial_relro(&mut self) {}
1383
1384 fn no_relro(&mut self) {}
1385
1386 fn gc_sections(&mut self, _keep_metadata: bool) {
1387 self.link_arg("--gc-sections");
1388 }
1389
1390 fn no_gc_sections(&mut self) {
1391 self.link_arg("--no-gc-sections");
1392 }
1393
1394 fn optimize(&mut self) {
1395 self.link_arg(match self.sess.opts.optimize {
1398 OptLevel::No => "-O0",
1399 OptLevel::Less => "-O1",
1400 OptLevel::More => "-O2",
1401 OptLevel::Aggressive => "-O3",
1402 OptLevel::Size => "-O2",
1405 OptLevel::SizeMin => "-O2",
1406 });
1407 }
1408
1409 fn pgo_gen(&mut self) {}
1410
1411 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1412 match strip {
1413 Strip::None => {}
1414 Strip::Debuginfo => {
1415 self.link_arg("--strip-debug");
1416 }
1417 Strip::Symbols => {
1418 self.link_arg("--strip-all");
1419 }
1420 }
1421 }
1422
1423 fn control_flow_guard(&mut self) {}
1424
1425 fn ehcont_guard(&mut self) {}
1426
1427 fn no_crt_objects(&mut self) {}
1428
1429 fn no_default_libraries(&mut self) {}
1430
1431 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1432 for sym in symbols {
1433 self.link_args(&["--export", sym]);
1434 }
1435
1436 if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
1441 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1442 }
1443 }
1444
1445 fn subsystem(&mut self, _subsystem: &str) {}
1446
1447 fn linker_plugin_lto(&mut self) {
1448 match self.sess.opts.cg.linker_plugin_lto {
1449 LinkerPluginLto::Disabled => {
1450 }
1452 LinkerPluginLto::LinkerPluginAuto => {
1453 self.push_linker_plugin_lto_args();
1454 }
1455 LinkerPluginLto::LinkerPlugin(_) => {
1456 self.push_linker_plugin_lto_args();
1457 }
1458 }
1459 }
1460}
1461
1462impl<'a> WasmLd<'a> {
1463 fn push_linker_plugin_lto_args(&mut self) {
1464 let opt_level = match self.sess.opts.optimize {
1465 config::OptLevel::No => "O0",
1466 config::OptLevel::Less => "O1",
1467 config::OptLevel::More => "O2",
1468 config::OptLevel::Aggressive => "O3",
1469 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1471 };
1472 self.link_arg(&format!("--lto-{opt_level}"));
1473 }
1474}
1475
1476struct L4Bender<'a> {
1478 cmd: Command,
1479 sess: &'a Session,
1480 hinted_static: bool,
1481}
1482
1483impl<'a> Linker for L4Bender<'a> {
1484 fn cmd(&mut self) -> &mut Command {
1485 &mut self.cmd
1486 }
1487
1488 fn set_output_kind(
1489 &mut self,
1490 _output_kind: LinkOutputKind,
1491 _crate_type: CrateType,
1492 _out_filename: &Path,
1493 ) {
1494 }
1495
1496 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1497 self.hint_static();
1498 if !whole_archive {
1499 self.link_arg(format!("-PC{name}"));
1500 } else {
1501 self.link_arg("--whole-archive")
1502 .link_or_cc_arg(format!("-l{name}"))
1503 .link_arg("--no-whole-archive");
1504 }
1505 }
1506
1507 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1508 self.hint_static();
1509 if !whole_archive {
1510 self.link_or_cc_arg(path);
1511 } else {
1512 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1513 }
1514 }
1515
1516 fn full_relro(&mut self) {
1517 self.link_args(&["-z", "relro", "-z", "now"]);
1518 }
1519
1520 fn partial_relro(&mut self) {
1521 self.link_args(&["-z", "relro"]);
1522 }
1523
1524 fn no_relro(&mut self) {
1525 self.link_args(&["-z", "norelro"]);
1526 }
1527
1528 fn gc_sections(&mut self, keep_metadata: bool) {
1529 if !keep_metadata {
1530 self.link_arg("--gc-sections");
1531 }
1532 }
1533
1534 fn no_gc_sections(&mut self) {
1535 self.link_arg("--no-gc-sections");
1536 }
1537
1538 fn optimize(&mut self) {
1539 if self.sess.opts.optimize == config::OptLevel::More
1542 || self.sess.opts.optimize == config::OptLevel::Aggressive
1543 {
1544 self.link_arg("-O1");
1545 }
1546 }
1547
1548 fn pgo_gen(&mut self) {}
1549
1550 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1551 match strip {
1552 Strip::None => {}
1553 Strip::Debuginfo => {
1554 self.link_arg("--strip-debug");
1555 }
1556 Strip::Symbols => {
1557 self.link_arg("--strip-all");
1558 }
1559 }
1560 }
1561
1562 fn no_default_libraries(&mut self) {
1563 self.cc_arg("-nostdlib");
1564 }
1565
1566 fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
1567 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1569 }
1570
1571 fn subsystem(&mut self, subsystem: &str) {
1572 self.link_arg(&format!("--subsystem {subsystem}"));
1573 }
1574
1575 fn reset_per_library_state(&mut self) {
1576 self.hint_static(); }
1578
1579 fn linker_plugin_lto(&mut self) {}
1580
1581 fn control_flow_guard(&mut self) {}
1582
1583 fn ehcont_guard(&mut self) {}
1584
1585 fn no_crt_objects(&mut self) {}
1586}
1587
1588impl<'a> L4Bender<'a> {
1589 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1590 L4Bender { cmd, sess, hinted_static: false }
1591 }
1592
1593 fn hint_static(&mut self) {
1594 if !self.hinted_static {
1595 self.link_or_cc_arg("-static");
1596 self.hinted_static = true;
1597 }
1598 }
1599}
1600
1601struct AixLinker<'a> {
1603 cmd: Command,
1604 sess: &'a Session,
1605 hinted_static: Option<bool>,
1606}
1607
1608impl<'a> AixLinker<'a> {
1609 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1610 AixLinker { cmd, sess, hinted_static: None }
1611 }
1612
1613 fn hint_static(&mut self) {
1614 if self.hinted_static != Some(true) {
1615 self.link_arg("-bstatic");
1616 self.hinted_static = Some(true);
1617 }
1618 }
1619
1620 fn hint_dynamic(&mut self) {
1621 if self.hinted_static != Some(false) {
1622 self.link_arg("-bdynamic");
1623 self.hinted_static = Some(false);
1624 }
1625 }
1626
1627 fn build_dylib(&mut self, _out_filename: &Path) {
1628 self.link_args(&["-bM:SRE", "-bnoentry"]);
1629 self.link_arg("-bexpfull");
1632 }
1633}
1634
1635impl<'a> Linker for AixLinker<'a> {
1636 fn cmd(&mut self) -> &mut Command {
1637 &mut self.cmd
1638 }
1639
1640 fn set_output_kind(
1641 &mut self,
1642 output_kind: LinkOutputKind,
1643 _crate_type: CrateType,
1644 out_filename: &Path,
1645 ) {
1646 match output_kind {
1647 LinkOutputKind::DynamicDylib => {
1648 self.hint_dynamic();
1649 self.build_dylib(out_filename);
1650 }
1651 LinkOutputKind::StaticDylib => {
1652 self.hint_static();
1653 self.build_dylib(out_filename);
1654 }
1655 _ => {}
1656 }
1657 }
1658
1659 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1660 self.hint_dynamic();
1661 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1662 }
1663
1664 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1665 self.hint_dynamic();
1666 self.link_or_cc_arg(path);
1667 }
1668
1669 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1670 self.hint_static();
1671 if !whole_archive {
1672 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1673 } else {
1674 let mut arg = OsString::from("-bkeepfile:");
1675 arg.push(find_native_static_library(name, verbatim, self.sess));
1676 self.link_or_cc_arg(arg);
1677 }
1678 }
1679
1680 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1681 self.hint_static();
1682 if !whole_archive {
1683 self.link_or_cc_arg(path);
1684 } else {
1685 let mut arg = OsString::from("-bkeepfile:");
1686 arg.push(path);
1687 self.link_arg(arg);
1688 }
1689 }
1690
1691 fn full_relro(&mut self) {}
1692
1693 fn partial_relro(&mut self) {}
1694
1695 fn no_relro(&mut self) {}
1696
1697 fn gc_sections(&mut self, _keep_metadata: bool) {
1698 self.link_arg("-bgc");
1699 }
1700
1701 fn no_gc_sections(&mut self) {
1702 self.link_arg("-bnogc");
1703 }
1704
1705 fn optimize(&mut self) {}
1706
1707 fn pgo_gen(&mut self) {
1708 self.link_arg("-bdbg:namedsects:ss");
1709 self.link_arg("-u");
1710 self.link_arg("__llvm_profile_runtime");
1711 }
1712
1713 fn control_flow_guard(&mut self) {}
1714
1715 fn ehcont_guard(&mut self) {}
1716
1717 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1718
1719 fn no_crt_objects(&mut self) {}
1720
1721 fn no_default_libraries(&mut self) {}
1722
1723 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1724 let path = tmpdir.join("list.exp");
1725 let res: io::Result<()> = try {
1726 let mut f = File::create_buffered(&path)?;
1727 for symbol in symbols {
1729 debug!(" _{symbol}");
1730 writeln!(f, " {symbol}")?;
1731 }
1732 };
1733 if let Err(e) = res {
1734 self.sess.dcx().fatal(format!("failed to write export file: {e}"));
1735 }
1736 self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
1737 }
1738
1739 fn subsystem(&mut self, _subsystem: &str) {}
1740
1741 fn reset_per_library_state(&mut self) {
1742 self.hint_dynamic();
1743 }
1744
1745 fn linker_plugin_lto(&mut self) {}
1746
1747 fn add_eh_frame_header(&mut self) {}
1748
1749 fn add_no_exec(&mut self) {}
1750
1751 fn add_as_needed(&mut self) {}
1752}
1753
1754fn for_each_exported_symbols_include_dep<'tcx>(
1755 tcx: TyCtxt<'tcx>,
1756 crate_type: CrateType,
1757 mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
1758) {
1759 let formats = tcx.dependency_formats(());
1760 let deps = &formats[&crate_type];
1761
1762 for (cnum, dep_format) in deps.iter_enumerated() {
1763 if *dep_format == Linkage::Static {
1765 for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
1766 callback(symbol, info, cnum);
1767 }
1768 }
1769 }
1770}
1771
1772pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1773 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1774 return exports.iter().map(ToString::to_string).collect();
1775 }
1776
1777 if let CrateType::ProcMacro = crate_type {
1778 exported_symbols_for_proc_macro_crate(tcx)
1779 } else {
1780 exported_symbols_for_non_proc_macro(tcx, crate_type)
1781 }
1782}
1783
1784fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1785 let mut symbols = Vec::new();
1786 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1787 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1788 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1792 symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1793 tcx, symbol, cnum,
1794 ));
1795 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1796 }
1797 });
1798
1799 symbols
1800}
1801
1802fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
1803 if !tcx.sess.opts.output_types.should_codegen() {
1805 return Vec::new();
1806 }
1807
1808 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1809 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1810 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1811
1812 vec![proc_macro_decls_name, metadata_symbol_name]
1813}
1814
1815pub(crate) fn linked_symbols(
1816 tcx: TyCtxt<'_>,
1817 crate_type: CrateType,
1818) -> Vec<(String, SymbolExportKind)> {
1819 match crate_type {
1820 CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
1821 CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
1822 return Vec::new();
1823 }
1824 }
1825
1826 let mut symbols = Vec::new();
1827
1828 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1829 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1830 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
1831 || info.used
1832 {
1833 symbols.push((
1834 symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1835 info.kind,
1836 ));
1837 }
1838 });
1839
1840 symbols
1841}
1842
1843struct PtxLinker<'a> {
1846 cmd: Command,
1847 sess: &'a Session,
1848}
1849
1850impl<'a> Linker for PtxLinker<'a> {
1851 fn cmd(&mut self) -> &mut Command {
1852 &mut self.cmd
1853 }
1854
1855 fn set_output_kind(
1856 &mut self,
1857 _output_kind: LinkOutputKind,
1858 _crate_type: CrateType,
1859 _out_filename: &Path,
1860 ) {
1861 }
1862
1863 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1864 panic!("staticlibs not supported")
1865 }
1866
1867 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1868 self.link_arg("--rlib").link_arg(path);
1869 }
1870
1871 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1872 self.link_arg("--debug");
1873 }
1874
1875 fn add_object(&mut self, path: &Path) {
1876 self.link_arg("--bitcode").link_arg(path);
1877 }
1878
1879 fn optimize(&mut self) {
1880 match self.sess.lto() {
1881 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1882 self.link_arg("-Olto");
1883 }
1884
1885 Lto::No => {}
1886 }
1887 }
1888
1889 fn full_relro(&mut self) {}
1890
1891 fn partial_relro(&mut self) {}
1892
1893 fn no_relro(&mut self) {}
1894
1895 fn gc_sections(&mut self, _keep_metadata: bool) {}
1896
1897 fn no_gc_sections(&mut self) {}
1898
1899 fn pgo_gen(&mut self) {}
1900
1901 fn no_crt_objects(&mut self) {}
1902
1903 fn no_default_libraries(&mut self) {}
1904
1905 fn control_flow_guard(&mut self) {}
1906
1907 fn ehcont_guard(&mut self) {}
1908
1909 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1910
1911 fn subsystem(&mut self, _subsystem: &str) {}
1912
1913 fn linker_plugin_lto(&mut self) {}
1914}
1915
1916struct LlbcLinker<'a> {
1918 cmd: Command,
1919 sess: &'a Session,
1920}
1921
1922impl<'a> Linker for LlbcLinker<'a> {
1923 fn cmd(&mut self) -> &mut Command {
1924 &mut self.cmd
1925 }
1926
1927 fn set_output_kind(
1928 &mut self,
1929 _output_kind: LinkOutputKind,
1930 _crate_type: CrateType,
1931 _out_filename: &Path,
1932 ) {
1933 }
1934
1935 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1936 panic!("staticlibs not supported")
1937 }
1938
1939 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1940 self.link_or_cc_arg(path);
1941 }
1942
1943 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1944 self.link_arg("--debug");
1945 }
1946
1947 fn optimize(&mut self) {
1948 self.link_arg(match self.sess.opts.optimize {
1949 OptLevel::No => "-O0",
1950 OptLevel::Less => "-O1",
1951 OptLevel::More => "-O2",
1952 OptLevel::Aggressive => "-O3",
1953 OptLevel::Size => "-Os",
1954 OptLevel::SizeMin => "-Oz",
1955 });
1956 }
1957
1958 fn full_relro(&mut self) {}
1959
1960 fn partial_relro(&mut self) {}
1961
1962 fn no_relro(&mut self) {}
1963
1964 fn gc_sections(&mut self, _keep_metadata: bool) {}
1965
1966 fn no_gc_sections(&mut self) {}
1967
1968 fn pgo_gen(&mut self) {}
1969
1970 fn no_crt_objects(&mut self) {}
1971
1972 fn no_default_libraries(&mut self) {}
1973
1974 fn control_flow_guard(&mut self) {}
1975
1976 fn ehcont_guard(&mut self) {}
1977
1978 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1979 match _crate_type {
1980 CrateType::Cdylib => {
1981 for sym in symbols {
1982 self.link_args(&["--export-symbol", sym]);
1983 }
1984 }
1985 _ => (),
1986 }
1987 }
1988
1989 fn subsystem(&mut self, _subsystem: &str) {}
1990
1991 fn linker_plugin_lto(&mut self) {}
1992}
1993
1994struct BpfLinker<'a> {
1995 cmd: Command,
1996 sess: &'a Session,
1997}
1998
1999impl<'a> Linker for BpfLinker<'a> {
2000 fn cmd(&mut self) -> &mut Command {
2001 &mut self.cmd
2002 }
2003
2004 fn set_output_kind(
2005 &mut self,
2006 _output_kind: LinkOutputKind,
2007 _crate_type: CrateType,
2008 _out_filename: &Path,
2009 ) {
2010 }
2011
2012 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2013 panic!("staticlibs not supported")
2014 }
2015
2016 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2017 self.link_or_cc_arg(path);
2018 }
2019
2020 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2021 self.link_arg("--debug");
2022 }
2023
2024 fn optimize(&mut self) {
2025 self.link_arg(match self.sess.opts.optimize {
2026 OptLevel::No => "-O0",
2027 OptLevel::Less => "-O1",
2028 OptLevel::More => "-O2",
2029 OptLevel::Aggressive => "-O3",
2030 OptLevel::Size => "-Os",
2031 OptLevel::SizeMin => "-Oz",
2032 });
2033 }
2034
2035 fn full_relro(&mut self) {}
2036
2037 fn partial_relro(&mut self) {}
2038
2039 fn no_relro(&mut self) {}
2040
2041 fn gc_sections(&mut self, _keep_metadata: bool) {}
2042
2043 fn no_gc_sections(&mut self) {}
2044
2045 fn pgo_gen(&mut self) {}
2046
2047 fn no_crt_objects(&mut self) {}
2048
2049 fn no_default_libraries(&mut self) {}
2050
2051 fn control_flow_guard(&mut self) {}
2052
2053 fn ehcont_guard(&mut self) {}
2054
2055 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2056 let path = tmpdir.join("symbols");
2057 let res: io::Result<()> = try {
2058 let mut f = File::create_buffered(&path)?;
2059 for sym in symbols {
2060 writeln!(f, "{sym}")?;
2061 }
2062 };
2063 if let Err(error) = res {
2064 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2065 } else {
2066 self.link_arg("--export-symbols").link_arg(&path);
2067 }
2068 }
2069
2070 fn subsystem(&mut self, _subsystem: &str) {}
2071
2072 fn linker_plugin_lto(&mut self) {}
2073}