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::{
15 self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
16};
17use rustc_middle::ty::TyCtxt;
18use rustc_session::Session;
19use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
20use rustc_span::sym;
21use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
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) -> Box<dyn Linker + 'a> {
56 let msvc_tool = windows_registry::find_tool(&sess.target.arch, "link.exe");
57
58 let mut cmd = match linker.to_str() {
67 Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
68 _ => match flavor {
69 LinkerFlavor::Gnu(Cc::No, Lld::Yes)
70 | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
71 | LinkerFlavor::WasmLld(Cc::No)
72 | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
73 LinkerFlavor::Msvc(Lld::No)
74 if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
75 {
76 Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
77 }
78 _ => Command::new(linker),
79 },
80 };
81
82 let t = &sess.target;
86 if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
87 if let Some(ref tool) = msvc_tool {
88 let original_path = tool.path();
89 if let Some(root_lib_path) = original_path.ancestors().nth(4) {
90 let arch = match t.arch.as_ref() {
91 "x86_64" => Some("x64"),
92 "x86" => Some("x86"),
93 "aarch64" => Some("arm64"),
94 "arm" => Some("arm"),
95 _ => None,
96 };
97 if let Some(ref a) = arch {
98 let mut arg = OsString::from("/LIBPATH:");
100 arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
101 cmd.arg(&arg);
102 } else {
103 warn!("arch is not supported");
104 }
105 } else {
106 warn!("MSVC root path lib location not found");
107 }
108 } else {
109 warn!("link.exe not found");
110 }
111 }
112
113 let mut new_path = sess.get_tools_search_paths(self_contained);
116 let mut msvc_changed_path = false;
117 if sess.target.is_like_msvc
118 && let Some(ref tool) = msvc_tool
119 {
120 cmd.args(tool.args());
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.vendor == "uwp");
139 match flavor {
140 LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
141 Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
142 }
143 LinkerFlavor::Unix(Cc::No) if sess.target.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 }) as Box<dyn Linker>,
159 LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
160 LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
161 LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
162 LinkerFlavor::Llbc => Box::new(LlbcLinker { cmd, sess }) as Box<dyn Linker>,
163 LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
164 }
165}
166
167fn verbatim_args<L: Linker + ?Sized>(
177 l: &mut L,
178 args: impl IntoIterator<Item: AsRef<OsStr>>,
179) -> &mut L {
180 for arg in args {
181 l.cmd().arg(arg);
182 }
183 l
184}
185fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
188 let mut combined_arg = OsString::from("-Wl");
189 for arg in args {
190 if arg.as_ref().as_encoded_bytes().contains(&b',') {
193 if combined_arg != OsStr::new("-Wl") {
195 cmd.arg(combined_arg);
196 combined_arg = OsString::from("-Wl");
198 }
199
200 cmd.arg("-Xlinker");
202 cmd.arg(arg);
203 } else {
204 combined_arg.push(",");
206 combined_arg.push(arg);
207 }
208 }
209 if combined_arg != OsStr::new("-Wl") {
211 cmd.arg(combined_arg);
212 }
213}
214fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
217 if !l.is_cc() {
218 verbatim_args(l, args);
219 } else {
220 convert_link_args_to_cc_args(l.cmd(), args);
221 }
222 l
223}
224fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
227 assert!(l.is_cc());
228 verbatim_args(l, args)
229}
230fn link_or_cc_args<L: Linker + ?Sized>(
232 l: &mut L,
233 args: impl IntoIterator<Item: AsRef<OsStr>>,
234) -> &mut L {
235 verbatim_args(l, args)
236}
237
238macro_rules! generate_arg_methods {
239 ($($ty:ty)*) => { $(
240 impl $ty {
241 #[allow(unused)]
242 pub(crate) fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
243 verbatim_args(self, args)
244 }
245 #[allow(unused)]
246 pub(crate) fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
247 verbatim_args(self, iter::once(arg))
248 }
249 #[allow(unused)]
250 pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
251 link_args(self, args)
252 }
253 #[allow(unused)]
254 pub(crate) fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
255 link_args(self, iter::once(arg))
256 }
257 #[allow(unused)]
258 pub(crate) fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
259 cc_args(self, args)
260 }
261 #[allow(unused)]
262 pub(crate) fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
263 cc_args(self, iter::once(arg))
264 }
265 #[allow(unused)]
266 pub(crate) fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
267 link_or_cc_args(self, args)
268 }
269 #[allow(unused)]
270 pub(crate) fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
271 link_or_cc_args(self, iter::once(arg))
272 }
273 }
274 )* }
275}
276
277generate_arg_methods! {
278 GccLinker<'_>
279 MsvcLinker<'_>
280 EmLinker<'_>
281 WasmLd<'_>
282 L4Bender<'_>
283 AixLinker<'_>
284 LlbcLinker<'_>
285 PtxLinker<'_>
286 BpfLinker<'_>
287 dyn Linker + '_
288}
289
290pub(crate) trait Linker {
298 fn cmd(&mut self) -> &mut Command;
299 fn is_cc(&self) -> bool {
300 false
301 }
302 fn set_output_kind(
303 &mut self,
304 output_kind: LinkOutputKind,
305 crate_type: CrateType,
306 out_filename: &Path,
307 );
308 fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
309 bug!("dylib linked with unsupported linker")
310 }
311 fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
312 bug!("dylib linked with unsupported linker")
313 }
314 fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
315 bug!("framework linked with unsupported linker")
316 }
317 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
318 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
319 fn include_path(&mut self, path: &Path) {
320 link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]);
321 }
322 fn framework_path(&mut self, _path: &Path) {
323 bug!("framework path set with unsupported linker")
324 }
325 fn output_filename(&mut self, path: &Path) {
326 link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]);
327 }
328 fn add_object(&mut self, path: &Path) {
329 link_or_cc_args(self, &[path]);
330 }
331 fn gc_sections(&mut self, keep_metadata: bool);
332 fn full_relro(&mut self);
333 fn partial_relro(&mut self);
334 fn no_relro(&mut self);
335 fn optimize(&mut self);
336 fn pgo_gen(&mut self);
337 fn control_flow_guard(&mut self);
338 fn ehcont_guard(&mut self);
339 fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
340 fn no_crt_objects(&mut self);
341 fn no_default_libraries(&mut self);
342 fn export_symbols(
343 &mut self,
344 tmpdir: &Path,
345 crate_type: CrateType,
346 symbols: &[(String, SymbolExportKind)],
347 );
348 fn subsystem(&mut self, subsystem: &str);
349 fn linker_plugin_lto(&mut self);
350 fn add_eh_frame_header(&mut self) {}
351 fn add_no_exec(&mut self) {}
352 fn add_as_needed(&mut self) {}
353 fn reset_per_library_state(&mut self) {}
354}
355
356impl dyn Linker + '_ {
357 pub(crate) fn take_cmd(&mut self) -> Command {
358 mem::replace(self.cmd(), Command::new(""))
359 }
360}
361
362struct GccLinker<'a> {
363 cmd: Command,
364 sess: &'a Session,
365 target_cpu: &'a str,
366 hinted_static: Option<bool>, is_ld: bool,
369 is_gnu: bool,
370 uses_lld: bool,
371}
372
373impl<'a> GccLinker<'a> {
374 fn takes_hints(&self) -> bool {
375 !self.sess.target.is_like_darwin && !self.sess.target.is_like_wasm
384 }
385
386 fn hint_static(&mut self) {
391 if !self.takes_hints() {
392 return;
393 }
394 if self.hinted_static != Some(true) {
395 self.link_arg("-Bstatic");
396 self.hinted_static = Some(true);
397 }
398 }
399
400 fn hint_dynamic(&mut self) {
401 if !self.takes_hints() {
402 return;
403 }
404 if self.hinted_static != Some(false) {
405 self.link_arg("-Bdynamic");
406 self.hinted_static = Some(false);
407 }
408 }
409
410 fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
411 if let Some(plugin_path) = plugin_path {
412 let mut arg = OsString::from("-plugin=");
413 arg.push(plugin_path);
414 self.link_arg(&arg);
415 }
416
417 let opt_level = match self.sess.opts.optimize {
418 config::OptLevel::No => "O0",
419 config::OptLevel::Less => "O1",
420 config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
421 config::OptLevel::Aggressive => "O3",
422 };
423
424 if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
425 self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
426 };
427 self.link_args(&[
428 &format!("-plugin-opt={opt_level}"),
429 &format!("-plugin-opt=mcpu={}", self.target_cpu),
430 ]);
431 }
432
433 fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
434 if self.sess.target.is_like_darwin {
436 if self.is_cc() {
437 self.cc_arg("-dynamiclib");
439 } else {
440 self.link_arg("-dylib");
441 }
443
444 if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
449 let mut rpath = OsString::from("@rpath/");
450 rpath.push(out_filename.file_name().unwrap());
451 self.link_arg("-install_name").link_arg(rpath);
452 }
453 } else {
454 self.link_or_cc_arg("-shared");
455 if let Some(name) = out_filename.file_name() {
456 if self.sess.target.is_like_windows {
457 let (prefix, suffix) = self.sess.staticlib_components(false);
461 let mut implib_name = OsString::from(prefix);
462 implib_name.push(name);
463 implib_name.push(suffix);
464 let mut out_implib = OsString::from("--out-implib=");
465 out_implib.push(out_filename.with_file_name(implib_name));
466 self.link_arg(out_implib);
467 } else if crate_type == CrateType::Dylib {
468 let mut soname = OsString::from("-soname=");
472 soname.push(name);
473 self.link_arg(soname);
474 }
475 }
476 }
477 }
478
479 fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
480 if !as_needed {
481 if self.sess.target.is_like_darwin {
482 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
486 } else if self.is_gnu && !self.sess.target.is_like_windows {
487 self.link_arg("--no-as-needed");
488 } else {
489 self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
490 }
491 }
492
493 f(self);
494
495 if !as_needed {
496 if self.sess.target.is_like_darwin {
497 } else if self.is_gnu && !self.sess.target.is_like_windows {
499 self.link_arg("--as-needed");
500 }
501 }
502 }
503}
504
505impl<'a> Linker for GccLinker<'a> {
506 fn cmd(&mut self) -> &mut Command {
507 &mut self.cmd
508 }
509
510 fn is_cc(&self) -> bool {
511 !self.is_ld
512 }
513
514 fn set_output_kind(
515 &mut self,
516 output_kind: LinkOutputKind,
517 crate_type: CrateType,
518 out_filename: &Path,
519 ) {
520 match output_kind {
521 LinkOutputKind::DynamicNoPicExe => {
522 if !self.is_ld && self.is_gnu {
523 self.cc_arg("-no-pie");
524 }
525 }
526 LinkOutputKind::DynamicPicExe => {
527 if !self.sess.target.is_like_windows {
529 self.link_or_cc_arg("-pie");
531 }
532 }
533 LinkOutputKind::StaticNoPicExe => {
534 self.link_or_cc_arg("-static");
536 if !self.is_ld && self.is_gnu {
537 self.cc_arg("-no-pie");
538 }
539 }
540 LinkOutputKind::StaticPicExe => {
541 if !self.is_ld {
542 self.cc_arg("-static-pie");
545 } else {
546 self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
552 }
553 }
554 LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
555 LinkOutputKind::StaticDylib => {
556 self.link_or_cc_arg("-static");
557 self.build_dylib(crate_type, out_filename);
558 }
559 LinkOutputKind::WasiReactorExe => {
560 self.link_args(&["--entry", "_initialize"]);
561 }
562 }
563
564 if self.sess.target.os == "vxworks"
570 && matches!(
571 output_kind,
572 LinkOutputKind::StaticNoPicExe
573 | LinkOutputKind::StaticPicExe
574 | LinkOutputKind::StaticDylib
575 )
576 {
577 self.cc_arg("--static-crt");
578 }
579
580 if self.sess.target.arch == "avr" && !self.uses_lld {
586 self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
587 }
588 }
589
590 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
591 if self.sess.target.os == "illumos" && name == "c" {
592 return;
598 }
599 self.hint_dynamic();
600 self.with_as_needed(as_needed, |this| {
601 let colon = if verbatim && this.is_gnu { ":" } else { "" };
602 this.link_or_cc_arg(format!("-l{colon}{name}"));
603 });
604 }
605
606 fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
607 self.hint_dynamic();
608 self.with_as_needed(as_needed, |this| {
609 this.link_or_cc_arg(path);
610 })
611 }
612
613 fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
614 self.hint_dynamic();
615 if !as_needed {
616 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
620 }
621 self.link_or_cc_args(&["-framework", name]);
622 }
623
624 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
625 self.hint_static();
626 let colon = if verbatim && self.is_gnu { ":" } else { "" };
627 if !whole_archive {
628 self.link_or_cc_arg(format!("-l{colon}{name}"));
629 } else if self.sess.target.is_like_darwin {
630 self.link_arg("-force_load");
633 self.link_arg(find_native_static_library(name, verbatim, self.sess));
634 } else {
635 self.link_arg("--whole-archive")
636 .link_or_cc_arg(format!("-l{colon}{name}"))
637 .link_arg("--no-whole-archive");
638 }
639 }
640
641 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
642 self.hint_static();
643 if !whole_archive {
644 self.link_or_cc_arg(path);
645 } else if self.sess.target.is_like_darwin {
646 self.link_arg("-force_load").link_arg(path);
647 } else {
648 self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
649 }
650 }
651
652 fn framework_path(&mut self, path: &Path) {
653 self.link_or_cc_arg("-F").link_or_cc_arg(path);
654 }
655 fn full_relro(&mut self) {
656 self.link_args(&["-z", "relro", "-z", "now"]);
657 }
658 fn partial_relro(&mut self) {
659 self.link_args(&["-z", "relro"]);
660 }
661 fn no_relro(&mut self) {
662 self.link_args(&["-z", "norelro"]);
663 }
664
665 fn gc_sections(&mut self, keep_metadata: bool) {
666 if self.sess.target.is_like_darwin {
681 self.link_arg("-dead_strip");
682
683 } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
689 self.link_arg("--gc-sections");
690 }
691 }
692
693 fn optimize(&mut self) {
694 if !self.is_gnu && !self.sess.target.is_like_wasm {
695 return;
696 }
697
698 if self.sess.opts.optimize == config::OptLevel::More
701 || self.sess.opts.optimize == config::OptLevel::Aggressive
702 {
703 self.link_arg("-O1");
704 }
705 }
706
707 fn pgo_gen(&mut self) {
708 if !self.is_gnu {
709 return;
710 }
711
712 self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
724 }
725
726 fn control_flow_guard(&mut self) {}
727
728 fn ehcont_guard(&mut self) {}
729
730 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
731 if self.sess.target.is_like_darwin {
733 return;
734 }
735
736 match strip {
737 Strip::None => {}
738 Strip::Debuginfo => {
739 if !self.sess.target.is_like_solaris {
744 self.link_arg("--strip-debug");
745 }
746 }
747 Strip::Symbols => {
748 self.link_arg("--strip-all");
749 }
750 }
751 match self.sess.opts.unstable_opts.debuginfo_compression {
752 config::DebugInfoCompression::None => {}
753 config::DebugInfoCompression::Zlib => {
754 self.link_arg("--compress-debug-sections=zlib");
755 }
756 config::DebugInfoCompression::Zstd => {
757 self.link_arg("--compress-debug-sections=zstd");
758 }
759 }
760 }
761
762 fn no_crt_objects(&mut self) {
763 if !self.is_ld {
764 self.cc_arg("-nostartfiles");
765 }
766 }
767
768 fn no_default_libraries(&mut self) {
769 if !self.is_ld {
770 self.cc_arg("-nodefaultlibs");
771 }
772 }
773
774 fn export_symbols(
775 &mut self,
776 tmpdir: &Path,
777 crate_type: CrateType,
778 symbols: &[(String, SymbolExportKind)],
779 ) {
780 if crate_type == CrateType::Executable {
782 let should_export_executable_symbols =
783 self.sess.opts.unstable_opts.export_executable_symbols;
784 if self.sess.target.override_export_symbols.is_none()
785 && !should_export_executable_symbols
786 {
787 return;
788 }
789 }
790
791 if !self.sess.target.limit_rdylib_exports {
796 return;
797 }
798
799 let path = tmpdir.join(if self.sess.target.is_like_windows { "list.def" } else { "list" });
800 debug!("EXPORTED SYMBOLS:");
801
802 if self.sess.target.is_like_darwin {
803 let res: io::Result<()> = try {
805 let mut f = File::create_buffered(&path)?;
806 for (sym, _) in symbols {
807 debug!(" _{sym}");
808 writeln!(f, "_{sym}")?;
809 }
810 };
811 if let Err(error) = res {
812 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
813 }
814 self.link_arg("-exported_symbols_list").link_arg(path);
815 } else if self.sess.target.is_like_windows {
816 let res: io::Result<()> = try {
817 let mut f = File::create_buffered(&path)?;
818
819 writeln!(f, "EXPORTS")?;
822 for (symbol, kind) in symbols {
823 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
824 debug!(" _{symbol}");
825 writeln!(f, " \"{symbol}\"{kind_marker}")?;
828 }
829 };
830 if let Err(error) = res {
831 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
832 }
833 self.link_arg(path);
834 } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris {
835 let res: io::Result<()> = try {
836 let mut f = File::create_buffered(&path)?;
837 writeln!(f, "{{")?;
838 for (sym, _) in symbols {
839 debug!(sym);
840 writeln!(f, " {sym};")?;
841 }
842 writeln!(f, "}};")?;
843 };
844 if let Err(error) = res {
845 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
846 }
847 self.link_arg("--dynamic-list").link_arg(path);
848 } else {
849 let res: io::Result<()> = try {
851 let mut f = File::create_buffered(&path)?;
852 writeln!(f, "{{")?;
853 if !symbols.is_empty() {
854 writeln!(f, " global:")?;
855 for (sym, _) in symbols {
856 debug!(" {sym};");
857 writeln!(f, " {sym};")?;
858 }
859 }
860 writeln!(f, "\n local:\n *;\n}};")?;
861 };
862 if let Err(error) = res {
863 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
864 }
865 if self.sess.target.is_like_solaris {
866 self.link_arg("-M").link_arg(path);
867 } else {
868 let mut arg = OsString::from("--version-script=");
869 arg.push(path);
870 self.link_arg(arg).link_arg("--no-undefined-version");
871 }
872 }
873 }
874
875 fn subsystem(&mut self, subsystem: &str) {
876 self.link_args(&["--subsystem", subsystem]);
877 }
878
879 fn reset_per_library_state(&mut self) {
880 self.hint_dynamic(); }
882
883 fn linker_plugin_lto(&mut self) {
884 match self.sess.opts.cg.linker_plugin_lto {
885 LinkerPluginLto::Disabled => {
886 }
888 LinkerPluginLto::LinkerPluginAuto => {
889 self.push_linker_plugin_lto_args(None);
890 }
891 LinkerPluginLto::LinkerPlugin(ref path) => {
892 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
893 }
894 }
895 }
896
897 fn add_eh_frame_header(&mut self) {
901 self.link_arg("--eh-frame-hdr");
902 }
903
904 fn add_no_exec(&mut self) {
905 if self.sess.target.is_like_windows {
906 self.link_arg("--nxcompat");
907 } else if self.is_gnu {
908 self.link_args(&["-z", "noexecstack"]);
909 }
910 }
911
912 fn add_as_needed(&mut self) {
913 if self.is_gnu && !self.sess.target.is_like_windows {
914 self.link_arg("--as-needed");
915 } else if self.sess.target.is_like_solaris {
916 self.link_args(&["-z", "ignore"]);
918 }
919 }
920}
921
922struct MsvcLinker<'a> {
923 cmd: Command,
924 sess: &'a Session,
925}
926
927impl<'a> Linker for MsvcLinker<'a> {
928 fn cmd(&mut self) -> &mut Command {
929 &mut self.cmd
930 }
931
932 fn set_output_kind(
933 &mut self,
934 output_kind: LinkOutputKind,
935 _crate_type: CrateType,
936 out_filename: &Path,
937 ) {
938 match output_kind {
939 LinkOutputKind::DynamicNoPicExe
940 | LinkOutputKind::DynamicPicExe
941 | LinkOutputKind::StaticNoPicExe
942 | LinkOutputKind::StaticPicExe => {}
943 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
944 self.link_arg("/DLL");
945 let mut arg: OsString = "/IMPLIB:".into();
946 arg.push(out_filename.with_extension("dll.lib"));
947 self.link_arg(arg);
948 }
949 LinkOutputKind::WasiReactorExe => {
950 panic!("can't link as reactor on non-wasi target");
951 }
952 }
953 }
954
955 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
956 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
959 self.link_arg(path);
960 } else {
961 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
962 }
963 }
964
965 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
966 let implib_path = path.with_extension("dll.lib");
969 if implib_path.exists() {
970 self.link_or_cc_arg(implib_path);
971 }
972 }
973
974 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
975 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
978 self.link_staticlib_by_path(&path, whole_archive);
979 } else {
980 let opts = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
981 let (prefix, suffix) = self.sess.staticlib_components(verbatim);
982 self.link_arg(format!("{opts}{prefix}{name}{suffix}"));
983 }
984 }
985
986 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
987 if !whole_archive {
988 self.link_arg(path);
989 } else {
990 let mut arg = OsString::from("/WHOLEARCHIVE:");
991 arg.push(path);
992 self.link_arg(arg);
993 }
994 }
995
996 fn gc_sections(&mut self, _keep_metadata: bool) {
997 if self.sess.opts.optimize != config::OptLevel::No {
1001 self.link_arg("/OPT:REF,ICF");
1002 } else {
1003 self.link_arg("/OPT:REF,NOICF");
1006 }
1007 }
1008
1009 fn full_relro(&mut self) {
1010 }
1012
1013 fn partial_relro(&mut self) {
1014 }
1016
1017 fn no_relro(&mut self) {
1018 }
1020
1021 fn no_crt_objects(&mut self) {
1022 }
1024
1025 fn no_default_libraries(&mut self) {
1026 self.link_arg("/NODEFAULTLIB");
1027 }
1028
1029 fn include_path(&mut self, path: &Path) {
1030 let mut arg = OsString::from("/LIBPATH:");
1031 arg.push(path);
1032 self.link_arg(&arg);
1033 }
1034
1035 fn output_filename(&mut self, path: &Path) {
1036 let mut arg = OsString::from("/OUT:");
1037 arg.push(path);
1038 self.link_arg(&arg);
1039 }
1040
1041 fn optimize(&mut self) {
1042 }
1044
1045 fn pgo_gen(&mut self) {
1046 }
1048
1049 fn control_flow_guard(&mut self) {
1050 self.link_arg("/guard:cf");
1051 }
1052
1053 fn ehcont_guard(&mut self) {
1054 if self.sess.target.pointer_width == 64 {
1055 self.link_arg("/guard:ehcont");
1056 }
1057 }
1058
1059 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1060 self.link_arg("/DEBUG");
1063
1064 self.link_arg("/PDBALTPATH:%_PDB%");
1072
1073 let natvis_dir_path = self.sess.opts.sysroot.path().join("lib\\rustlib\\etc");
1075 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1076 for entry in natvis_dir {
1077 match entry {
1078 Ok(entry) => {
1079 let path = entry.path();
1080 if path.extension() == Some("natvis".as_ref()) {
1081 let mut arg = OsString::from("/NATVIS:");
1082 arg.push(path);
1083 self.link_arg(arg);
1084 }
1085 }
1086 Err(error) => {
1087 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1088 }
1089 }
1090 }
1091 }
1092
1093 for path in natvis_debugger_visualizers {
1095 let mut arg = OsString::from("/NATVIS:");
1096 arg.push(path);
1097 self.link_arg(arg);
1098 }
1099 }
1100
1101 fn export_symbols(
1114 &mut self,
1115 tmpdir: &Path,
1116 crate_type: CrateType,
1117 symbols: &[(String, SymbolExportKind)],
1118 ) {
1119 if crate_type == CrateType::Executable {
1121 let should_export_executable_symbols =
1122 self.sess.opts.unstable_opts.export_executable_symbols;
1123 if !should_export_executable_symbols {
1124 return;
1125 }
1126 }
1127
1128 let path = tmpdir.join("lib.def");
1129 let res: io::Result<()> = try {
1130 let mut f = File::create_buffered(&path)?;
1131
1132 writeln!(f, "LIBRARY")?;
1135 writeln!(f, "EXPORTS")?;
1136 for (symbol, kind) in symbols {
1137 let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
1138 debug!(" _{symbol}");
1139 writeln!(f, " {symbol}{kind_marker}")?;
1140 }
1141 };
1142 if let Err(error) = res {
1143 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1144 }
1145 let mut arg = OsString::from("/DEF:");
1146 arg.push(path);
1147 self.link_arg(&arg);
1148 }
1149
1150 fn subsystem(&mut self, subsystem: &str) {
1151 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1154
1155 if subsystem == "windows" {
1170 self.link_arg("/ENTRY:mainCRTStartup");
1171 }
1172 }
1173
1174 fn linker_plugin_lto(&mut self) {
1175 }
1177
1178 fn add_no_exec(&mut self) {
1179 self.link_arg("/NXCOMPAT");
1180 }
1181}
1182
1183struct EmLinker<'a> {
1184 cmd: Command,
1185 sess: &'a Session,
1186}
1187
1188impl<'a> Linker for EmLinker<'a> {
1189 fn cmd(&mut self) -> &mut Command {
1190 &mut self.cmd
1191 }
1192
1193 fn is_cc(&self) -> bool {
1194 true
1195 }
1196
1197 fn set_output_kind(
1198 &mut self,
1199 _output_kind: LinkOutputKind,
1200 _crate_type: CrateType,
1201 _out_filename: &Path,
1202 ) {
1203 }
1204
1205 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1206 self.link_or_cc_args(&["-l", name]);
1208 }
1209
1210 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1211 self.link_or_cc_arg(path);
1212 }
1213
1214 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1215 self.link_or_cc_args(&["-l", name]);
1216 }
1217
1218 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1219 self.link_or_cc_arg(path);
1220 }
1221
1222 fn full_relro(&mut self) {
1223 }
1225
1226 fn partial_relro(&mut self) {
1227 }
1229
1230 fn no_relro(&mut self) {
1231 }
1233
1234 fn gc_sections(&mut self, _keep_metadata: bool) {
1235 }
1237
1238 fn optimize(&mut self) {
1239 self.cc_arg(match self.sess.opts.optimize {
1241 OptLevel::No => "-O0",
1242 OptLevel::Less => "-O1",
1243 OptLevel::More => "-O2",
1244 OptLevel::Aggressive => "-O3",
1245 OptLevel::Size => "-Os",
1246 OptLevel::SizeMin => "-Oz",
1247 });
1248 }
1249
1250 fn pgo_gen(&mut self) {
1251 }
1253
1254 fn control_flow_guard(&mut self) {}
1255
1256 fn ehcont_guard(&mut self) {}
1257
1258 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1259 self.cc_arg(match self.sess.opts.debuginfo {
1262 DebugInfo::None => "-g0",
1263 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1264 "--profiling-funcs"
1265 }
1266 DebugInfo::Full => "-g",
1267 });
1268 }
1269
1270 fn no_crt_objects(&mut self) {}
1271
1272 fn no_default_libraries(&mut self) {
1273 self.cc_arg("-nodefaultlibs");
1274 }
1275
1276 fn export_symbols(
1277 &mut self,
1278 _tmpdir: &Path,
1279 _crate_type: CrateType,
1280 symbols: &[(String, SymbolExportKind)],
1281 ) {
1282 debug!("EXPORTED SYMBOLS:");
1283
1284 self.cc_arg("-s");
1285
1286 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1287 let encoded = serde_json::to_string(
1288 &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
1289 )
1290 .unwrap();
1291 debug!("{encoded}");
1292
1293 arg.push(encoded);
1294
1295 self.cc_arg(arg);
1296 }
1297
1298 fn subsystem(&mut self, _subsystem: &str) {
1299 }
1301
1302 fn linker_plugin_lto(&mut self) {
1303 }
1305}
1306
1307struct WasmLd<'a> {
1308 cmd: Command,
1309 sess: &'a Session,
1310}
1311
1312impl<'a> WasmLd<'a> {
1313 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1314 let mut wasm_ld = WasmLd { cmd, sess };
1333 if sess.target_features.contains(&sym::atomics) {
1334 wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1335 if sess.target.os == "unknown" || sess.target.os == "none" {
1336 wasm_ld.link_args(&[
1337 "--export=__wasm_init_tls",
1338 "--export=__tls_size",
1339 "--export=__tls_align",
1340 "--export=__tls_base",
1341 ]);
1342 }
1343 }
1344 wasm_ld
1345 }
1346}
1347
1348impl<'a> Linker for WasmLd<'a> {
1349 fn cmd(&mut self) -> &mut Command {
1350 &mut self.cmd
1351 }
1352
1353 fn set_output_kind(
1354 &mut self,
1355 output_kind: LinkOutputKind,
1356 _crate_type: CrateType,
1357 _out_filename: &Path,
1358 ) {
1359 match output_kind {
1360 LinkOutputKind::DynamicNoPicExe
1361 | LinkOutputKind::DynamicPicExe
1362 | LinkOutputKind::StaticNoPicExe
1363 | LinkOutputKind::StaticPicExe => {}
1364 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1365 self.link_arg("--no-entry");
1366 }
1367 LinkOutputKind::WasiReactorExe => {
1368 self.link_args(&["--entry", "_initialize"]);
1369 }
1370 }
1371 }
1372
1373 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1374 self.link_or_cc_args(&["-l", name]);
1375 }
1376
1377 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1378 self.link_or_cc_arg(path);
1379 }
1380
1381 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1382 if !whole_archive {
1383 self.link_or_cc_args(&["-l", name]);
1384 } else {
1385 self.link_arg("--whole-archive")
1386 .link_or_cc_args(&["-l", name])
1387 .link_arg("--no-whole-archive");
1388 }
1389 }
1390
1391 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1392 if !whole_archive {
1393 self.link_or_cc_arg(path);
1394 } else {
1395 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1396 }
1397 }
1398
1399 fn full_relro(&mut self) {}
1400
1401 fn partial_relro(&mut self) {}
1402
1403 fn no_relro(&mut self) {}
1404
1405 fn gc_sections(&mut self, _keep_metadata: bool) {
1406 self.link_arg("--gc-sections");
1407 }
1408
1409 fn optimize(&mut self) {
1410 self.link_arg(match self.sess.opts.optimize {
1413 OptLevel::No => "-O0",
1414 OptLevel::Less => "-O1",
1415 OptLevel::More => "-O2",
1416 OptLevel::Aggressive => "-O3",
1417 OptLevel::Size => "-O2",
1420 OptLevel::SizeMin => "-O2",
1421 });
1422 }
1423
1424 fn pgo_gen(&mut self) {}
1425
1426 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1427 match strip {
1428 Strip::None => {}
1429 Strip::Debuginfo => {
1430 self.link_arg("--strip-debug");
1431 }
1432 Strip::Symbols => {
1433 self.link_arg("--strip-all");
1434 }
1435 }
1436 }
1437
1438 fn control_flow_guard(&mut self) {}
1439
1440 fn ehcont_guard(&mut self) {}
1441
1442 fn no_crt_objects(&mut self) {}
1443
1444 fn no_default_libraries(&mut self) {}
1445
1446 fn export_symbols(
1447 &mut self,
1448 _tmpdir: &Path,
1449 _crate_type: CrateType,
1450 symbols: &[(String, SymbolExportKind)],
1451 ) {
1452 for (sym, _) in symbols {
1453 self.link_args(&["--export", sym]);
1454 }
1455
1456 if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
1461 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1462 }
1463 }
1464
1465 fn subsystem(&mut self, _subsystem: &str) {}
1466
1467 fn linker_plugin_lto(&mut self) {
1468 match self.sess.opts.cg.linker_plugin_lto {
1469 LinkerPluginLto::Disabled => {
1470 }
1472 LinkerPluginLto::LinkerPluginAuto => {
1473 self.push_linker_plugin_lto_args();
1474 }
1475 LinkerPluginLto::LinkerPlugin(_) => {
1476 self.push_linker_plugin_lto_args();
1477 }
1478 }
1479 }
1480}
1481
1482impl<'a> WasmLd<'a> {
1483 fn push_linker_plugin_lto_args(&mut self) {
1484 let opt_level = match self.sess.opts.optimize {
1485 config::OptLevel::No => "O0",
1486 config::OptLevel::Less => "O1",
1487 config::OptLevel::More => "O2",
1488 config::OptLevel::Aggressive => "O3",
1489 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1491 };
1492 self.link_arg(&format!("--lto-{opt_level}"));
1493 }
1494}
1495
1496struct L4Bender<'a> {
1498 cmd: Command,
1499 sess: &'a Session,
1500 hinted_static: bool,
1501}
1502
1503impl<'a> Linker for L4Bender<'a> {
1504 fn cmd(&mut self) -> &mut Command {
1505 &mut self.cmd
1506 }
1507
1508 fn set_output_kind(
1509 &mut self,
1510 _output_kind: LinkOutputKind,
1511 _crate_type: CrateType,
1512 _out_filename: &Path,
1513 ) {
1514 }
1515
1516 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1517 self.hint_static();
1518 if !whole_archive {
1519 self.link_arg(format!("-PC{name}"));
1520 } else {
1521 self.link_arg("--whole-archive")
1522 .link_or_cc_arg(format!("-l{name}"))
1523 .link_arg("--no-whole-archive");
1524 }
1525 }
1526
1527 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1528 self.hint_static();
1529 if !whole_archive {
1530 self.link_or_cc_arg(path);
1531 } else {
1532 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1533 }
1534 }
1535
1536 fn full_relro(&mut self) {
1537 self.link_args(&["-z", "relro", "-z", "now"]);
1538 }
1539
1540 fn partial_relro(&mut self) {
1541 self.link_args(&["-z", "relro"]);
1542 }
1543
1544 fn no_relro(&mut self) {
1545 self.link_args(&["-z", "norelro"]);
1546 }
1547
1548 fn gc_sections(&mut self, keep_metadata: bool) {
1549 if !keep_metadata {
1550 self.link_arg("--gc-sections");
1551 }
1552 }
1553
1554 fn optimize(&mut self) {
1555 if self.sess.opts.optimize == config::OptLevel::More
1558 || self.sess.opts.optimize == config::OptLevel::Aggressive
1559 {
1560 self.link_arg("-O1");
1561 }
1562 }
1563
1564 fn pgo_gen(&mut self) {}
1565
1566 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1567 match strip {
1568 Strip::None => {}
1569 Strip::Debuginfo => {
1570 self.link_arg("--strip-debug");
1571 }
1572 Strip::Symbols => {
1573 self.link_arg("--strip-all");
1574 }
1575 }
1576 }
1577
1578 fn no_default_libraries(&mut self) {
1579 self.cc_arg("-nostdlib");
1580 }
1581
1582 fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
1583 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1585 }
1586
1587 fn subsystem(&mut self, subsystem: &str) {
1588 self.link_arg(&format!("--subsystem {subsystem}"));
1589 }
1590
1591 fn reset_per_library_state(&mut self) {
1592 self.hint_static(); }
1594
1595 fn linker_plugin_lto(&mut self) {}
1596
1597 fn control_flow_guard(&mut self) {}
1598
1599 fn ehcont_guard(&mut self) {}
1600
1601 fn no_crt_objects(&mut self) {}
1602}
1603
1604impl<'a> L4Bender<'a> {
1605 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1606 L4Bender { cmd, sess, hinted_static: false }
1607 }
1608
1609 fn hint_static(&mut self) {
1610 if !self.hinted_static {
1611 self.link_or_cc_arg("-static");
1612 self.hinted_static = true;
1613 }
1614 }
1615}
1616
1617struct AixLinker<'a> {
1619 cmd: Command,
1620 sess: &'a Session,
1621 hinted_static: Option<bool>,
1622}
1623
1624impl<'a> AixLinker<'a> {
1625 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1626 AixLinker { cmd, sess, hinted_static: None }
1627 }
1628
1629 fn hint_static(&mut self) {
1630 if self.hinted_static != Some(true) {
1631 self.link_arg("-bstatic");
1632 self.hinted_static = Some(true);
1633 }
1634 }
1635
1636 fn hint_dynamic(&mut self) {
1637 if self.hinted_static != Some(false) {
1638 self.link_arg("-bdynamic");
1639 self.hinted_static = Some(false);
1640 }
1641 }
1642
1643 fn build_dylib(&mut self, _out_filename: &Path) {
1644 self.link_args(&["-bM:SRE", "-bnoentry"]);
1645 self.link_arg("-bexpfull");
1648 }
1649}
1650
1651impl<'a> Linker for AixLinker<'a> {
1652 fn cmd(&mut self) -> &mut Command {
1653 &mut self.cmd
1654 }
1655
1656 fn set_output_kind(
1657 &mut self,
1658 output_kind: LinkOutputKind,
1659 _crate_type: CrateType,
1660 out_filename: &Path,
1661 ) {
1662 match output_kind {
1663 LinkOutputKind::DynamicDylib => {
1664 self.hint_dynamic();
1665 self.build_dylib(out_filename);
1666 }
1667 LinkOutputKind::StaticDylib => {
1668 self.hint_static();
1669 self.build_dylib(out_filename);
1670 }
1671 _ => {}
1672 }
1673 }
1674
1675 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1676 self.hint_dynamic();
1677 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1678 }
1679
1680 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1681 self.hint_dynamic();
1682 self.link_or_cc_arg(path);
1683 }
1684
1685 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1686 self.hint_static();
1687 if !whole_archive {
1688 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1689 } else {
1690 let mut arg = OsString::from("-bkeepfile:");
1691 arg.push(find_native_static_library(name, verbatim, self.sess));
1692 self.link_or_cc_arg(arg);
1693 }
1694 }
1695
1696 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1697 self.hint_static();
1698 if !whole_archive {
1699 self.link_or_cc_arg(path);
1700 } else {
1701 let mut arg = OsString::from("-bkeepfile:");
1702 arg.push(path);
1703 self.link_arg(arg);
1704 }
1705 }
1706
1707 fn full_relro(&mut self) {}
1708
1709 fn partial_relro(&mut self) {}
1710
1711 fn no_relro(&mut self) {}
1712
1713 fn gc_sections(&mut self, _keep_metadata: bool) {
1714 self.link_arg("-bgc");
1715 }
1716
1717 fn optimize(&mut self) {}
1718
1719 fn pgo_gen(&mut self) {
1720 self.link_arg("-bdbg:namedsects:ss");
1721 self.link_arg("-u");
1722 self.link_arg("__llvm_profile_runtime");
1723 }
1724
1725 fn control_flow_guard(&mut self) {}
1726
1727 fn ehcont_guard(&mut self) {}
1728
1729 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1730
1731 fn no_crt_objects(&mut self) {}
1732
1733 fn no_default_libraries(&mut self) {}
1734
1735 fn export_symbols(
1736 &mut self,
1737 tmpdir: &Path,
1738 _crate_type: CrateType,
1739 symbols: &[(String, SymbolExportKind)],
1740 ) {
1741 let path = tmpdir.join("list.exp");
1742 let res: io::Result<()> = try {
1743 let mut f = File::create_buffered(&path)?;
1744 for (symbol, _) in symbols {
1746 debug!(" _{symbol}");
1747 writeln!(f, " {symbol}")?;
1748 }
1749 };
1750 if let Err(e) = res {
1751 self.sess.dcx().fatal(format!("failed to write export file: {e}"));
1752 }
1753 self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
1754 }
1755
1756 fn subsystem(&mut self, _subsystem: &str) {}
1757
1758 fn reset_per_library_state(&mut self) {
1759 self.hint_dynamic();
1760 }
1761
1762 fn linker_plugin_lto(&mut self) {}
1763
1764 fn add_eh_frame_header(&mut self) {}
1765
1766 fn add_no_exec(&mut self) {}
1767
1768 fn add_as_needed(&mut self) {}
1769}
1770
1771fn for_each_exported_symbols_include_dep<'tcx>(
1772 tcx: TyCtxt<'tcx>,
1773 crate_type: CrateType,
1774 mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
1775) {
1776 let formats = tcx.dependency_formats(());
1777 let deps = &formats[&crate_type];
1778
1779 for (cnum, dep_format) in deps.iter_enumerated() {
1780 if *dep_format == Linkage::Static {
1782 for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() {
1783 callback(symbol, info, cnum);
1784 }
1785 for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() {
1786 callback(symbol, info, cnum);
1787 }
1788 }
1789 }
1790}
1791
1792pub(crate) fn exported_symbols(
1793 tcx: TyCtxt<'_>,
1794 crate_type: CrateType,
1795) -> Vec<(String, SymbolExportKind)> {
1796 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1797 return exports
1798 .iter()
1799 .map(|name| {
1800 (
1801 name.to_string(),
1802 SymbolExportKind::Text,
1806 )
1807 })
1808 .collect();
1809 }
1810
1811 let mut symbols = if let CrateType::ProcMacro = crate_type {
1812 exported_symbols_for_proc_macro_crate(tcx)
1813 } else {
1814 exported_symbols_for_non_proc_macro(tcx, crate_type)
1815 };
1816
1817 if crate_type == CrateType::Dylib || crate_type == CrateType::ProcMacro {
1818 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1819 symbols.push((metadata_symbol_name, SymbolExportKind::Data));
1820 }
1821
1822 symbols
1823}
1824
1825fn exported_symbols_for_non_proc_macro(
1826 tcx: TyCtxt<'_>,
1827 crate_type: CrateType,
1828) -> Vec<(String, SymbolExportKind)> {
1829 let mut symbols = Vec::new();
1830 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1831 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1832 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1836 symbols.push((
1837 symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1838 info.kind,
1839 ));
1840 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1841 }
1842 });
1843
1844 if export_threshold == SymbolExportLevel::Rust
1846 && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
1847 && tcx.allocator_kind(()).is_some()
1848 {
1849 symbols.extend(allocator_shim_symbols(tcx));
1850 }
1851
1852 symbols
1853}
1854
1855fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
1856 if !tcx.sess.opts.output_types.should_codegen() {
1858 return Vec::new();
1859 }
1860
1861 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1862 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1863
1864 vec![(proc_macro_decls_name, SymbolExportKind::Data)]
1865}
1866
1867pub(crate) fn linked_symbols(
1868 tcx: TyCtxt<'_>,
1869 crate_type: CrateType,
1870) -> Vec<(String, SymbolExportKind)> {
1871 match crate_type {
1872 CrateType::Executable
1873 | CrateType::ProcMacro
1874 | CrateType::Cdylib
1875 | CrateType::Dylib
1876 | CrateType::Sdylib => (),
1877 CrateType::Staticlib | CrateType::Rlib => {
1878 return Vec::new();
1880 }
1881 }
1882
1883 match tcx.sess.lto() {
1884 Lto::No | Lto::ThinLocal => {}
1885 Lto::Thin | Lto::Fat => {
1886 return Vec::new();
1895 }
1896 }
1897
1898 let mut symbols = Vec::new();
1899
1900 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1901 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1902 if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum)
1903 || info.used
1904 || info.rustc_std_internal_symbol
1905 {
1906 symbols.push((
1907 symbol_export::linking_symbol_name_for_instance_in_crate(
1908 tcx, symbol, info.kind, cnum,
1909 ),
1910 info.kind,
1911 ));
1912 }
1913 });
1914
1915 symbols
1916}
1917
1918struct PtxLinker<'a> {
1921 cmd: Command,
1922 sess: &'a Session,
1923}
1924
1925impl<'a> Linker for PtxLinker<'a> {
1926 fn cmd(&mut self) -> &mut Command {
1927 &mut self.cmd
1928 }
1929
1930 fn set_output_kind(
1931 &mut self,
1932 _output_kind: LinkOutputKind,
1933 _crate_type: CrateType,
1934 _out_filename: &Path,
1935 ) {
1936 }
1937
1938 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1939 panic!("staticlibs not supported")
1940 }
1941
1942 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1943 self.link_arg("--rlib").link_arg(path);
1944 }
1945
1946 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1947 self.link_arg("--debug");
1948 }
1949
1950 fn add_object(&mut self, path: &Path) {
1951 self.link_arg("--bitcode").link_arg(path);
1952 }
1953
1954 fn optimize(&mut self) {
1955 match self.sess.lto() {
1956 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1957 self.link_arg("-Olto");
1958 }
1959
1960 Lto::No => {}
1961 }
1962 }
1963
1964 fn full_relro(&mut self) {}
1965
1966 fn partial_relro(&mut self) {}
1967
1968 fn no_relro(&mut self) {}
1969
1970 fn gc_sections(&mut self, _keep_metadata: bool) {}
1971
1972 fn pgo_gen(&mut self) {}
1973
1974 fn no_crt_objects(&mut self) {}
1975
1976 fn no_default_libraries(&mut self) {}
1977
1978 fn control_flow_guard(&mut self) {}
1979
1980 fn ehcont_guard(&mut self) {}
1981
1982 fn export_symbols(
1983 &mut self,
1984 _tmpdir: &Path,
1985 _crate_type: CrateType,
1986 _symbols: &[(String, SymbolExportKind)],
1987 ) {
1988 }
1989
1990 fn subsystem(&mut self, _subsystem: &str) {}
1991
1992 fn linker_plugin_lto(&mut self) {}
1993}
1994
1995struct LlbcLinker<'a> {
1997 cmd: Command,
1998 sess: &'a Session,
1999}
2000
2001impl<'a> Linker for LlbcLinker<'a> {
2002 fn cmd(&mut self) -> &mut Command {
2003 &mut self.cmd
2004 }
2005
2006 fn set_output_kind(
2007 &mut self,
2008 _output_kind: LinkOutputKind,
2009 _crate_type: CrateType,
2010 _out_filename: &Path,
2011 ) {
2012 }
2013
2014 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2015 panic!("staticlibs not supported")
2016 }
2017
2018 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2019 self.link_or_cc_arg(path);
2020 }
2021
2022 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2023 self.link_arg("--debug");
2024 }
2025
2026 fn optimize(&mut self) {
2027 self.link_arg(match self.sess.opts.optimize {
2028 OptLevel::No => "-O0",
2029 OptLevel::Less => "-O1",
2030 OptLevel::More => "-O2",
2031 OptLevel::Aggressive => "-O3",
2032 OptLevel::Size => "-Os",
2033 OptLevel::SizeMin => "-Oz",
2034 });
2035 }
2036
2037 fn full_relro(&mut self) {}
2038
2039 fn partial_relro(&mut self) {}
2040
2041 fn no_relro(&mut self) {}
2042
2043 fn gc_sections(&mut self, _keep_metadata: bool) {}
2044
2045 fn pgo_gen(&mut self) {}
2046
2047 fn no_crt_objects(&mut self) {}
2048
2049 fn no_default_libraries(&mut self) {}
2050
2051 fn control_flow_guard(&mut self) {}
2052
2053 fn ehcont_guard(&mut self) {}
2054
2055 fn export_symbols(
2056 &mut self,
2057 _tmpdir: &Path,
2058 _crate_type: CrateType,
2059 symbols: &[(String, SymbolExportKind)],
2060 ) {
2061 match _crate_type {
2062 CrateType::Cdylib => {
2063 for (sym, _) in symbols {
2064 self.link_args(&["--export-symbol", sym]);
2065 }
2066 }
2067 _ => (),
2068 }
2069 }
2070
2071 fn subsystem(&mut self, _subsystem: &str) {}
2072
2073 fn linker_plugin_lto(&mut self) {}
2074}
2075
2076struct BpfLinker<'a> {
2077 cmd: Command,
2078 sess: &'a Session,
2079}
2080
2081impl<'a> Linker for BpfLinker<'a> {
2082 fn cmd(&mut self) -> &mut Command {
2083 &mut self.cmd
2084 }
2085
2086 fn set_output_kind(
2087 &mut self,
2088 _output_kind: LinkOutputKind,
2089 _crate_type: CrateType,
2090 _out_filename: &Path,
2091 ) {
2092 }
2093
2094 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2095 panic!("staticlibs not supported")
2096 }
2097
2098 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2099 self.link_or_cc_arg(path);
2100 }
2101
2102 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2103 self.link_arg("--debug");
2104 }
2105
2106 fn optimize(&mut self) {
2107 self.link_arg(match self.sess.opts.optimize {
2108 OptLevel::No => "-O0",
2109 OptLevel::Less => "-O1",
2110 OptLevel::More => "-O2",
2111 OptLevel::Aggressive => "-O3",
2112 OptLevel::Size => "-Os",
2113 OptLevel::SizeMin => "-Oz",
2114 });
2115 }
2116
2117 fn full_relro(&mut self) {}
2118
2119 fn partial_relro(&mut self) {}
2120
2121 fn no_relro(&mut self) {}
2122
2123 fn gc_sections(&mut self, _keep_metadata: bool) {}
2124
2125 fn pgo_gen(&mut self) {}
2126
2127 fn no_crt_objects(&mut self) {}
2128
2129 fn no_default_libraries(&mut self) {}
2130
2131 fn control_flow_guard(&mut self) {}
2132
2133 fn ehcont_guard(&mut self) {}
2134
2135 fn export_symbols(
2136 &mut self,
2137 tmpdir: &Path,
2138 _crate_type: CrateType,
2139 symbols: &[(String, SymbolExportKind)],
2140 ) {
2141 let path = tmpdir.join("symbols");
2142 let res: io::Result<()> = try {
2143 let mut f = File::create_buffered(&path)?;
2144 for (sym, _) in symbols {
2145 writeln!(f, "{sym}")?;
2146 }
2147 };
2148 if let Err(error) = res {
2149 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2150 } else {
2151 self.link_arg("--export-symbols").link_arg(&path);
2152 }
2153 }
2154
2155 fn subsystem(&mut self, _subsystem: &str) {}
2156
2157 fn linker_plugin_lto(&mut self) {}
2158}