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 find_msvc_tools;
8use rustc_hir::attrs::WindowsSubsystemKind;
9use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
10use rustc_metadata::{
11 find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
12};
13use rustc_middle::bug;
14use rustc_middle::middle::dependency_format::Linkage;
15use rustc_middle::middle::exported_symbols::{
16 self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
17};
18use rustc_middle::ty::TyCtxt;
19use rustc_session::Session;
20use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
21use rustc_target::spec::{Abi, Arch, Cc, LinkOutputKind, LinkerFlavor, Lld, Os};
22use tracing::{debug, warn};
23
24use super::command::Command;
25use super::symbol_export;
26use crate::back::symbol_export::allocator_shim_symbols;
27use crate::base::needs_allocator_shim_for_linking;
28use crate::errors;
29
30#[cfg(test)]
31mod tests;
32
33pub(crate) fn disable_localization(linker: &mut Command) {
39 linker.env("LC_ALL", "C");
42 linker.env("VSLANG", "1033");
44}
45
46pub(crate) fn get_linker<'a>(
50 sess: &'a Session,
51 linker: &Path,
52 flavor: LinkerFlavor,
53 self_contained: bool,
54 target_cpu: &'a str,
55 codegen_backend: &'static str,
56) -> Box<dyn Linker + 'a> {
57 let msvc_tool = find_msvc_tools::find_tool(sess.target.arch.desc(), "link.exe");
58
59 let mut cmd = match linker.to_str() {
68 Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
69 _ => match flavor {
70 LinkerFlavor::Gnu(Cc::No, Lld::Yes)
71 | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
72 | LinkerFlavor::WasmLld(Cc::No)
73 | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
74 LinkerFlavor::Msvc(Lld::No)
75 if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
76 {
77 Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
78 }
79 _ => Command::new(linker),
80 },
81 };
82
83 let t = &sess.target;
87 if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == Abi::Uwp {
88 if let Some(ref tool) = msvc_tool {
89 let original_path = tool.path();
90 if let Some(root_lib_path) = original_path.ancestors().nth(4) {
91 let arch = match t.arch {
92 Arch::X86_64 => Some("x64"),
93 Arch::X86 => Some("x86"),
94 Arch::AArch64 => Some("arm64"),
95 Arch::Arm => Some("arm"),
96 _ => None,
97 };
98 if let Some(ref a) = arch {
99 let mut arg = OsString::from("/LIBPATH:");
101 arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
102 cmd.arg(&arg);
103 } else {
104 warn!("arch is not supported");
105 }
106 } else {
107 warn!("MSVC root path lib location not found");
108 }
109 } else {
110 warn!("link.exe not found");
111 }
112 }
113
114 let mut new_path = sess.get_tools_search_paths(self_contained);
117 let mut msvc_changed_path = false;
118 if sess.target.is_like_msvc
119 && let Some(ref tool) = msvc_tool
120 {
121 for (k, v) in tool.env() {
122 if k == "PATH" {
123 new_path.extend(env::split_paths(v));
124 msvc_changed_path = true;
125 } else {
126 cmd.env(k, v);
127 }
128 }
129 }
130
131 if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
132 new_path.extend(env::split_paths(&path));
133 }
134 cmd.env("PATH", env::join_paths(new_path).unwrap());
135
136 assert!(cmd.get_args().is_empty() || sess.target.abi == Abi::Uwp);
139 match flavor {
140 LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::L4Re => {
141 Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
142 }
143 LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::Aix => {
144 Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
145 }
146 LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
147 LinkerFlavor::Gnu(cc, _)
148 | LinkerFlavor::Darwin(cc, _)
149 | LinkerFlavor::WasmLld(cc)
150 | LinkerFlavor::Unix(cc) => Box::new(GccLinker {
151 cmd,
152 sess,
153 target_cpu,
154 hinted_static: None,
155 is_ld: cc == Cc::No,
156 is_gnu: flavor.is_gnu(),
157 uses_lld: flavor.uses_lld(),
158 codegen_backend,
159 }) as Box<dyn Linker>,
160 LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
161 LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
162 LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
163 LinkerFlavor::Llbc => Box::new(LlbcLinker { cmd, sess }) as Box<dyn Linker>,
164 LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
165 }
166}
167
168fn verbatim_args<L: Linker + ?Sized>(
178 l: &mut L,
179 args: impl IntoIterator<Item: AsRef<OsStr>>,
180) -> &mut L {
181 for arg in args {
182 l.cmd().arg(arg);
183 }
184 l
185}
186fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
189 let mut combined_arg = OsString::from("-Wl");
190 for arg in args {
191 if arg.as_ref().as_encoded_bytes().contains(&b',') {
194 if combined_arg != OsStr::new("-Wl") {
196 cmd.arg(combined_arg);
197 combined_arg = OsString::from("-Wl");
199 }
200
201 cmd.arg("-Xlinker");
203 cmd.arg(arg);
204 } else {
205 combined_arg.push(",");
207 combined_arg.push(arg);
208 }
209 }
210 if combined_arg != OsStr::new("-Wl") {
212 cmd.arg(combined_arg);
213 }
214}
215fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
218 if !l.is_cc() {
219 verbatim_args(l, args);
220 } else {
221 convert_link_args_to_cc_args(l.cmd(), args);
222 }
223 l
224}
225fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
228 assert!(l.is_cc());
229 verbatim_args(l, args)
230}
231fn link_or_cc_args<L: Linker + ?Sized>(
233 l: &mut L,
234 args: impl IntoIterator<Item: AsRef<OsStr>>,
235) -> &mut L {
236 verbatim_args(l, args)
237}
238
239macro_rules! generate_arg_methods {
240 ($($ty:ty)*) => { $(
241 impl $ty {
242 #[allow(unused)]
243 pub(crate) fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
244 verbatim_args(self, args)
245 }
246 #[allow(unused)]
247 pub(crate) fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
248 verbatim_args(self, iter::once(arg))
249 }
250 #[allow(unused)]
251 pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
252 link_args(self, args)
253 }
254 #[allow(unused)]
255 pub(crate) fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
256 link_args(self, iter::once(arg))
257 }
258 #[allow(unused)]
259 pub(crate) fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
260 cc_args(self, args)
261 }
262 #[allow(unused)]
263 pub(crate) fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
264 cc_args(self, iter::once(arg))
265 }
266 #[allow(unused)]
267 pub(crate) fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
268 link_or_cc_args(self, args)
269 }
270 #[allow(unused)]
271 pub(crate) fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
272 link_or_cc_args(self, iter::once(arg))
273 }
274 }
275 )* }
276}
277
278generate_arg_methods! {
279 GccLinker<'_>
280 MsvcLinker<'_>
281 EmLinker<'_>
282 WasmLd<'_>
283 L4Bender<'_>
284 AixLinker<'_>
285 LlbcLinker<'_>
286 PtxLinker<'_>
287 BpfLinker<'_>
288 dyn Linker + '_
289}
290
291pub(crate) trait Linker {
299 fn cmd(&mut self) -> &mut Command;
300 fn is_cc(&self) -> bool {
301 false
302 }
303 fn set_output_kind(
304 &mut self,
305 output_kind: LinkOutputKind,
306 crate_type: CrateType,
307 out_filename: &Path,
308 );
309 fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
310 bug!("dylib linked with unsupported linker")
311 }
312 fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
313 bug!("dylib linked with unsupported linker")
314 }
315 fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
316 bug!("framework linked with unsupported linker")
317 }
318 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
319 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
320 fn include_path(&mut self, path: &Path) {
321 link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]);
322 }
323 fn framework_path(&mut self, _path: &Path) {
324 bug!("framework path set with unsupported linker")
325 }
326 fn output_filename(&mut self, path: &Path) {
327 link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]);
328 }
329 fn add_object(&mut self, path: &Path) {
330 link_or_cc_args(self, &[path]);
331 }
332 fn gc_sections(&mut self, keep_metadata: bool);
333 fn full_relro(&mut self);
334 fn partial_relro(&mut self);
335 fn no_relro(&mut self);
336 fn optimize(&mut self);
337 fn pgo_gen(&mut self);
338 fn control_flow_guard(&mut self);
339 fn ehcont_guard(&mut self);
340 fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
341 fn no_crt_objects(&mut self);
342 fn no_default_libraries(&mut self);
343 fn export_symbols(
344 &mut self,
345 tmpdir: &Path,
346 crate_type: CrateType,
347 symbols: &[(String, SymbolExportKind)],
348 );
349 fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind);
350 fn linker_plugin_lto(&mut self);
351 fn add_eh_frame_header(&mut self) {}
352 fn add_no_exec(&mut self) {}
353 fn add_as_needed(&mut self) {}
354 fn reset_per_library_state(&mut self) {}
355}
356
357impl dyn Linker + '_ {
358 pub(crate) fn take_cmd(&mut self) -> Command {
359 mem::replace(self.cmd(), Command::new(""))
360 }
361}
362
363struct GccLinker<'a> {
364 cmd: Command,
365 sess: &'a Session,
366 target_cpu: &'a str,
367 hinted_static: Option<bool>, is_ld: bool,
370 is_gnu: bool,
371 uses_lld: bool,
372 codegen_backend: &'static str,
373}
374
375impl<'a> GccLinker<'a> {
376 fn takes_hints(&self) -> bool {
377 !self.sess.target.is_like_darwin && !self.sess.target.is_like_wasm
386 }
387
388 fn hint_static(&mut self) {
393 if !self.takes_hints() {
394 return;
395 }
396 if self.hinted_static != Some(true) {
397 self.link_arg("-Bstatic");
398 self.hinted_static = Some(true);
399 }
400 }
401
402 fn hint_dynamic(&mut self) {
403 if !self.takes_hints() {
404 return;
405 }
406 if self.hinted_static != Some(false) {
407 self.link_arg("-Bdynamic");
408 self.hinted_static = Some(false);
409 }
410 }
411
412 fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
413 if let Some(plugin_path) = plugin_path {
414 let mut arg = OsString::from("-plugin=");
415 arg.push(plugin_path);
416 self.link_arg(&arg);
417 }
418
419 let opt_level = match self.sess.opts.optimize {
420 config::OptLevel::No => "O0",
421 config::OptLevel::Less => "O1",
422 config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
423 config::OptLevel::Aggressive => "O3",
424 };
425
426 if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
427 self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
428 };
429 let prefix = if self.codegen_backend == "gcc" {
430 "-"
432 } else {
433 ""
434 };
435 self.link_args(&[
436 &format!("-plugin-opt={prefix}{opt_level}"),
437 &format!("-plugin-opt={prefix}mcpu={}", self.target_cpu),
438 ]);
439 }
440
441 fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
442 if self.sess.target.is_like_darwin {
444 if self.is_cc() {
445 self.cc_arg("-dynamiclib");
447 } else {
448 self.link_arg("-dylib");
449 }
451
452 if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
457 let mut rpath = OsString::from("@rpath/");
458 rpath.push(out_filename.file_name().unwrap());
459 self.link_arg("-install_name").link_arg(rpath);
460 }
461 } else {
462 self.link_or_cc_arg("-shared");
463 if let Some(name) = out_filename.file_name() {
464 if self.sess.target.is_like_windows {
465 let (prefix, suffix) = self.sess.staticlib_components(false);
469 let mut implib_name = OsString::from(prefix);
470 implib_name.push(name);
471 implib_name.push(suffix);
472 let mut out_implib = OsString::from("--out-implib=");
473 out_implib.push(out_filename.with_file_name(implib_name));
474 self.link_arg(out_implib);
475 } else if crate_type == CrateType::Dylib {
476 let mut soname = OsString::from("-soname=");
480 soname.push(name);
481 self.link_arg(soname);
482 }
483 }
484 }
485 }
486
487 fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
488 if !as_needed {
489 if self.sess.target.is_like_darwin {
490 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
494 } else if self.is_gnu && !self.sess.target.is_like_windows {
495 self.link_arg("--no-as-needed");
496 } else {
497 self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
498 }
499 }
500
501 f(self);
502
503 if !as_needed {
504 if self.sess.target.is_like_darwin {
505 } else if self.is_gnu && !self.sess.target.is_like_windows {
507 self.link_arg("--as-needed");
508 }
509 }
510 }
511}
512
513impl<'a> Linker for GccLinker<'a> {
514 fn cmd(&mut self) -> &mut Command {
515 &mut self.cmd
516 }
517
518 fn is_cc(&self) -> bool {
519 !self.is_ld
520 }
521
522 fn set_output_kind(
523 &mut self,
524 output_kind: LinkOutputKind,
525 crate_type: CrateType,
526 out_filename: &Path,
527 ) {
528 match output_kind {
529 LinkOutputKind::DynamicNoPicExe => {
530 if !self.is_ld && self.is_gnu {
531 self.cc_arg("-no-pie");
532 }
533 }
534 LinkOutputKind::DynamicPicExe => {
535 if !self.sess.target.is_like_windows {
537 self.link_or_cc_arg("-pie");
539 }
540 }
541 LinkOutputKind::StaticNoPicExe => {
542 self.link_or_cc_arg("-static");
544 if !self.is_ld && self.is_gnu {
545 self.cc_arg("-no-pie");
546 }
547 }
548 LinkOutputKind::StaticPicExe => {
549 if !self.is_ld {
550 self.cc_arg("-static-pie");
553 } else {
554 self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
560 }
561 }
562 LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
563 LinkOutputKind::StaticDylib => {
564 self.link_or_cc_arg("-static");
565 self.build_dylib(crate_type, out_filename);
566 }
567 LinkOutputKind::WasiReactorExe => {
568 self.link_args(&["--entry", "_initialize"]);
569 }
570 }
571
572 if self.sess.target.os == Os::VxWorks
578 && matches!(
579 output_kind,
580 LinkOutputKind::StaticNoPicExe
581 | LinkOutputKind::StaticPicExe
582 | LinkOutputKind::StaticDylib
583 )
584 {
585 self.cc_arg("--static-crt");
586 }
587
588 if self.sess.target.arch == Arch::Avr && !self.uses_lld {
594 self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
595 }
596 }
597
598 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
599 if self.sess.target.os == Os::Illumos && name == "c" {
600 return;
606 }
607 self.hint_dynamic();
608 self.with_as_needed(as_needed, |this| {
609 let colon = if verbatim && this.is_gnu { ":" } else { "" };
610 this.link_or_cc_arg(format!("-l{colon}{name}"));
611 });
612 }
613
614 fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
615 self.hint_dynamic();
616 self.with_as_needed(as_needed, |this| {
617 this.link_or_cc_arg(path);
618 })
619 }
620
621 fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
622 self.hint_dynamic();
623 if !as_needed {
624 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
628 }
629 self.link_or_cc_args(&["-framework", name]);
630 }
631
632 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
633 self.hint_static();
634 let colon = if verbatim && self.is_gnu { ":" } else { "" };
635 if !whole_archive {
636 self.link_or_cc_arg(format!("-l{colon}{name}"));
637 } else if self.sess.target.is_like_darwin {
638 self.link_arg("-force_load");
641 self.link_arg(find_native_static_library(name, verbatim, self.sess));
642 } else {
643 self.link_arg("--whole-archive")
644 .link_or_cc_arg(format!("-l{colon}{name}"))
645 .link_arg("--no-whole-archive");
646 }
647 }
648
649 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
650 self.hint_static();
651 if !whole_archive {
652 self.link_or_cc_arg(path);
653 } else if self.sess.target.is_like_darwin {
654 self.link_arg("-force_load").link_arg(path);
655 } else {
656 self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
657 }
658 }
659
660 fn framework_path(&mut self, path: &Path) {
661 self.link_or_cc_arg("-F").link_or_cc_arg(path);
662 }
663 fn full_relro(&mut self) {
664 self.link_args(&["-z", "relro", "-z", "now"]);
665 }
666 fn partial_relro(&mut self) {
667 self.link_args(&["-z", "relro"]);
668 }
669 fn no_relro(&mut self) {
670 self.link_args(&["-z", "norelro"]);
671 }
672
673 fn gc_sections(&mut self, keep_metadata: bool) {
674 if self.sess.target.is_like_darwin {
689 self.link_arg("-dead_strip");
690
691 } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
697 self.link_arg("--gc-sections");
698 }
699 }
700
701 fn optimize(&mut self) {
702 if !self.is_gnu && !self.sess.target.is_like_wasm {
703 return;
704 }
705
706 if self.sess.opts.optimize == config::OptLevel::More
709 || self.sess.opts.optimize == config::OptLevel::Aggressive
710 {
711 self.link_arg("-O1");
712 }
713 }
714
715 fn pgo_gen(&mut self) {
716 if !self.is_gnu {
717 return;
718 }
719
720 self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
732 }
733
734 fn control_flow_guard(&mut self) {}
735
736 fn ehcont_guard(&mut self) {}
737
738 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
739 if self.sess.target.is_like_darwin {
741 return;
742 }
743
744 match strip {
745 Strip::None => {}
746 Strip::Debuginfo => {
747 if !self.sess.target.is_like_solaris {
752 self.link_arg("--strip-debug");
753 }
754 }
755 Strip::Symbols => {
756 self.link_arg("--strip-all");
757 }
758 }
759 match self.sess.opts.unstable_opts.debuginfo_compression {
760 config::DebugInfoCompression::None => {}
761 config::DebugInfoCompression::Zlib => {
762 self.link_arg("--compress-debug-sections=zlib");
763 }
764 config::DebugInfoCompression::Zstd => {
765 self.link_arg("--compress-debug-sections=zstd");
766 }
767 }
768 }
769
770 fn no_crt_objects(&mut self) {
771 if !self.is_ld {
772 self.cc_arg("-nostartfiles");
773 }
774 }
775
776 fn no_default_libraries(&mut self) {
777 if !self.is_ld {
778 self.cc_arg("-nodefaultlibs");
779 }
780 }
781
782 fn export_symbols(
783 &mut self,
784 tmpdir: &Path,
785 crate_type: CrateType,
786 symbols: &[(String, SymbolExportKind)],
787 ) {
788 if crate_type == CrateType::Executable {
790 let should_export_executable_symbols =
791 self.sess.opts.unstable_opts.export_executable_symbols;
792 if self.sess.target.override_export_symbols.is_none()
793 && !should_export_executable_symbols
794 {
795 return;
796 }
797 }
798
799 if !self.sess.target.limit_rdylib_exports {
804 return;
805 }
806
807 let path = tmpdir.join(if self.sess.target.is_like_windows { "list.def" } else { "list" });
808 debug!("EXPORTED SYMBOLS:");
809
810 if self.sess.target.is_like_darwin {
811 let res: io::Result<()> = try {
813 let mut f = File::create_buffered(&path)?;
814 for (sym, _) in symbols {
815 debug!(" _{sym}");
816 writeln!(f, "_{sym}")?;
817 }
818 };
819 if let Err(error) = res {
820 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
821 }
822 self.link_arg("-exported_symbols_list").link_arg(path);
823 } else if self.sess.target.is_like_windows {
824 let res: io::Result<()> = try {
825 let mut f = File::create_buffered(&path)?;
826
827 writeln!(f, "EXPORTS")?;
830 for (symbol, kind) in symbols {
831 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
832 debug!(" _{symbol}");
833 writeln!(f, " \"{symbol}\"{kind_marker}")?;
836 }
837 };
838 if let Err(error) = res {
839 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
840 }
841 self.link_arg(path);
842 } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
843 let res: io::Result<()> = try {
844 let mut f = File::create_buffered(&path)?;
845 writeln!(f, "{{")?;
846 for (sym, _) in symbols {
847 debug!(sym);
848 writeln!(f, " {sym};")?;
849 }
850 writeln!(f, "}};")?;
851 };
852 if let Err(error) = res {
853 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
854 }
855 self.link_arg("--dynamic-list").link_arg(path);
856 } else if self.sess.target.is_like_wasm {
857 self.link_arg("--no-export-dynamic");
858 for (sym, _) in symbols {
859 self.link_arg("--export").link_arg(sym);
860 }
861 } else {
862 let res: io::Result<()> = try {
864 let mut f = File::create_buffered(&path)?;
865 writeln!(f, "{{")?;
866 if !symbols.is_empty() {
867 writeln!(f, " global:")?;
868 for (sym, _) in symbols {
869 debug!(" {sym};");
870 writeln!(f, " {sym};")?;
871 }
872 }
873 writeln!(f, "\n local:\n *;\n}};")?;
874 };
875 if let Err(error) = res {
876 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
877 }
878 if self.sess.target.is_like_solaris {
879 self.link_arg("-M").link_arg(path);
880 } else {
881 let mut arg = OsString::from("--version-script=");
882 arg.push(path);
883 self.link_arg(arg).link_arg("--no-undefined-version");
884 }
885 }
886 }
887
888 fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind) {
889 self.link_args(&["--subsystem", subsystem.as_str()]);
890 }
891
892 fn reset_per_library_state(&mut self) {
893 self.hint_dynamic(); }
895
896 fn linker_plugin_lto(&mut self) {
897 match self.sess.opts.cg.linker_plugin_lto {
898 LinkerPluginLto::Disabled => {
899 }
901 LinkerPluginLto::LinkerPluginAuto => {
902 self.push_linker_plugin_lto_args(None);
903 }
904 LinkerPluginLto::LinkerPlugin(ref path) => {
905 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
906 }
907 }
908 }
909
910 fn add_eh_frame_header(&mut self) {
914 self.link_arg("--eh-frame-hdr");
915 }
916
917 fn add_no_exec(&mut self) {
918 if self.sess.target.is_like_windows {
919 self.link_arg("--nxcompat");
920 } else if self.is_gnu {
921 self.link_args(&["-z", "noexecstack"]);
922 }
923 }
924
925 fn add_as_needed(&mut self) {
926 if self.is_gnu && !self.sess.target.is_like_windows {
927 self.link_arg("--as-needed");
928 } else if self.sess.target.is_like_solaris {
929 self.link_args(&["-z", "ignore"]);
931 }
932 }
933}
934
935struct MsvcLinker<'a> {
936 cmd: Command,
937 sess: &'a Session,
938}
939
940impl<'a> Linker for MsvcLinker<'a> {
941 fn cmd(&mut self) -> &mut Command {
942 &mut self.cmd
943 }
944
945 fn set_output_kind(
946 &mut self,
947 output_kind: LinkOutputKind,
948 _crate_type: CrateType,
949 out_filename: &Path,
950 ) {
951 match output_kind {
952 LinkOutputKind::DynamicNoPicExe
953 | LinkOutputKind::DynamicPicExe
954 | LinkOutputKind::StaticNoPicExe
955 | LinkOutputKind::StaticPicExe => {}
956 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
957 self.link_arg("/DLL");
958 let mut arg: OsString = "/IMPLIB:".into();
959 arg.push(out_filename.with_extension("dll.lib"));
960 self.link_arg(arg);
961 }
962 LinkOutputKind::WasiReactorExe => {
963 panic!("can't link as reactor on non-wasi target");
964 }
965 }
966 }
967
968 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
969 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
972 self.link_arg(path);
973 } else {
974 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
975 }
976 }
977
978 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
979 let implib_path = path.with_extension("dll.lib");
982 if implib_path.exists() {
983 self.link_or_cc_arg(implib_path);
984 }
985 }
986
987 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
988 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
991 self.link_staticlib_by_path(&path, whole_archive);
992 } else {
993 let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
994 let (prefix, suffix) = self.sess.staticlib_components(verbatim);
995 self.link_arg(format!("{opts}{prefix}{name}{suffix}"));
996 }
997 }
998
999 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1000 if !whole_archive {
1001 self.link_arg(path);
1002 } else {
1003 let mut arg = OsString::from("/WHOLEARCHIVE:");
1004 arg.push(path);
1005 self.link_arg(arg);
1006 }
1007 }
1008
1009 fn gc_sections(&mut self, _keep_metadata: bool) {
1010 if self.sess.opts.optimize != config::OptLevel::No {
1014 self.link_arg("/OPT:REF,ICF");
1015 } else {
1016 self.link_arg("/OPT:REF,NOICF");
1019 }
1020 }
1021
1022 fn full_relro(&mut self) {
1023 }
1025
1026 fn partial_relro(&mut self) {
1027 }
1029
1030 fn no_relro(&mut self) {
1031 }
1033
1034 fn no_crt_objects(&mut self) {
1035 }
1037
1038 fn no_default_libraries(&mut self) {
1039 self.link_arg("/NODEFAULTLIB");
1040 }
1041
1042 fn include_path(&mut self, path: &Path) {
1043 let mut arg = OsString::from("/LIBPATH:");
1044 arg.push(path);
1045 self.link_arg(&arg);
1046 }
1047
1048 fn output_filename(&mut self, path: &Path) {
1049 let mut arg = OsString::from("/OUT:");
1050 arg.push(path);
1051 self.link_arg(&arg);
1052 }
1053
1054 fn optimize(&mut self) {
1055 }
1057
1058 fn pgo_gen(&mut self) {
1059 }
1061
1062 fn control_flow_guard(&mut self) {
1063 self.link_arg("/guard:cf");
1064 }
1065
1066 fn ehcont_guard(&mut self) {
1067 if self.sess.target.pointer_width == 64 {
1068 self.link_arg("/guard:ehcont");
1069 }
1070 }
1071
1072 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1073 self.link_arg("/DEBUG");
1076
1077 self.link_arg("/PDBALTPATH:%_PDB%");
1085
1086 let natvis_dir_path = self.sess.opts.sysroot.path().join("lib\\rustlib\\etc");
1088 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1089 for entry in natvis_dir {
1090 match entry {
1091 Ok(entry) => {
1092 let path = entry.path();
1093 if path.extension() == Some("natvis".as_ref()) {
1094 let mut arg = OsString::from("/NATVIS:");
1095 arg.push(path);
1096 self.link_arg(arg);
1097 }
1098 }
1099 Err(error) => {
1100 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1101 }
1102 }
1103 }
1104 }
1105
1106 for path in natvis_debugger_visualizers {
1108 let mut arg = OsString::from("/NATVIS:");
1109 arg.push(path);
1110 self.link_arg(arg);
1111 }
1112 }
1113
1114 fn export_symbols(
1127 &mut self,
1128 tmpdir: &Path,
1129 crate_type: CrateType,
1130 symbols: &[(String, SymbolExportKind)],
1131 ) {
1132 if crate_type == CrateType::Executable {
1134 let should_export_executable_symbols =
1135 self.sess.opts.unstable_opts.export_executable_symbols;
1136 if !should_export_executable_symbols {
1137 return;
1138 }
1139 }
1140
1141 let path = tmpdir.join("lib.def");
1142 let res: io::Result<()> = try {
1143 let mut f = File::create_buffered(&path)?;
1144
1145 writeln!(f, "LIBRARY")?;
1148 writeln!(f, "EXPORTS")?;
1149 for (symbol, kind) in symbols {
1150 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
1151 debug!(" _{symbol}");
1152 writeln!(f, " {symbol}{kind_marker}")?;
1153 }
1154 };
1155 if let Err(error) = res {
1156 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1157 }
1158 let mut arg = OsString::from("/DEF:");
1159 arg.push(path);
1160 self.link_arg(&arg);
1161 }
1162
1163 fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind) {
1164 let subsystem = subsystem.as_str();
1165 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1166
1167 if subsystem == "windows" {
1182 self.link_arg("/ENTRY:mainCRTStartup");
1183 }
1184 }
1185
1186 fn linker_plugin_lto(&mut self) {
1187 }
1189
1190 fn add_no_exec(&mut self) {
1191 self.link_arg("/NXCOMPAT");
1192 }
1193}
1194
1195struct EmLinker<'a> {
1196 cmd: Command,
1197 sess: &'a Session,
1198}
1199
1200impl<'a> Linker for EmLinker<'a> {
1201 fn cmd(&mut self) -> &mut Command {
1202 &mut self.cmd
1203 }
1204
1205 fn is_cc(&self) -> bool {
1206 true
1207 }
1208
1209 fn set_output_kind(
1210 &mut self,
1211 _output_kind: LinkOutputKind,
1212 _crate_type: CrateType,
1213 _out_filename: &Path,
1214 ) {
1215 }
1216
1217 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1218 self.link_or_cc_args(&["-l", name]);
1220 }
1221
1222 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1223 self.link_or_cc_arg(path);
1224 }
1225
1226 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1227 self.link_or_cc_args(&["-l", name]);
1228 }
1229
1230 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1231 self.link_or_cc_arg(path);
1232 }
1233
1234 fn full_relro(&mut self) {
1235 }
1237
1238 fn partial_relro(&mut self) {
1239 }
1241
1242 fn no_relro(&mut self) {
1243 }
1245
1246 fn gc_sections(&mut self, _keep_metadata: bool) {
1247 }
1249
1250 fn optimize(&mut self) {
1251 self.cc_arg(match self.sess.opts.optimize {
1253 OptLevel::No => "-O0",
1254 OptLevel::Less => "-O1",
1255 OptLevel::More => "-O2",
1256 OptLevel::Aggressive => "-O3",
1257 OptLevel::Size => "-Os",
1258 OptLevel::SizeMin => "-Oz",
1259 });
1260 }
1261
1262 fn pgo_gen(&mut self) {
1263 }
1265
1266 fn control_flow_guard(&mut self) {}
1267
1268 fn ehcont_guard(&mut self) {}
1269
1270 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1271 self.cc_arg(match self.sess.opts.debuginfo {
1274 DebugInfo::None => "-g0",
1275 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1276 "--profiling-funcs"
1277 }
1278 DebugInfo::Full => "-g",
1279 });
1280 }
1281
1282 fn no_crt_objects(&mut self) {}
1283
1284 fn no_default_libraries(&mut self) {
1285 self.cc_arg("-nodefaultlibs");
1286 }
1287
1288 fn export_symbols(
1289 &mut self,
1290 _tmpdir: &Path,
1291 _crate_type: CrateType,
1292 symbols: &[(String, SymbolExportKind)],
1293 ) {
1294 debug!("EXPORTED SYMBOLS:");
1295
1296 self.cc_arg("-s");
1297
1298 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1299 let encoded = serde_json::to_string(
1300 &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
1301 )
1302 .unwrap();
1303 debug!("{encoded}");
1304
1305 arg.push(encoded);
1306
1307 self.cc_arg(arg);
1308 }
1309
1310 fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {
1311 }
1313
1314 fn linker_plugin_lto(&mut self) {
1315 }
1317}
1318
1319struct WasmLd<'a> {
1320 cmd: Command,
1321 sess: &'a Session,
1322}
1323
1324impl<'a> WasmLd<'a> {
1325 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1326 WasmLd { cmd, sess }
1327 }
1328}
1329
1330impl<'a> Linker for WasmLd<'a> {
1331 fn cmd(&mut self) -> &mut Command {
1332 &mut self.cmd
1333 }
1334
1335 fn set_output_kind(
1336 &mut self,
1337 output_kind: LinkOutputKind,
1338 _crate_type: CrateType,
1339 _out_filename: &Path,
1340 ) {
1341 match output_kind {
1342 LinkOutputKind::DynamicNoPicExe
1343 | LinkOutputKind::DynamicPicExe
1344 | LinkOutputKind::StaticNoPicExe
1345 | LinkOutputKind::StaticPicExe => {}
1346 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1347 self.link_arg("--no-entry");
1348 }
1349 LinkOutputKind::WasiReactorExe => {
1350 self.link_args(&["--entry", "_initialize"]);
1351 }
1352 }
1353 }
1354
1355 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1356 self.link_or_cc_args(&["-l", name]);
1357 }
1358
1359 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1360 self.link_or_cc_arg(path);
1361 }
1362
1363 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1364 if !whole_archive {
1365 self.link_or_cc_args(&["-l", name]);
1366 } else {
1367 self.link_arg("--whole-archive")
1368 .link_or_cc_args(&["-l", name])
1369 .link_arg("--no-whole-archive");
1370 }
1371 }
1372
1373 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1374 if !whole_archive {
1375 self.link_or_cc_arg(path);
1376 } else {
1377 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1378 }
1379 }
1380
1381 fn full_relro(&mut self) {}
1382
1383 fn partial_relro(&mut self) {}
1384
1385 fn no_relro(&mut self) {}
1386
1387 fn gc_sections(&mut self, _keep_metadata: bool) {
1388 self.link_arg("--gc-sections");
1389 }
1390
1391 fn optimize(&mut self) {
1392 self.link_arg(match self.sess.opts.optimize {
1395 OptLevel::No => "-O0",
1396 OptLevel::Less => "-O1",
1397 OptLevel::More => "-O2",
1398 OptLevel::Aggressive => "-O3",
1399 OptLevel::Size => "-O2",
1402 OptLevel::SizeMin => "-O2",
1403 });
1404 }
1405
1406 fn pgo_gen(&mut self) {}
1407
1408 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1409 match strip {
1410 Strip::None => {}
1411 Strip::Debuginfo => {
1412 self.link_arg("--strip-debug");
1413 }
1414 Strip::Symbols => {
1415 self.link_arg("--strip-all");
1416 }
1417 }
1418 }
1419
1420 fn control_flow_guard(&mut self) {}
1421
1422 fn ehcont_guard(&mut self) {}
1423
1424 fn no_crt_objects(&mut self) {}
1425
1426 fn no_default_libraries(&mut self) {}
1427
1428 fn export_symbols(
1429 &mut self,
1430 _tmpdir: &Path,
1431 _crate_type: CrateType,
1432 symbols: &[(String, SymbolExportKind)],
1433 ) {
1434 for (sym, _) in symbols {
1435 self.link_args(&["--export", sym]);
1436 }
1437
1438 if matches!(self.sess.target.os, Os::Unknown | Os::None) {
1443 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1444 }
1445 }
1446
1447 fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {}
1448
1449 fn linker_plugin_lto(&mut self) {
1450 match self.sess.opts.cg.linker_plugin_lto {
1451 LinkerPluginLto::Disabled => {
1452 }
1454 LinkerPluginLto::LinkerPluginAuto => {
1455 self.push_linker_plugin_lto_args();
1456 }
1457 LinkerPluginLto::LinkerPlugin(_) => {
1458 self.push_linker_plugin_lto_args();
1459 }
1460 }
1461 }
1462}
1463
1464impl<'a> WasmLd<'a> {
1465 fn push_linker_plugin_lto_args(&mut self) {
1466 let opt_level = match self.sess.opts.optimize {
1467 config::OptLevel::No => "O0",
1468 config::OptLevel::Less => "O1",
1469 config::OptLevel::More => "O2",
1470 config::OptLevel::Aggressive => "O3",
1471 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1473 };
1474 self.link_arg(&format!("--lto-{opt_level}"));
1475 }
1476}
1477
1478struct L4Bender<'a> {
1480 cmd: Command,
1481 sess: &'a Session,
1482 hinted_static: bool,
1483}
1484
1485impl<'a> Linker for L4Bender<'a> {
1486 fn cmd(&mut self) -> &mut Command {
1487 &mut self.cmd
1488 }
1489
1490 fn set_output_kind(
1491 &mut self,
1492 _output_kind: LinkOutputKind,
1493 _crate_type: CrateType,
1494 _out_filename: &Path,
1495 ) {
1496 }
1497
1498 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1499 self.hint_static();
1500 if !whole_archive {
1501 self.link_arg(format!("-PC{name}"));
1502 } else {
1503 self.link_arg("--whole-archive")
1504 .link_or_cc_arg(format!("-l{name}"))
1505 .link_arg("--no-whole-archive");
1506 }
1507 }
1508
1509 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1510 self.hint_static();
1511 if !whole_archive {
1512 self.link_or_cc_arg(path);
1513 } else {
1514 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1515 }
1516 }
1517
1518 fn full_relro(&mut self) {
1519 self.link_args(&["-z", "relro", "-z", "now"]);
1520 }
1521
1522 fn partial_relro(&mut self) {
1523 self.link_args(&["-z", "relro"]);
1524 }
1525
1526 fn no_relro(&mut self) {
1527 self.link_args(&["-z", "norelro"]);
1528 }
1529
1530 fn gc_sections(&mut self, keep_metadata: bool) {
1531 if !keep_metadata {
1532 self.link_arg("--gc-sections");
1533 }
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, SymbolExportKind)]) {
1565 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1567 }
1568
1569 fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind) {
1570 let subsystem = subsystem.as_str();
1571 self.link_arg(&format!("--subsystem {subsystem}"));
1572 }
1573
1574 fn reset_per_library_state(&mut self) {
1575 self.hint_static(); }
1577
1578 fn linker_plugin_lto(&mut self) {}
1579
1580 fn control_flow_guard(&mut self) {}
1581
1582 fn ehcont_guard(&mut self) {}
1583
1584 fn no_crt_objects(&mut self) {}
1585}
1586
1587impl<'a> L4Bender<'a> {
1588 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1589 L4Bender { cmd, sess, hinted_static: false }
1590 }
1591
1592 fn hint_static(&mut self) {
1593 if !self.hinted_static {
1594 self.link_or_cc_arg("-static");
1595 self.hinted_static = true;
1596 }
1597 }
1598}
1599
1600struct AixLinker<'a> {
1602 cmd: Command,
1603 sess: &'a Session,
1604 hinted_static: Option<bool>,
1605}
1606
1607impl<'a> AixLinker<'a> {
1608 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1609 AixLinker { cmd, sess, hinted_static: None }
1610 }
1611
1612 fn hint_static(&mut self) {
1613 if self.hinted_static != Some(true) {
1614 self.link_arg("-bstatic");
1615 self.hinted_static = Some(true);
1616 }
1617 }
1618
1619 fn hint_dynamic(&mut self) {
1620 if self.hinted_static != Some(false) {
1621 self.link_arg("-bdynamic");
1622 self.hinted_static = Some(false);
1623 }
1624 }
1625
1626 fn build_dylib(&mut self, _out_filename: &Path) {
1627 self.link_args(&["-bM:SRE", "-bnoentry"]);
1628 self.link_arg("-bexpfull");
1631 }
1632}
1633
1634impl<'a> Linker for AixLinker<'a> {
1635 fn cmd(&mut self) -> &mut Command {
1636 &mut self.cmd
1637 }
1638
1639 fn set_output_kind(
1640 &mut self,
1641 output_kind: LinkOutputKind,
1642 _crate_type: CrateType,
1643 out_filename: &Path,
1644 ) {
1645 match output_kind {
1646 LinkOutputKind::DynamicDylib => {
1647 self.hint_dynamic();
1648 self.build_dylib(out_filename);
1649 }
1650 LinkOutputKind::StaticDylib => {
1651 self.hint_static();
1652 self.build_dylib(out_filename);
1653 }
1654 _ => {}
1655 }
1656 }
1657
1658 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1659 self.hint_dynamic();
1660 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1661 }
1662
1663 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1664 self.hint_dynamic();
1665 self.link_or_cc_arg(path);
1666 }
1667
1668 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1669 self.hint_static();
1670 if !whole_archive {
1671 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1672 } else {
1673 let mut arg = OsString::from("-bkeepfile:");
1674 arg.push(find_native_static_library(name, verbatim, self.sess));
1675 self.link_or_cc_arg(arg);
1676 }
1677 }
1678
1679 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1680 self.hint_static();
1681 if !whole_archive {
1682 self.link_or_cc_arg(path);
1683 } else {
1684 let mut arg = OsString::from("-bkeepfile:");
1685 arg.push(path);
1686 self.link_arg(arg);
1687 }
1688 }
1689
1690 fn full_relro(&mut self) {}
1691
1692 fn partial_relro(&mut self) {}
1693
1694 fn no_relro(&mut self) {}
1695
1696 fn gc_sections(&mut self, _keep_metadata: bool) {
1697 self.link_arg("-bgc");
1698 }
1699
1700 fn optimize(&mut self) {}
1701
1702 fn pgo_gen(&mut self) {
1703 self.link_arg("-bdbg:namedsects:ss");
1704 self.link_arg("-u");
1705 self.link_arg("__llvm_profile_runtime");
1706 }
1707
1708 fn control_flow_guard(&mut self) {}
1709
1710 fn ehcont_guard(&mut self) {}
1711
1712 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1713
1714 fn no_crt_objects(&mut self) {}
1715
1716 fn no_default_libraries(&mut self) {}
1717
1718 fn export_symbols(
1719 &mut self,
1720 tmpdir: &Path,
1721 _crate_type: CrateType,
1722 symbols: &[(String, SymbolExportKind)],
1723 ) {
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 windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {}
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_non_generic_symbols(cnum).iter() {
1766 callback(symbol, info, cnum);
1767 }
1768 for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() {
1769 callback(symbol, info, cnum);
1770 }
1771 }
1772 }
1773}
1774
1775pub(crate) fn exported_symbols(
1776 tcx: TyCtxt<'_>,
1777 crate_type: CrateType,
1778) -> Vec<(String, SymbolExportKind)> {
1779 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1780 return exports
1781 .iter()
1782 .map(|name| {
1783 (
1784 name.to_string(),
1785 SymbolExportKind::Text,
1789 )
1790 })
1791 .collect();
1792 }
1793
1794 let mut symbols = if let CrateType::ProcMacro = crate_type {
1795 exported_symbols_for_proc_macro_crate(tcx)
1796 } else {
1797 exported_symbols_for_non_proc_macro(tcx, crate_type)
1798 };
1799
1800 if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
1801 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1802 symbols.push((metadata_symbol_name, SymbolExportKind::Data));
1803 }
1804
1805 symbols
1806}
1807
1808fn exported_symbols_for_non_proc_macro(
1809 tcx: TyCtxt<'_>,
1810 crate_type: CrateType,
1811) -> Vec<(String, SymbolExportKind)> {
1812 let mut symbols = Vec::new();
1813 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1814 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1815 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1819 symbols.push((
1820 symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1821 info.kind,
1822 ));
1823 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1824 }
1825 });
1826
1827 if export_threshold == SymbolExportLevel::Rust
1829 && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
1830 && tcx.allocator_kind(()).is_some()
1831 {
1832 symbols.extend(allocator_shim_symbols(tcx));
1833 }
1834
1835 symbols
1836}
1837
1838fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
1839 if !tcx.sess.opts.output_types.should_codegen() {
1841 return Vec::new();
1842 }
1843
1844 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1845 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1846
1847 vec![(proc_macro_decls_name, SymbolExportKind::Data)]
1848}
1849
1850pub(crate) fn linked_symbols(
1851 tcx: TyCtxt<'_>,
1852 crate_type: CrateType,
1853) -> Vec<(String, SymbolExportKind)> {
1854 match crate_type {
1855 CrateType::Executable
1856 | CrateType::ProcMacro
1857 | CrateType::Cdylib
1858 | CrateType::Dylib
1859 | CrateType::Sdylib => (),
1860 CrateType::Staticlib | CrateType::Rlib => {
1861 return Vec::new();
1863 }
1864 }
1865
1866 match tcx.sess.lto() {
1867 Lto::No | Lto::ThinLocal => {}
1868 Lto::Thin | Lto::Fat => {
1869 return Vec::new();
1878 }
1879 }
1880
1881 let mut symbols = Vec::new();
1882
1883 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1884 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1885 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
1886 || info.used
1887 || info.rustc_std_internal_symbol
1888 {
1889 symbols.push((
1890 symbol_export::linking_symbol_name_for_instance_in_crate(
1891 tcx, symbol, info.kind, cnum,
1892 ),
1893 info.kind,
1894 ));
1895 }
1896 });
1897
1898 symbols
1899}
1900
1901struct PtxLinker<'a> {
1904 cmd: Command,
1905 sess: &'a Session,
1906}
1907
1908impl<'a> Linker for PtxLinker<'a> {
1909 fn cmd(&mut self) -> &mut Command {
1910 &mut self.cmd
1911 }
1912
1913 fn set_output_kind(
1914 &mut self,
1915 _output_kind: LinkOutputKind,
1916 _crate_type: CrateType,
1917 _out_filename: &Path,
1918 ) {
1919 }
1920
1921 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1922 panic!("staticlibs not supported")
1923 }
1924
1925 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1926 self.link_arg("--rlib").link_arg(path);
1927 }
1928
1929 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1930 self.link_arg("--debug");
1931 }
1932
1933 fn add_object(&mut self, path: &Path) {
1934 self.link_arg("--bitcode").link_arg(path);
1935 }
1936
1937 fn optimize(&mut self) {
1938 match self.sess.lto() {
1939 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1940 self.link_arg("-Olto");
1941 }
1942
1943 Lto::No => {}
1944 }
1945 }
1946
1947 fn full_relro(&mut self) {}
1948
1949 fn partial_relro(&mut self) {}
1950
1951 fn no_relro(&mut self) {}
1952
1953 fn gc_sections(&mut self, _keep_metadata: bool) {}
1954
1955 fn pgo_gen(&mut self) {}
1956
1957 fn no_crt_objects(&mut self) {}
1958
1959 fn no_default_libraries(&mut self) {}
1960
1961 fn control_flow_guard(&mut self) {}
1962
1963 fn ehcont_guard(&mut self) {}
1964
1965 fn export_symbols(
1966 &mut self,
1967 _tmpdir: &Path,
1968 _crate_type: CrateType,
1969 _symbols: &[(String, SymbolExportKind)],
1970 ) {
1971 }
1972
1973 fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {}
1974
1975 fn linker_plugin_lto(&mut self) {}
1976}
1977
1978struct LlbcLinker<'a> {
1980 cmd: Command,
1981 sess: &'a Session,
1982}
1983
1984impl<'a> Linker for LlbcLinker<'a> {
1985 fn cmd(&mut self) -> &mut Command {
1986 &mut self.cmd
1987 }
1988
1989 fn set_output_kind(
1990 &mut self,
1991 _output_kind: LinkOutputKind,
1992 _crate_type: CrateType,
1993 _out_filename: &Path,
1994 ) {
1995 }
1996
1997 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1998 panic!("staticlibs not supported")
1999 }
2000
2001 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2002 self.link_or_cc_arg(path);
2003 }
2004
2005 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2006 self.link_arg("--debug");
2007 }
2008
2009 fn optimize(&mut self) {
2010 self.link_arg(match self.sess.opts.optimize {
2011 OptLevel::No => "-O0",
2012 OptLevel::Less => "-O1",
2013 OptLevel::More => "-O2",
2014 OptLevel::Aggressive => "-O3",
2015 OptLevel::Size => "-Os",
2016 OptLevel::SizeMin => "-Oz",
2017 });
2018 }
2019
2020 fn full_relro(&mut self) {}
2021
2022 fn partial_relro(&mut self) {}
2023
2024 fn no_relro(&mut self) {}
2025
2026 fn gc_sections(&mut self, _keep_metadata: bool) {}
2027
2028 fn pgo_gen(&mut self) {}
2029
2030 fn no_crt_objects(&mut self) {}
2031
2032 fn no_default_libraries(&mut self) {}
2033
2034 fn control_flow_guard(&mut self) {}
2035
2036 fn ehcont_guard(&mut self) {}
2037
2038 fn export_symbols(
2039 &mut self,
2040 _tmpdir: &Path,
2041 _crate_type: CrateType,
2042 symbols: &[(String, SymbolExportKind)],
2043 ) {
2044 match _crate_type {
2045 CrateType::Cdylib => {
2046 for (sym, _) in symbols {
2047 self.link_args(&["--export-symbol", sym]);
2048 }
2049 }
2050 _ => (),
2051 }
2052 }
2053
2054 fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {}
2055
2056 fn linker_plugin_lto(&mut self) {}
2057}
2058
2059struct BpfLinker<'a> {
2060 cmd: Command,
2061 sess: &'a Session,
2062}
2063
2064impl<'a> Linker for BpfLinker<'a> {
2065 fn cmd(&mut self) -> &mut Command {
2066 &mut self.cmd
2067 }
2068
2069 fn set_output_kind(
2070 &mut self,
2071 _output_kind: LinkOutputKind,
2072 _crate_type: CrateType,
2073 _out_filename: &Path,
2074 ) {
2075 }
2076
2077 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2078 panic!("staticlibs not supported")
2079 }
2080
2081 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2082 self.link_or_cc_arg(path);
2083 }
2084
2085 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2086 self.link_arg("--debug");
2087 }
2088
2089 fn optimize(&mut self) {
2090 self.link_arg(match self.sess.opts.optimize {
2091 OptLevel::No => "-O0",
2092 OptLevel::Less => "-O1",
2093 OptLevel::More => "-O2",
2094 OptLevel::Aggressive => "-O3",
2095 OptLevel::Size => "-Os",
2096 OptLevel::SizeMin => "-Oz",
2097 });
2098 }
2099
2100 fn full_relro(&mut self) {}
2101
2102 fn partial_relro(&mut self) {}
2103
2104 fn no_relro(&mut self) {}
2105
2106 fn gc_sections(&mut self, _keep_metadata: bool) {}
2107
2108 fn pgo_gen(&mut self) {}
2109
2110 fn no_crt_objects(&mut self) {}
2111
2112 fn no_default_libraries(&mut self) {}
2113
2114 fn control_flow_guard(&mut self) {}
2115
2116 fn ehcont_guard(&mut self) {}
2117
2118 fn export_symbols(
2119 &mut self,
2120 tmpdir: &Path,
2121 _crate_type: CrateType,
2122 symbols: &[(String, SymbolExportKind)],
2123 ) {
2124 let path = tmpdir.join("symbols");
2125 let res: io::Result<()> = try {
2126 let mut f = File::create_buffered(&path)?;
2127 for (sym, _) in symbols {
2128 writeln!(f, "{sym}")?;
2129 }
2130 };
2131 if let Err(error) = res {
2132 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2133 } else {
2134 self.link_arg("--export-symbols").link_arg(&path);
2135 }
2136 }
2137
2138 fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {}
2139
2140 fn linker_plugin_lto(&mut self) {}
2141}