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 full_relro(&mut self);
330 fn partial_relro(&mut self);
331 fn no_relro(&mut self);
332 fn optimize(&mut self);
333 fn pgo_gen(&mut self);
334 fn control_flow_guard(&mut self);
335 fn ehcont_guard(&mut self);
336 fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
337 fn no_crt_objects(&mut self);
338 fn no_default_libraries(&mut self);
339 fn export_symbols(
340 &mut self,
341 tmpdir: &Path,
342 crate_type: CrateType,
343 symbols: &[(String, SymbolExportKind)],
344 );
345 fn subsystem(&mut self, subsystem: &str);
346 fn linker_plugin_lto(&mut self);
347 fn add_eh_frame_header(&mut self) {}
348 fn add_no_exec(&mut self) {}
349 fn add_as_needed(&mut self) {}
350 fn reset_per_library_state(&mut self) {}
351}
352
353impl dyn Linker + '_ {
354 pub(crate) fn take_cmd(&mut self) -> Command {
355 mem::replace(self.cmd(), Command::new(""))
356 }
357}
358
359struct GccLinker<'a> {
360 cmd: Command,
361 sess: &'a Session,
362 target_cpu: &'a str,
363 hinted_static: Option<bool>, is_ld: bool,
366 is_gnu: bool,
367 uses_lld: bool,
368}
369
370impl<'a> GccLinker<'a> {
371 fn takes_hints(&self) -> bool {
372 !self.sess.target.is_like_darwin && !self.sess.target.is_like_wasm
381 }
382
383 fn hint_static(&mut self) {
388 if !self.takes_hints() {
389 return;
390 }
391 if self.hinted_static != Some(true) {
392 self.link_arg("-Bstatic");
393 self.hinted_static = Some(true);
394 }
395 }
396
397 fn hint_dynamic(&mut self) {
398 if !self.takes_hints() {
399 return;
400 }
401 if self.hinted_static != Some(false) {
402 self.link_arg("-Bdynamic");
403 self.hinted_static = Some(false);
404 }
405 }
406
407 fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
408 if let Some(plugin_path) = plugin_path {
409 let mut arg = OsString::from("-plugin=");
410 arg.push(plugin_path);
411 self.link_arg(&arg);
412 }
413
414 let opt_level = match self.sess.opts.optimize {
415 config::OptLevel::No => "O0",
416 config::OptLevel::Less => "O1",
417 config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
418 config::OptLevel::Aggressive => "O3",
419 };
420
421 if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
422 self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
423 };
424 self.link_args(&[
425 &format!("-plugin-opt={opt_level}"),
426 &format!("-plugin-opt=mcpu={}", self.target_cpu),
427 ]);
428 }
429
430 fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
431 if self.sess.target.is_like_darwin {
433 if self.is_cc() {
434 self.cc_arg("-dynamiclib");
436 } else {
437 self.link_arg("-dylib");
438 }
440
441 if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
446 let mut rpath = OsString::from("@rpath/");
447 rpath.push(out_filename.file_name().unwrap());
448 self.link_arg("-install_name").link_arg(rpath);
449 }
450 } else {
451 self.link_or_cc_arg("-shared");
452 if let Some(name) = out_filename.file_name() {
453 if self.sess.target.is_like_windows {
454 let (prefix, suffix) = self.sess.staticlib_components(false);
458 let mut implib_name = OsString::from(prefix);
459 implib_name.push(name);
460 implib_name.push(suffix);
461 let mut out_implib = OsString::from("--out-implib=");
462 out_implib.push(out_filename.with_file_name(implib_name));
463 self.link_arg(out_implib);
464 } else if crate_type == CrateType::Dylib {
465 let mut soname = OsString::from("-soname=");
469 soname.push(name);
470 self.link_arg(soname);
471 }
472 }
473 }
474 }
475
476 fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
477 if !as_needed {
478 if self.sess.target.is_like_darwin {
479 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
483 } else if self.is_gnu && !self.sess.target.is_like_windows {
484 self.link_arg("--no-as-needed");
485 } else {
486 self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
487 }
488 }
489
490 f(self);
491
492 if !as_needed {
493 if self.sess.target.is_like_darwin {
494 } else if self.is_gnu && !self.sess.target.is_like_windows {
496 self.link_arg("--as-needed");
497 }
498 }
499 }
500}
501
502impl<'a> Linker for GccLinker<'a> {
503 fn cmd(&mut self) -> &mut Command {
504 &mut self.cmd
505 }
506
507 fn is_cc(&self) -> bool {
508 !self.is_ld
509 }
510
511 fn set_output_kind(
512 &mut self,
513 output_kind: LinkOutputKind,
514 crate_type: CrateType,
515 out_filename: &Path,
516 ) {
517 match output_kind {
518 LinkOutputKind::DynamicNoPicExe => {
519 if !self.is_ld && self.is_gnu {
520 self.cc_arg("-no-pie");
521 }
522 }
523 LinkOutputKind::DynamicPicExe => {
524 if !self.sess.target.is_like_windows {
526 self.link_or_cc_arg("-pie");
528 }
529 }
530 LinkOutputKind::StaticNoPicExe => {
531 self.link_or_cc_arg("-static");
533 if !self.is_ld && self.is_gnu {
534 self.cc_arg("-no-pie");
535 }
536 }
537 LinkOutputKind::StaticPicExe => {
538 if !self.is_ld {
539 self.cc_arg("-static-pie");
542 } else {
543 self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
549 }
550 }
551 LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
552 LinkOutputKind::StaticDylib => {
553 self.link_or_cc_arg("-static");
554 self.build_dylib(crate_type, out_filename);
555 }
556 LinkOutputKind::WasiReactorExe => {
557 self.link_args(&["--entry", "_initialize"]);
558 }
559 }
560
561 if self.sess.target.os == "vxworks"
567 && matches!(
568 output_kind,
569 LinkOutputKind::StaticNoPicExe
570 | LinkOutputKind::StaticPicExe
571 | LinkOutputKind::StaticDylib
572 )
573 {
574 self.cc_arg("--static-crt");
575 }
576
577 if self.sess.target.arch == "avr" && !self.uses_lld {
583 self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
584 }
585 }
586
587 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
588 if self.sess.target.os == "illumos" && name == "c" {
589 return;
595 }
596 self.hint_dynamic();
597 self.with_as_needed(as_needed, |this| {
598 let colon = if verbatim && this.is_gnu { ":" } else { "" };
599 this.link_or_cc_arg(format!("-l{colon}{name}"));
600 });
601 }
602
603 fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
604 self.hint_dynamic();
605 self.with_as_needed(as_needed, |this| {
606 this.link_or_cc_arg(path);
607 })
608 }
609
610 fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
611 self.hint_dynamic();
612 if !as_needed {
613 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
617 }
618 self.link_or_cc_args(&["-framework", name]);
619 }
620
621 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
622 self.hint_static();
623 let colon = if verbatim && self.is_gnu { ":" } else { "" };
624 if !whole_archive {
625 self.link_or_cc_arg(format!("-l{colon}{name}"));
626 } else if self.sess.target.is_like_darwin {
627 self.link_arg("-force_load");
630 self.link_arg(find_native_static_library(name, verbatim, self.sess));
631 } else {
632 self.link_arg("--whole-archive")
633 .link_or_cc_arg(format!("-l{colon}{name}"))
634 .link_arg("--no-whole-archive");
635 }
636 }
637
638 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
639 self.hint_static();
640 if !whole_archive {
641 self.link_or_cc_arg(path);
642 } else if self.sess.target.is_like_darwin {
643 self.link_arg("-force_load").link_arg(path);
644 } else {
645 self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
646 }
647 }
648
649 fn framework_path(&mut self, path: &Path) {
650 self.link_or_cc_arg("-F").link_or_cc_arg(path);
651 }
652 fn full_relro(&mut self) {
653 self.link_args(&["-z", "relro", "-z", "now"]);
654 }
655 fn partial_relro(&mut self) {
656 self.link_args(&["-z", "relro"]);
657 }
658 fn no_relro(&mut self) {
659 self.link_args(&["-z", "norelro"]);
660 }
661
662 fn gc_sections(&mut self, keep_metadata: bool) {
663 if self.sess.target.is_like_darwin {
678 self.link_arg("-dead_strip");
679
680 } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
686 self.link_arg("--gc-sections");
687 }
688 }
689
690 fn optimize(&mut self) {
691 if !self.is_gnu && !self.sess.target.is_like_wasm {
692 return;
693 }
694
695 if self.sess.opts.optimize == config::OptLevel::More
698 || self.sess.opts.optimize == config::OptLevel::Aggressive
699 {
700 self.link_arg("-O1");
701 }
702 }
703
704 fn pgo_gen(&mut self) {
705 if !self.is_gnu {
706 return;
707 }
708
709 self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
721 }
722
723 fn control_flow_guard(&mut self) {}
724
725 fn ehcont_guard(&mut self) {}
726
727 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
728 if self.sess.target.is_like_darwin {
730 return;
731 }
732
733 match strip {
734 Strip::None => {}
735 Strip::Debuginfo => {
736 if !self.sess.target.is_like_solaris {
741 self.link_arg("--strip-debug");
742 }
743 }
744 Strip::Symbols => {
745 self.link_arg("--strip-all");
746 }
747 }
748 match self.sess.opts.unstable_opts.debuginfo_compression {
749 config::DebugInfoCompression::None => {}
750 config::DebugInfoCompression::Zlib => {
751 self.link_arg("--compress-debug-sections=zlib");
752 }
753 config::DebugInfoCompression::Zstd => {
754 self.link_arg("--compress-debug-sections=zstd");
755 }
756 }
757 }
758
759 fn no_crt_objects(&mut self) {
760 if !self.is_ld {
761 self.cc_arg("-nostartfiles");
762 }
763 }
764
765 fn no_default_libraries(&mut self) {
766 if !self.is_ld {
767 self.cc_arg("-nodefaultlibs");
768 }
769 }
770
771 fn export_symbols(
772 &mut self,
773 tmpdir: &Path,
774 crate_type: CrateType,
775 symbols: &[(String, SymbolExportKind)],
776 ) {
777 if crate_type == CrateType::Executable {
779 let should_export_executable_symbols =
780 self.sess.opts.unstable_opts.export_executable_symbols;
781 if self.sess.target.override_export_symbols.is_none()
782 && !should_export_executable_symbols
783 {
784 return;
785 }
786 }
787
788 if !self.sess.target.limit_rdylib_exports {
793 return;
794 }
795
796 let path = tmpdir.join(if self.sess.target.is_like_windows { "list.def" } else { "list" });
797 debug!("EXPORTED SYMBOLS:");
798
799 if self.sess.target.is_like_darwin {
800 let res: io::Result<()> = try {
802 let mut f = File::create_buffered(&path)?;
803 for (sym, _) in symbols {
804 debug!(" _{sym}");
805 writeln!(f, "_{sym}")?;
806 }
807 };
808 if let Err(error) = res {
809 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
810 }
811 self.link_arg("-exported_symbols_list").link_arg(path);
812 } else if self.sess.target.is_like_windows {
813 let res: io::Result<()> = try {
814 let mut f = File::create_buffered(&path)?;
815
816 writeln!(f, "EXPORTS")?;
819 for (symbol, kind) in symbols {
820 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
821 debug!(" _{symbol}");
822 writeln!(f, " \"{symbol}\"{kind_marker}")?;
825 }
826 };
827 if let Err(error) = res {
828 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
829 }
830 self.link_arg(path);
831 } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
832 let res: io::Result<()> = try {
833 let mut f = File::create_buffered(&path)?;
834 writeln!(f, "{{")?;
835 for (sym, _) in symbols {
836 debug!(sym);
837 writeln!(f, " {sym};")?;
838 }
839 writeln!(f, "}};")?;
840 };
841 if let Err(error) = res {
842 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
843 }
844 self.link_arg("--dynamic-list").link_arg(path);
845 } else {
846 let res: io::Result<()> = try {
848 let mut f = File::create_buffered(&path)?;
849 writeln!(f, "{{")?;
850 if !symbols.is_empty() {
851 writeln!(f, " global:")?;
852 for (sym, _) in symbols {
853 debug!(" {sym};");
854 writeln!(f, " {sym};")?;
855 }
856 }
857 writeln!(f, "\n local:\n *;\n}};")?;
858 };
859 if let Err(error) = res {
860 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
861 }
862 if self.sess.target.is_like_solaris {
863 self.link_arg("-M").link_arg(path);
864 } else {
865 let mut arg = OsString::from("--version-script=");
866 arg.push(path);
867 self.link_arg(arg).link_arg("--no-undefined-version");
868 }
869 }
870 }
871
872 fn subsystem(&mut self, subsystem: &str) {
873 self.link_args(&["--subsystem", subsystem]);
874 }
875
876 fn reset_per_library_state(&mut self) {
877 self.hint_dynamic(); }
879
880 fn linker_plugin_lto(&mut self) {
881 match self.sess.opts.cg.linker_plugin_lto {
882 LinkerPluginLto::Disabled => {
883 }
885 LinkerPluginLto::LinkerPluginAuto => {
886 self.push_linker_plugin_lto_args(None);
887 }
888 LinkerPluginLto::LinkerPlugin(ref path) => {
889 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
890 }
891 }
892 }
893
894 fn add_eh_frame_header(&mut self) {
898 self.link_arg("--eh-frame-hdr");
899 }
900
901 fn add_no_exec(&mut self) {
902 if self.sess.target.is_like_windows {
903 self.link_arg("--nxcompat");
904 } else if self.is_gnu {
905 self.link_args(&["-z", "noexecstack"]);
906 }
907 }
908
909 fn add_as_needed(&mut self) {
910 if self.is_gnu && !self.sess.target.is_like_windows {
911 self.link_arg("--as-needed");
912 } else if self.sess.target.is_like_solaris {
913 self.link_args(&["-z", "ignore"]);
915 }
916 }
917}
918
919struct MsvcLinker<'a> {
920 cmd: Command,
921 sess: &'a Session,
922}
923
924impl<'a> Linker for MsvcLinker<'a> {
925 fn cmd(&mut self) -> &mut Command {
926 &mut self.cmd
927 }
928
929 fn set_output_kind(
930 &mut self,
931 output_kind: LinkOutputKind,
932 _crate_type: CrateType,
933 out_filename: &Path,
934 ) {
935 match output_kind {
936 LinkOutputKind::DynamicNoPicExe
937 | LinkOutputKind::DynamicPicExe
938 | LinkOutputKind::StaticNoPicExe
939 | LinkOutputKind::StaticPicExe => {}
940 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
941 self.link_arg("/DLL");
942 let mut arg: OsString = "/IMPLIB:".into();
943 arg.push(out_filename.with_extension("dll.lib"));
944 self.link_arg(arg);
945 }
946 LinkOutputKind::WasiReactorExe => {
947 panic!("can't link as reactor on non-wasi target");
948 }
949 }
950 }
951
952 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
953 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
956 self.link_arg(path);
957 } else {
958 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
959 }
960 }
961
962 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
963 let implib_path = path.with_extension("dll.lib");
966 if implib_path.exists() {
967 self.link_or_cc_arg(implib_path);
968 }
969 }
970
971 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
972 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
975 self.link_staticlib_by_path(&path, whole_archive);
976 } else {
977 let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
978 let (prefix, suffix) = self.sess.staticlib_components(verbatim);
979 self.link_arg(format!("{opts}{prefix}{name}{suffix}"));
980 }
981 }
982
983 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
984 if !whole_archive {
985 self.link_arg(path);
986 } else {
987 let mut arg = OsString::from("/WHOLEARCHIVE:");
988 arg.push(path);
989 self.link_arg(arg);
990 }
991 }
992
993 fn gc_sections(&mut self, _keep_metadata: bool) {
994 if self.sess.opts.optimize != config::OptLevel::No {
998 self.link_arg("/OPT:REF,ICF");
999 } else {
1000 self.link_arg("/OPT:REF,NOICF");
1003 }
1004 }
1005
1006 fn full_relro(&mut self) {
1007 }
1009
1010 fn partial_relro(&mut self) {
1011 }
1013
1014 fn no_relro(&mut self) {
1015 }
1017
1018 fn no_crt_objects(&mut self) {
1019 }
1021
1022 fn no_default_libraries(&mut self) {
1023 self.link_arg("/NODEFAULTLIB");
1024 }
1025
1026 fn include_path(&mut self, path: &Path) {
1027 let mut arg = OsString::from("/LIBPATH:");
1028 arg.push(path);
1029 self.link_arg(&arg);
1030 }
1031
1032 fn output_filename(&mut self, path: &Path) {
1033 let mut arg = OsString::from("/OUT:");
1034 arg.push(path);
1035 self.link_arg(&arg);
1036 }
1037
1038 fn optimize(&mut self) {
1039 }
1041
1042 fn pgo_gen(&mut self) {
1043 }
1045
1046 fn control_flow_guard(&mut self) {
1047 self.link_arg("/guard:cf");
1048 }
1049
1050 fn ehcont_guard(&mut self) {
1051 if self.sess.target.pointer_width == 64 {
1052 self.link_arg("/guard:ehcont");
1053 }
1054 }
1055
1056 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1057 self.link_arg("/DEBUG");
1060
1061 self.link_arg("/PDBALTPATH:%_PDB%");
1069
1070 let natvis_dir_path = self.sess.opts.sysroot.path().join("lib\\rustlib\\etc");
1072 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1073 for entry in natvis_dir {
1074 match entry {
1075 Ok(entry) => {
1076 let path = entry.path();
1077 if path.extension() == Some("natvis".as_ref()) {
1078 let mut arg = OsString::from("/NATVIS:");
1079 arg.push(path);
1080 self.link_arg(arg);
1081 }
1082 }
1083 Err(error) => {
1084 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1085 }
1086 }
1087 }
1088 }
1089
1090 for path in natvis_debugger_visualizers {
1092 let mut arg = OsString::from("/NATVIS:");
1093 arg.push(path);
1094 self.link_arg(arg);
1095 }
1096 }
1097
1098 fn export_symbols(
1111 &mut self,
1112 tmpdir: &Path,
1113 crate_type: CrateType,
1114 symbols: &[(String, SymbolExportKind)],
1115 ) {
1116 if crate_type == CrateType::Executable {
1118 let should_export_executable_symbols =
1119 self.sess.opts.unstable_opts.export_executable_symbols;
1120 if !should_export_executable_symbols {
1121 return;
1122 }
1123 }
1124
1125 let path = tmpdir.join("lib.def");
1126 let res: io::Result<()> = try {
1127 let mut f = File::create_buffered(&path)?;
1128
1129 writeln!(f, "LIBRARY")?;
1132 writeln!(f, "EXPORTS")?;
1133 for (symbol, kind) in symbols {
1134 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
1135 debug!(" _{symbol}");
1136 writeln!(f, " {symbol}{kind_marker}")?;
1137 }
1138 };
1139 if let Err(error) = res {
1140 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1141 }
1142 let mut arg = OsString::from("/DEF:");
1143 arg.push(path);
1144 self.link_arg(&arg);
1145 }
1146
1147 fn subsystem(&mut self, subsystem: &str) {
1148 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1151
1152 if subsystem == "windows" {
1167 self.link_arg("/ENTRY:mainCRTStartup");
1168 }
1169 }
1170
1171 fn linker_plugin_lto(&mut self) {
1172 }
1174
1175 fn add_no_exec(&mut self) {
1176 self.link_arg("/NXCOMPAT");
1177 }
1178}
1179
1180struct EmLinker<'a> {
1181 cmd: Command,
1182 sess: &'a Session,
1183}
1184
1185impl<'a> Linker for EmLinker<'a> {
1186 fn cmd(&mut self) -> &mut Command {
1187 &mut self.cmd
1188 }
1189
1190 fn is_cc(&self) -> bool {
1191 true
1192 }
1193
1194 fn set_output_kind(
1195 &mut self,
1196 _output_kind: LinkOutputKind,
1197 _crate_type: CrateType,
1198 _out_filename: &Path,
1199 ) {
1200 }
1201
1202 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1203 self.link_or_cc_args(&["-l", name]);
1205 }
1206
1207 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1208 self.link_or_cc_arg(path);
1209 }
1210
1211 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1212 self.link_or_cc_args(&["-l", name]);
1213 }
1214
1215 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1216 self.link_or_cc_arg(path);
1217 }
1218
1219 fn full_relro(&mut self) {
1220 }
1222
1223 fn partial_relro(&mut self) {
1224 }
1226
1227 fn no_relro(&mut self) {
1228 }
1230
1231 fn gc_sections(&mut self, _keep_metadata: bool) {
1232 }
1234
1235 fn optimize(&mut self) {
1236 self.cc_arg(match self.sess.opts.optimize {
1238 OptLevel::No => "-O0",
1239 OptLevel::Less => "-O1",
1240 OptLevel::More => "-O2",
1241 OptLevel::Aggressive => "-O3",
1242 OptLevel::Size => "-Os",
1243 OptLevel::SizeMin => "-Oz",
1244 });
1245 }
1246
1247 fn pgo_gen(&mut self) {
1248 }
1250
1251 fn control_flow_guard(&mut self) {}
1252
1253 fn ehcont_guard(&mut self) {}
1254
1255 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1256 self.cc_arg(match self.sess.opts.debuginfo {
1259 DebugInfo::None => "-g0",
1260 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1261 "--profiling-funcs"
1262 }
1263 DebugInfo::Full => "-g",
1264 });
1265 }
1266
1267 fn no_crt_objects(&mut self) {}
1268
1269 fn no_default_libraries(&mut self) {
1270 self.cc_arg("-nodefaultlibs");
1271 }
1272
1273 fn export_symbols(
1274 &mut self,
1275 _tmpdir: &Path,
1276 _crate_type: CrateType,
1277 symbols: &[(String, SymbolExportKind)],
1278 ) {
1279 debug!("EXPORTED SYMBOLS:");
1280
1281 self.cc_arg("-s");
1282
1283 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1284 let encoded = serde_json::to_string(
1285 &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
1286 )
1287 .unwrap();
1288 debug!("{encoded}");
1289
1290 arg.push(encoded);
1291
1292 self.cc_arg(arg);
1293 }
1294
1295 fn subsystem(&mut self, _subsystem: &str) {
1296 }
1298
1299 fn linker_plugin_lto(&mut self) {
1300 }
1302}
1303
1304struct WasmLd<'a> {
1305 cmd: Command,
1306 sess: &'a Session,
1307}
1308
1309impl<'a> WasmLd<'a> {
1310 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1311 let mut wasm_ld = WasmLd { cmd, sess };
1330 if sess.target_features.contains(&sym::atomics) {
1331 wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1332 if sess.target.os == "unknown" || sess.target.os == "none" {
1333 wasm_ld.link_args(&[
1334 "--export=__wasm_init_tls",
1335 "--export=__tls_size",
1336 "--export=__tls_align",
1337 "--export=__tls_base",
1338 ]);
1339 }
1340 }
1341 wasm_ld
1342 }
1343}
1344
1345impl<'a> Linker for WasmLd<'a> {
1346 fn cmd(&mut self) -> &mut Command {
1347 &mut self.cmd
1348 }
1349
1350 fn set_output_kind(
1351 &mut self,
1352 output_kind: LinkOutputKind,
1353 _crate_type: CrateType,
1354 _out_filename: &Path,
1355 ) {
1356 match output_kind {
1357 LinkOutputKind::DynamicNoPicExe
1358 | LinkOutputKind::DynamicPicExe
1359 | LinkOutputKind::StaticNoPicExe
1360 | LinkOutputKind::StaticPicExe => {}
1361 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1362 self.link_arg("--no-entry");
1363 }
1364 LinkOutputKind::WasiReactorExe => {
1365 self.link_args(&["--entry", "_initialize"]);
1366 }
1367 }
1368 }
1369
1370 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1371 self.link_or_cc_args(&["-l", name]);
1372 }
1373
1374 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1375 self.link_or_cc_arg(path);
1376 }
1377
1378 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1379 if !whole_archive {
1380 self.link_or_cc_args(&["-l", name]);
1381 } else {
1382 self.link_arg("--whole-archive")
1383 .link_or_cc_args(&["-l", name])
1384 .link_arg("--no-whole-archive");
1385 }
1386 }
1387
1388 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1389 if !whole_archive {
1390 self.link_or_cc_arg(path);
1391 } else {
1392 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1393 }
1394 }
1395
1396 fn full_relro(&mut self) {}
1397
1398 fn partial_relro(&mut self) {}
1399
1400 fn no_relro(&mut self) {}
1401
1402 fn gc_sections(&mut self, _keep_metadata: bool) {
1403 self.link_arg("--gc-sections");
1404 }
1405
1406 fn optimize(&mut self) {
1407 self.link_arg(match self.sess.opts.optimize {
1410 OptLevel::No => "-O0",
1411 OptLevel::Less => "-O1",
1412 OptLevel::More => "-O2",
1413 OptLevel::Aggressive => "-O3",
1414 OptLevel::Size => "-O2",
1417 OptLevel::SizeMin => "-O2",
1418 });
1419 }
1420
1421 fn pgo_gen(&mut self) {}
1422
1423 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1424 match strip {
1425 Strip::None => {}
1426 Strip::Debuginfo => {
1427 self.link_arg("--strip-debug");
1428 }
1429 Strip::Symbols => {
1430 self.link_arg("--strip-all");
1431 }
1432 }
1433 }
1434
1435 fn control_flow_guard(&mut self) {}
1436
1437 fn ehcont_guard(&mut self) {}
1438
1439 fn no_crt_objects(&mut self) {}
1440
1441 fn no_default_libraries(&mut self) {}
1442
1443 fn export_symbols(
1444 &mut self,
1445 _tmpdir: &Path,
1446 _crate_type: CrateType,
1447 symbols: &[(String, SymbolExportKind)],
1448 ) {
1449 for (sym, _) in symbols {
1450 self.link_args(&["--export", sym]);
1451 }
1452
1453 if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
1458 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1459 }
1460 }
1461
1462 fn subsystem(&mut self, _subsystem: &str) {}
1463
1464 fn linker_plugin_lto(&mut self) {
1465 match self.sess.opts.cg.linker_plugin_lto {
1466 LinkerPluginLto::Disabled => {
1467 }
1469 LinkerPluginLto::LinkerPluginAuto => {
1470 self.push_linker_plugin_lto_args();
1471 }
1472 LinkerPluginLto::LinkerPlugin(_) => {
1473 self.push_linker_plugin_lto_args();
1474 }
1475 }
1476 }
1477}
1478
1479impl<'a> WasmLd<'a> {
1480 fn push_linker_plugin_lto_args(&mut self) {
1481 let opt_level = match self.sess.opts.optimize {
1482 config::OptLevel::No => "O0",
1483 config::OptLevel::Less => "O1",
1484 config::OptLevel::More => "O2",
1485 config::OptLevel::Aggressive => "O3",
1486 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1488 };
1489 self.link_arg(&format!("--lto-{opt_level}"));
1490 }
1491}
1492
1493struct L4Bender<'a> {
1495 cmd: Command,
1496 sess: &'a Session,
1497 hinted_static: bool,
1498}
1499
1500impl<'a> Linker for L4Bender<'a> {
1501 fn cmd(&mut self) -> &mut Command {
1502 &mut self.cmd
1503 }
1504
1505 fn set_output_kind(
1506 &mut self,
1507 _output_kind: LinkOutputKind,
1508 _crate_type: CrateType,
1509 _out_filename: &Path,
1510 ) {
1511 }
1512
1513 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1514 self.hint_static();
1515 if !whole_archive {
1516 self.link_arg(format!("-PC{name}"));
1517 } else {
1518 self.link_arg("--whole-archive")
1519 .link_or_cc_arg(format!("-l{name}"))
1520 .link_arg("--no-whole-archive");
1521 }
1522 }
1523
1524 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1525 self.hint_static();
1526 if !whole_archive {
1527 self.link_or_cc_arg(path);
1528 } else {
1529 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1530 }
1531 }
1532
1533 fn full_relro(&mut self) {
1534 self.link_args(&["-z", "relro", "-z", "now"]);
1535 }
1536
1537 fn partial_relro(&mut self) {
1538 self.link_args(&["-z", "relro"]);
1539 }
1540
1541 fn no_relro(&mut self) {
1542 self.link_args(&["-z", "norelro"]);
1543 }
1544
1545 fn gc_sections(&mut self, keep_metadata: bool) {
1546 if !keep_metadata {
1547 self.link_arg("--gc-sections");
1548 }
1549 }
1550
1551 fn optimize(&mut self) {
1552 if self.sess.opts.optimize == config::OptLevel::More
1555 || self.sess.opts.optimize == config::OptLevel::Aggressive
1556 {
1557 self.link_arg("-O1");
1558 }
1559 }
1560
1561 fn pgo_gen(&mut self) {}
1562
1563 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1564 match strip {
1565 Strip::None => {}
1566 Strip::Debuginfo => {
1567 self.link_arg("--strip-debug");
1568 }
1569 Strip::Symbols => {
1570 self.link_arg("--strip-all");
1571 }
1572 }
1573 }
1574
1575 fn no_default_libraries(&mut self) {
1576 self.cc_arg("-nostdlib");
1577 }
1578
1579 fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
1580 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1582 }
1583
1584 fn subsystem(&mut self, subsystem: &str) {
1585 self.link_arg(&format!("--subsystem {subsystem}"));
1586 }
1587
1588 fn reset_per_library_state(&mut self) {
1589 self.hint_static(); }
1591
1592 fn linker_plugin_lto(&mut self) {}
1593
1594 fn control_flow_guard(&mut self) {}
1595
1596 fn ehcont_guard(&mut self) {}
1597
1598 fn no_crt_objects(&mut self) {}
1599}
1600
1601impl<'a> L4Bender<'a> {
1602 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1603 L4Bender { cmd, sess, hinted_static: false }
1604 }
1605
1606 fn hint_static(&mut self) {
1607 if !self.hinted_static {
1608 self.link_or_cc_arg("-static");
1609 self.hinted_static = true;
1610 }
1611 }
1612}
1613
1614struct AixLinker<'a> {
1616 cmd: Command,
1617 sess: &'a Session,
1618 hinted_static: Option<bool>,
1619}
1620
1621impl<'a> AixLinker<'a> {
1622 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1623 AixLinker { cmd, sess, hinted_static: None }
1624 }
1625
1626 fn hint_static(&mut self) {
1627 if self.hinted_static != Some(true) {
1628 self.link_arg("-bstatic");
1629 self.hinted_static = Some(true);
1630 }
1631 }
1632
1633 fn hint_dynamic(&mut self) {
1634 if self.hinted_static != Some(false) {
1635 self.link_arg("-bdynamic");
1636 self.hinted_static = Some(false);
1637 }
1638 }
1639
1640 fn build_dylib(&mut self, _out_filename: &Path) {
1641 self.link_args(&["-bM:SRE", "-bnoentry"]);
1642 self.link_arg("-bexpfull");
1645 }
1646}
1647
1648impl<'a> Linker for AixLinker<'a> {
1649 fn cmd(&mut self) -> &mut Command {
1650 &mut self.cmd
1651 }
1652
1653 fn set_output_kind(
1654 &mut self,
1655 output_kind: LinkOutputKind,
1656 _crate_type: CrateType,
1657 out_filename: &Path,
1658 ) {
1659 match output_kind {
1660 LinkOutputKind::DynamicDylib => {
1661 self.hint_dynamic();
1662 self.build_dylib(out_filename);
1663 }
1664 LinkOutputKind::StaticDylib => {
1665 self.hint_static();
1666 self.build_dylib(out_filename);
1667 }
1668 _ => {}
1669 }
1670 }
1671
1672 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1673 self.hint_dynamic();
1674 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1675 }
1676
1677 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1678 self.hint_dynamic();
1679 self.link_or_cc_arg(path);
1680 }
1681
1682 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1683 self.hint_static();
1684 if !whole_archive {
1685 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1686 } else {
1687 let mut arg = OsString::from("-bkeepfile:");
1688 arg.push(find_native_static_library(name, verbatim, self.sess));
1689 self.link_or_cc_arg(arg);
1690 }
1691 }
1692
1693 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1694 self.hint_static();
1695 if !whole_archive {
1696 self.link_or_cc_arg(path);
1697 } else {
1698 let mut arg = OsString::from("-bkeepfile:");
1699 arg.push(path);
1700 self.link_arg(arg);
1701 }
1702 }
1703
1704 fn full_relro(&mut self) {}
1705
1706 fn partial_relro(&mut self) {}
1707
1708 fn no_relro(&mut self) {}
1709
1710 fn gc_sections(&mut self, _keep_metadata: bool) {
1711 self.link_arg("-bgc");
1712 }
1713
1714 fn optimize(&mut self) {}
1715
1716 fn pgo_gen(&mut self) {
1717 self.link_arg("-bdbg:namedsects:ss");
1718 self.link_arg("-u");
1719 self.link_arg("__llvm_profile_runtime");
1720 }
1721
1722 fn control_flow_guard(&mut self) {}
1723
1724 fn ehcont_guard(&mut self) {}
1725
1726 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1727
1728 fn no_crt_objects(&mut self) {}
1729
1730 fn no_default_libraries(&mut self) {}
1731
1732 fn export_symbols(
1733 &mut self,
1734 tmpdir: &Path,
1735 _crate_type: CrateType,
1736 symbols: &[(String, SymbolExportKind)],
1737 ) {
1738 let path = tmpdir.join("list.exp");
1739 let res: io::Result<()> = try {
1740 let mut f = File::create_buffered(&path)?;
1741 for (symbol, _) in symbols {
1743 debug!(" _{symbol}");
1744 writeln!(f, " {symbol}")?;
1745 }
1746 };
1747 if let Err(e) = res {
1748 self.sess.dcx().fatal(format!("failed to write export file: {e}"));
1749 }
1750 self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
1751 }
1752
1753 fn subsystem(&mut self, _subsystem: &str) {}
1754
1755 fn reset_per_library_state(&mut self) {
1756 self.hint_dynamic();
1757 }
1758
1759 fn linker_plugin_lto(&mut self) {}
1760
1761 fn add_eh_frame_header(&mut self) {}
1762
1763 fn add_no_exec(&mut self) {}
1764
1765 fn add_as_needed(&mut self) {}
1766}
1767
1768fn for_each_exported_symbols_include_dep<'tcx>(
1769 tcx: TyCtxt<'tcx>,
1770 crate_type: CrateType,
1771 mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
1772) {
1773 let formats = tcx.dependency_formats(());
1774 let deps = &formats[&crate_type];
1775
1776 for (cnum, dep_format) in deps.iter_enumerated() {
1777 if *dep_format == Linkage::Static {
1779 for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() {
1780 callback(symbol, info, cnum);
1781 }
1782 for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() {
1783 callback(symbol, info, cnum);
1784 }
1785 }
1786 }
1787}
1788
1789pub(crate) fn exported_symbols(
1790 tcx: TyCtxt<'_>,
1791 crate_type: CrateType,
1792) -> Vec<(String, SymbolExportKind)> {
1793 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1794 return exports
1795 .iter()
1796 .map(|name| {
1797 (
1798 name.to_string(),
1799 SymbolExportKind::Text,
1803 )
1804 })
1805 .collect();
1806 }
1807
1808 if let CrateType::ProcMacro = crate_type {
1809 exported_symbols_for_proc_macro_crate(tcx)
1810 } else {
1811 exported_symbols_for_non_proc_macro(tcx, crate_type)
1812 }
1813}
1814
1815fn exported_symbols_for_non_proc_macro(
1816 tcx: TyCtxt<'_>,
1817 crate_type: CrateType,
1818) -> Vec<(String, SymbolExportKind)> {
1819 let mut symbols = Vec::new();
1820 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1821 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1822 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1826 symbols.push((
1827 symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1828 info.kind,
1829 ));
1830 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1831 }
1832 });
1833
1834 symbols
1835}
1836
1837fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
1838 if !tcx.sess.opts.output_types.should_codegen() {
1840 return Vec::new();
1841 }
1842
1843 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1844 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1845 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1846
1847 vec![
1848 (proc_macro_decls_name, SymbolExportKind::Data),
1849 (metadata_symbol_name, SymbolExportKind::Data),
1850 ]
1851}
1852
1853pub(crate) fn linked_symbols(
1854 tcx: TyCtxt<'_>,
1855 crate_type: CrateType,
1856) -> Vec<(String, SymbolExportKind)> {
1857 match crate_type {
1858 CrateType::Executable
1859 | CrateType::ProcMacro
1860 | CrateType::Cdylib
1861 | CrateType::Dylib
1862 | CrateType::Sdylib => (),
1863 CrateType::Staticlib | CrateType::Rlib => {
1864 return Vec::new();
1866 }
1867 }
1868
1869 match tcx.sess.lto() {
1870 Lto::No | Lto::ThinLocal => {}
1871 Lto::Thin | Lto::Fat => {
1872 return Vec::new();
1881 }
1882 }
1883
1884 let mut symbols = Vec::new();
1885
1886 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1887 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1888 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
1889 || info.used
1890 || info.rustc_std_internal_symbol
1891 {
1892 symbols.push((
1893 symbol_export::linking_symbol_name_for_instance_in_crate(
1894 tcx, symbol, info.kind, cnum,
1895 ),
1896 info.kind,
1897 ));
1898 }
1899 });
1900
1901 symbols
1902}
1903
1904struct PtxLinker<'a> {
1907 cmd: Command,
1908 sess: &'a Session,
1909}
1910
1911impl<'a> Linker for PtxLinker<'a> {
1912 fn cmd(&mut self) -> &mut Command {
1913 &mut self.cmd
1914 }
1915
1916 fn set_output_kind(
1917 &mut self,
1918 _output_kind: LinkOutputKind,
1919 _crate_type: CrateType,
1920 _out_filename: &Path,
1921 ) {
1922 }
1923
1924 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1925 panic!("staticlibs not supported")
1926 }
1927
1928 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1929 self.link_arg("--rlib").link_arg(path);
1930 }
1931
1932 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1933 self.link_arg("--debug");
1934 }
1935
1936 fn add_object(&mut self, path: &Path) {
1937 self.link_arg("--bitcode").link_arg(path);
1938 }
1939
1940 fn optimize(&mut self) {
1941 match self.sess.lto() {
1942 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1943 self.link_arg("-Olto");
1944 }
1945
1946 Lto::No => {}
1947 }
1948 }
1949
1950 fn full_relro(&mut self) {}
1951
1952 fn partial_relro(&mut self) {}
1953
1954 fn no_relro(&mut self) {}
1955
1956 fn gc_sections(&mut self, _keep_metadata: bool) {}
1957
1958 fn pgo_gen(&mut self) {}
1959
1960 fn no_crt_objects(&mut self) {}
1961
1962 fn no_default_libraries(&mut self) {}
1963
1964 fn control_flow_guard(&mut self) {}
1965
1966 fn ehcont_guard(&mut self) {}
1967
1968 fn export_symbols(
1969 &mut self,
1970 _tmpdir: &Path,
1971 _crate_type: CrateType,
1972 _symbols: &[(String, SymbolExportKind)],
1973 ) {
1974 }
1975
1976 fn subsystem(&mut self, _subsystem: &str) {}
1977
1978 fn linker_plugin_lto(&mut self) {}
1979}
1980
1981struct LlbcLinker<'a> {
1983 cmd: Command,
1984 sess: &'a Session,
1985}
1986
1987impl<'a> Linker for LlbcLinker<'a> {
1988 fn cmd(&mut self) -> &mut Command {
1989 &mut self.cmd
1990 }
1991
1992 fn set_output_kind(
1993 &mut self,
1994 _output_kind: LinkOutputKind,
1995 _crate_type: CrateType,
1996 _out_filename: &Path,
1997 ) {
1998 }
1999
2000 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2001 panic!("staticlibs not supported")
2002 }
2003
2004 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2005 self.link_or_cc_arg(path);
2006 }
2007
2008 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2009 self.link_arg("--debug");
2010 }
2011
2012 fn optimize(&mut self) {
2013 self.link_arg(match self.sess.opts.optimize {
2014 OptLevel::No => "-O0",
2015 OptLevel::Less => "-O1",
2016 OptLevel::More => "-O2",
2017 OptLevel::Aggressive => "-O3",
2018 OptLevel::Size => "-Os",
2019 OptLevel::SizeMin => "-Oz",
2020 });
2021 }
2022
2023 fn full_relro(&mut self) {}
2024
2025 fn partial_relro(&mut self) {}
2026
2027 fn no_relro(&mut self) {}
2028
2029 fn gc_sections(&mut self, _keep_metadata: bool) {}
2030
2031 fn pgo_gen(&mut self) {}
2032
2033 fn no_crt_objects(&mut self) {}
2034
2035 fn no_default_libraries(&mut self) {}
2036
2037 fn control_flow_guard(&mut self) {}
2038
2039 fn ehcont_guard(&mut self) {}
2040
2041 fn export_symbols(
2042 &mut self,
2043 _tmpdir: &Path,
2044 _crate_type: CrateType,
2045 symbols: &[(String, SymbolExportKind)],
2046 ) {
2047 match _crate_type {
2048 CrateType::Cdylib => {
2049 for (sym, _) in symbols {
2050 self.link_args(&["--export-symbol", sym]);
2051 }
2052 }
2053 _ => (),
2054 }
2055 }
2056
2057 fn subsystem(&mut self, _subsystem: &str) {}
2058
2059 fn linker_plugin_lto(&mut self) {}
2060}
2061
2062struct BpfLinker<'a> {
2063 cmd: Command,
2064 sess: &'a Session,
2065}
2066
2067impl<'a> Linker for BpfLinker<'a> {
2068 fn cmd(&mut self) -> &mut Command {
2069 &mut self.cmd
2070 }
2071
2072 fn set_output_kind(
2073 &mut self,
2074 _output_kind: LinkOutputKind,
2075 _crate_type: CrateType,
2076 _out_filename: &Path,
2077 ) {
2078 }
2079
2080 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2081 panic!("staticlibs not supported")
2082 }
2083
2084 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2085 self.link_or_cc_arg(path);
2086 }
2087
2088 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2089 self.link_arg("--debug");
2090 }
2091
2092 fn optimize(&mut self) {
2093 self.link_arg(match self.sess.opts.optimize {
2094 OptLevel::No => "-O0",
2095 OptLevel::Less => "-O1",
2096 OptLevel::More => "-O2",
2097 OptLevel::Aggressive => "-O3",
2098 OptLevel::Size => "-Os",
2099 OptLevel::SizeMin => "-Oz",
2100 });
2101 }
2102
2103 fn full_relro(&mut self) {}
2104
2105 fn partial_relro(&mut self) {}
2106
2107 fn no_relro(&mut self) {}
2108
2109 fn gc_sections(&mut self, _keep_metadata: bool) {}
2110
2111 fn pgo_gen(&mut self) {}
2112
2113 fn no_crt_objects(&mut self) {}
2114
2115 fn no_default_libraries(&mut self) {}
2116
2117 fn control_flow_guard(&mut self) {}
2118
2119 fn ehcont_guard(&mut self) {}
2120
2121 fn export_symbols(
2122 &mut self,
2123 tmpdir: &Path,
2124 _crate_type: CrateType,
2125 symbols: &[(String, SymbolExportKind)],
2126 ) {
2127 let path = tmpdir.join("symbols");
2128 let res: io::Result<()> = try {
2129 let mut f = File::create_buffered(&path)?;
2130 for (sym, _) in symbols {
2131 writeln!(f, "{sym}")?;
2132 }
2133 };
2134 if let Err(error) = res {
2135 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2136 } else {
2137 self.link_arg("--export-symbols").link_arg(&path);
2138 }
2139 }
2140
2141 fn subsystem(&mut self, _subsystem: &str) {}
2142
2143 fn linker_plugin_lto(&mut self) {}
2144}