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