1use std::ffi::{OsStr, OsString};
2use std::fs::{self, File};
3use std::io::prelude::*;
4use std::path::{Path, PathBuf};
5use std::{env, io, iter, mem, str};
6
7use cc::windows_registry;
8use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
9use rustc_metadata::{
10 find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
11};
12use rustc_middle::bug;
13use rustc_middle::middle::dependency_format::Linkage;
14use rustc_middle::middle::exported_symbols;
15use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
16use rustc_middle::ty::TyCtxt;
17use rustc_session::Session;
18use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
19use rustc_span::sym;
20use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
21use tracing::{debug, warn};
22
23use super::command::Command;
24use super::symbol_export;
25use crate::errors;
26
27#[cfg(test)]
28mod tests;
29
30pub(crate) fn disable_localization(linker: &mut Command) {
36 linker.env("LC_ALL", "C");
39 linker.env("VSLANG", "1033");
41}
42
43pub(crate) fn get_linker<'a>(
47 sess: &'a Session,
48 linker: &Path,
49 flavor: LinkerFlavor,
50 self_contained: bool,
51 target_cpu: &'a str,
52) -> Box<dyn Linker + 'a> {
53 let msvc_tool = windows_registry::find_tool(&sess.target.arch, "link.exe");
54
55 let mut cmd = match linker.to_str() {
64 Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
65 _ => match flavor {
66 LinkerFlavor::Gnu(Cc::No, Lld::Yes)
67 | LinkerFlavor::Darwin(Cc::No, Lld::Yes)
68 | LinkerFlavor::WasmLld(Cc::No)
69 | LinkerFlavor::Msvc(Lld::Yes) => Command::lld(linker, flavor.lld_flavor()),
70 LinkerFlavor::Msvc(Lld::No)
71 if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() =>
72 {
73 Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
74 }
75 _ => Command::new(linker),
76 },
77 };
78
79 let t = &sess.target;
83 if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
84 if let Some(ref tool) = msvc_tool {
85 let original_path = tool.path();
86 if let Some(root_lib_path) = original_path.ancestors().nth(4) {
87 let arch = match t.arch.as_ref() {
88 "x86_64" => Some("x64"),
89 "x86" => Some("x86"),
90 "aarch64" => Some("arm64"),
91 "arm" => Some("arm"),
92 _ => None,
93 };
94 if let Some(ref a) = arch {
95 let mut arg = OsString::from("/LIBPATH:");
97 arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a));
98 cmd.arg(&arg);
99 } else {
100 warn!("arch is not supported");
101 }
102 } else {
103 warn!("MSVC root path lib location not found");
104 }
105 } else {
106 warn!("link.exe not found");
107 }
108 }
109
110 let mut new_path = sess.get_tools_search_paths(self_contained);
113 let mut msvc_changed_path = false;
114 if sess.target.is_like_msvc
115 && let Some(ref tool) = msvc_tool
116 {
117 cmd.args(tool.args());
118 for (k, v) in tool.env() {
119 if k == "PATH" {
120 new_path.extend(env::split_paths(v));
121 msvc_changed_path = true;
122 } else {
123 cmd.env(k, v);
124 }
125 }
126 }
127
128 if !msvc_changed_path && let Some(path) = env::var_os("PATH") {
129 new_path.extend(env::split_paths(&path));
130 }
131 cmd.env("PATH", env::join_paths(new_path).unwrap());
132
133 assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
136 match flavor {
137 LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
138 Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
139 }
140 LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
141 Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
142 }
143 LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
144 LinkerFlavor::Gnu(cc, _)
145 | LinkerFlavor::Darwin(cc, _)
146 | LinkerFlavor::WasmLld(cc)
147 | LinkerFlavor::Unix(cc) => Box::new(GccLinker {
148 cmd,
149 sess,
150 target_cpu,
151 hinted_static: None,
152 is_ld: cc == Cc::No,
153 is_gnu: flavor.is_gnu(),
154 uses_lld: flavor.uses_lld(),
155 }) as Box<dyn Linker>,
156 LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
157 LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
158 LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
159 LinkerFlavor::Llbc => Box::new(LlbcLinker { cmd, sess }) as Box<dyn Linker>,
160 LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
161 }
162}
163
164fn verbatim_args<L: Linker + ?Sized>(
174 l: &mut L,
175 args: impl IntoIterator<Item: AsRef<OsStr>>,
176) -> &mut L {
177 for arg in args {
178 l.cmd().arg(arg);
179 }
180 l
181}
182fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
185 let mut combined_arg = OsString::from("-Wl");
186 for arg in args {
187 if arg.as_ref().as_encoded_bytes().contains(&b',') {
190 if combined_arg != OsStr::new("-Wl") {
192 cmd.arg(combined_arg);
193 combined_arg = OsString::from("-Wl");
195 }
196
197 cmd.arg("-Xlinker");
199 cmd.arg(arg);
200 } else {
201 combined_arg.push(",");
203 combined_arg.push(arg);
204 }
205 }
206 if combined_arg != OsStr::new("-Wl") {
208 cmd.arg(combined_arg);
209 }
210}
211fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
214 if !l.is_cc() {
215 verbatim_args(l, args);
216 } else {
217 convert_link_args_to_cc_args(l.cmd(), args);
218 }
219 l
220}
221fn cc_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
224 assert!(l.is_cc());
225 verbatim_args(l, args)
226}
227fn link_or_cc_args<L: Linker + ?Sized>(
229 l: &mut L,
230 args: impl IntoIterator<Item: AsRef<OsStr>>,
231) -> &mut L {
232 verbatim_args(l, args)
233}
234
235macro_rules! generate_arg_methods {
236 ($($ty:ty)*) => { $(
237 impl $ty {
238 #[allow(unused)]
239 pub(crate) fn verbatim_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
240 verbatim_args(self, args)
241 }
242 #[allow(unused)]
243 pub(crate) fn verbatim_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
244 verbatim_args(self, iter::once(arg))
245 }
246 #[allow(unused)]
247 pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
248 link_args(self, args)
249 }
250 #[allow(unused)]
251 pub(crate) fn link_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
252 link_args(self, iter::once(arg))
253 }
254 #[allow(unused)]
255 pub(crate) fn cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
256 cc_args(self, args)
257 }
258 #[allow(unused)]
259 pub(crate) fn cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
260 cc_args(self, iter::once(arg))
261 }
262 #[allow(unused)]
263 pub(crate) fn link_or_cc_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
264 link_or_cc_args(self, args)
265 }
266 #[allow(unused)]
267 pub(crate) fn link_or_cc_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
268 link_or_cc_args(self, iter::once(arg))
269 }
270 }
271 )* }
272}
273
274generate_arg_methods! {
275 GccLinker<'_>
276 MsvcLinker<'_>
277 EmLinker<'_>
278 WasmLd<'_>
279 L4Bender<'_>
280 AixLinker<'_>
281 LlbcLinker<'_>
282 PtxLinker<'_>
283 BpfLinker<'_>
284 dyn Linker + '_
285}
286
287pub(crate) trait Linker {
295 fn cmd(&mut self) -> &mut Command;
296 fn is_cc(&self) -> bool {
297 false
298 }
299 fn set_output_kind(
300 &mut self,
301 output_kind: LinkOutputKind,
302 crate_type: CrateType,
303 out_filename: &Path,
304 );
305 fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
306 bug!("dylib linked with unsupported linker")
307 }
308 fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) {
309 bug!("dylib linked with unsupported linker")
310 }
311 fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
312 bug!("framework linked with unsupported linker")
313 }
314 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool);
315 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
316 fn include_path(&mut self, path: &Path) {
317 link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]);
318 }
319 fn framework_path(&mut self, _path: &Path) {
320 bug!("framework path set with unsupported linker")
321 }
322 fn output_filename(&mut self, path: &Path) {
323 link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]);
324 }
325 fn add_object(&mut self, path: &Path) {
326 link_or_cc_args(self, &[path]);
327 }
328 fn gc_sections(&mut self, keep_metadata: bool);
329 fn no_gc_sections(&mut self);
330 fn full_relro(&mut self);
331 fn partial_relro(&mut self);
332 fn no_relro(&mut self);
333 fn optimize(&mut self);
334 fn pgo_gen(&mut self);
335 fn control_flow_guard(&mut self);
336 fn ehcont_guard(&mut self);
337 fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
338 fn no_crt_objects(&mut self);
339 fn no_default_libraries(&mut self);
340 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
341 fn subsystem(&mut self, subsystem: &str);
342 fn linker_plugin_lto(&mut self);
343 fn add_eh_frame_header(&mut self) {}
344 fn add_no_exec(&mut self) {}
345 fn add_as_needed(&mut self) {}
346 fn reset_per_library_state(&mut self) {}
347}
348
349impl dyn Linker + '_ {
350 pub(crate) fn take_cmd(&mut self) -> Command {
351 mem::replace(self.cmd(), Command::new(""))
352 }
353}
354
355struct GccLinker<'a> {
356 cmd: Command,
357 sess: &'a Session,
358 target_cpu: &'a str,
359 hinted_static: Option<bool>, is_ld: bool,
362 is_gnu: bool,
363 uses_lld: bool,
364}
365
366impl<'a> GccLinker<'a> {
367 fn takes_hints(&self) -> bool {
368 !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm
377 }
378
379 fn hint_static(&mut self) {
384 if !self.takes_hints() {
385 return;
386 }
387 if self.hinted_static != Some(true) {
388 self.link_arg("-Bstatic");
389 self.hinted_static = Some(true);
390 }
391 }
392
393 fn hint_dynamic(&mut self) {
394 if !self.takes_hints() {
395 return;
396 }
397 if self.hinted_static != Some(false) {
398 self.link_arg("-Bdynamic");
399 self.hinted_static = Some(false);
400 }
401 }
402
403 fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
404 if let Some(plugin_path) = plugin_path {
405 let mut arg = OsString::from("-plugin=");
406 arg.push(plugin_path);
407 self.link_arg(&arg);
408 }
409
410 let opt_level = match self.sess.opts.optimize {
411 config::OptLevel::No => "O0",
412 config::OptLevel::Less => "O1",
413 config::OptLevel::More | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
414 config::OptLevel::Aggressive => "O3",
415 };
416
417 if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use {
418 self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
419 };
420 self.link_args(&[
421 &format!("-plugin-opt={opt_level}"),
422 &format!("-plugin-opt=mcpu={}", self.target_cpu),
423 ]);
424 }
425
426 fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
427 if self.sess.target.is_like_osx {
429 if self.is_cc() {
430 self.cc_arg("-dynamiclib");
432 } else {
433 self.link_arg("-dylib");
434 }
436
437 if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {
442 let mut rpath = OsString::from("@rpath/");
443 rpath.push(out_filename.file_name().unwrap());
444 self.link_arg("-install_name").link_arg(rpath);
445 }
446 } else {
447 self.link_or_cc_arg("-shared");
448 if let Some(name) = out_filename.file_name() {
449 if self.sess.target.is_like_windows {
450 let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix);
454 implib_name.push(name);
455 implib_name.push(&*self.sess.target.staticlib_suffix);
456 let mut out_implib = OsString::from("--out-implib=");
457 out_implib.push(out_filename.with_file_name(implib_name));
458 self.link_arg(out_implib);
459 } else if crate_type == CrateType::Dylib {
460 let mut soname = OsString::from("-soname=");
464 soname.push(name);
465 self.link_arg(soname);
466 }
467 }
468 }
469 }
470
471 fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) {
472 if !as_needed {
473 if self.sess.target.is_like_osx {
474 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
478 } else if self.is_gnu && !self.sess.target.is_like_windows {
479 self.link_arg("--no-as-needed");
480 } else {
481 self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier);
482 }
483 }
484
485 f(self);
486
487 if !as_needed {
488 if self.sess.target.is_like_osx {
489 } else if self.is_gnu && !self.sess.target.is_like_windows {
491 self.link_arg("--as-needed");
492 }
493 }
494 }
495}
496
497impl<'a> Linker for GccLinker<'a> {
498 fn cmd(&mut self) -> &mut Command {
499 &mut self.cmd
500 }
501
502 fn is_cc(&self) -> bool {
503 !self.is_ld
504 }
505
506 fn set_output_kind(
507 &mut self,
508 output_kind: LinkOutputKind,
509 crate_type: CrateType,
510 out_filename: &Path,
511 ) {
512 match output_kind {
513 LinkOutputKind::DynamicNoPicExe => {
514 if !self.is_ld && self.is_gnu {
515 self.cc_arg("-no-pie");
516 }
517 }
518 LinkOutputKind::DynamicPicExe => {
519 if !self.sess.target.is_like_windows {
521 self.link_or_cc_arg("-pie");
523 }
524 }
525 LinkOutputKind::StaticNoPicExe => {
526 self.link_or_cc_arg("-static");
528 if !self.is_ld && self.is_gnu {
529 self.cc_arg("-no-pie");
530 }
531 }
532 LinkOutputKind::StaticPicExe => {
533 if !self.is_ld {
534 self.cc_arg("-static-pie");
537 } else {
538 self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
544 }
545 }
546 LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
547 LinkOutputKind::StaticDylib => {
548 self.link_or_cc_arg("-static");
549 self.build_dylib(crate_type, out_filename);
550 }
551 LinkOutputKind::WasiReactorExe => {
552 self.link_args(&["--entry", "_initialize"]);
553 }
554 }
555
556 if self.sess.target.os == "vxworks"
562 && matches!(
563 output_kind,
564 LinkOutputKind::StaticNoPicExe
565 | LinkOutputKind::StaticPicExe
566 | LinkOutputKind::StaticDylib
567 )
568 {
569 self.cc_arg("--static-crt");
570 }
571
572 if self.sess.target.arch == "avr" && !self.uses_lld {
578 self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
579 }
580 }
581
582 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
583 if self.sess.target.os == "illumos" && name == "c" {
584 return;
590 }
591 self.hint_dynamic();
592 self.with_as_needed(as_needed, |this| {
593 let colon = if verbatim && this.is_gnu { ":" } else { "" };
594 this.link_or_cc_arg(format!("-l{colon}{name}"));
595 });
596 }
597
598 fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) {
599 self.hint_dynamic();
600 self.with_as_needed(as_needed, |this| {
601 this.link_or_cc_arg(path);
602 })
603 }
604
605 fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
606 self.hint_dynamic();
607 if !as_needed {
608 self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
612 }
613 self.link_or_cc_args(&["-framework", name]);
614 }
615
616 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
617 self.hint_static();
618 let colon = if verbatim && self.is_gnu { ":" } else { "" };
619 if !whole_archive {
620 self.link_or_cc_arg(format!("-l{colon}{name}"));
621 } else if self.sess.target.is_like_osx {
622 self.link_arg("-force_load");
625 self.link_arg(find_native_static_library(name, verbatim, self.sess));
626 } else {
627 self.link_arg("--whole-archive")
628 .link_or_cc_arg(format!("-l{colon}{name}"))
629 .link_arg("--no-whole-archive");
630 }
631 }
632
633 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
634 self.hint_static();
635 if !whole_archive {
636 self.link_or_cc_arg(path);
637 } else if self.sess.target.is_like_osx {
638 self.link_arg("-force_load").link_arg(path);
639 } else {
640 self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive");
641 }
642 }
643
644 fn framework_path(&mut self, path: &Path) {
645 self.link_or_cc_arg("-F").link_or_cc_arg(path);
646 }
647 fn full_relro(&mut self) {
648 self.link_args(&["-z", "relro", "-z", "now"]);
649 }
650 fn partial_relro(&mut self) {
651 self.link_args(&["-z", "relro"]);
652 }
653 fn no_relro(&mut self) {
654 self.link_args(&["-z", "norelro"]);
655 }
656
657 fn gc_sections(&mut self, keep_metadata: bool) {
658 if self.sess.target.is_like_osx {
673 self.link_arg("-dead_strip");
674
675 } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata {
681 self.link_arg("--gc-sections");
682 }
683 }
684
685 fn no_gc_sections(&mut self) {
686 if self.is_gnu || self.sess.target.is_like_wasm {
687 self.link_arg("--no-gc-sections");
688 }
689 }
690
691 fn optimize(&mut self) {
692 if !self.is_gnu && !self.sess.target.is_like_wasm {
693 return;
694 }
695
696 if self.sess.opts.optimize == config::OptLevel::More
699 || self.sess.opts.optimize == config::OptLevel::Aggressive
700 {
701 self.link_arg("-O1");
702 }
703 }
704
705 fn pgo_gen(&mut self) {
706 if !self.is_gnu {
707 return;
708 }
709
710 self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]);
722 }
723
724 fn control_flow_guard(&mut self) {}
725
726 fn ehcont_guard(&mut self) {}
727
728 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
729 if self.sess.target.is_like_osx {
731 return;
732 }
733
734 match strip {
735 Strip::None => {}
736 Strip::Debuginfo => {
737 if !self.sess.target.is_like_solaris {
742 self.link_arg("--strip-debug");
743 }
744 }
745 Strip::Symbols => {
746 self.link_arg("--strip-all");
747 }
748 }
749 match self.sess.opts.unstable_opts.debuginfo_compression {
750 config::DebugInfoCompression::None => {}
751 config::DebugInfoCompression::Zlib => {
752 self.link_arg("--compress-debug-sections=zlib");
753 }
754 config::DebugInfoCompression::Zstd => {
755 self.link_arg("--compress-debug-sections=zstd");
756 }
757 }
758 }
759
760 fn no_crt_objects(&mut self) {
761 if !self.is_ld {
762 self.cc_arg("-nostartfiles");
763 }
764 }
765
766 fn no_default_libraries(&mut self) {
767 if !self.is_ld {
768 self.cc_arg("-nodefaultlibs");
769 }
770 }
771
772 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
773 if crate_type == CrateType::Executable {
775 let should_export_executable_symbols =
776 self.sess.opts.unstable_opts.export_executable_symbols;
777 if self.sess.target.override_export_symbols.is_none()
778 && !should_export_executable_symbols
779 {
780 return;
781 }
782 }
783
784 if !self.sess.target.limit_rdylib_exports {
789 return;
790 }
791
792 let is_windows = self.sess.target.is_like_windows;
793 let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
794
795 debug!("EXPORTED SYMBOLS:");
796
797 if self.sess.target.is_like_osx {
798 let res: io::Result<()> = try {
800 let mut f = File::create_buffered(&path)?;
801 for sym in symbols {
802 debug!(" _{sym}");
803 writeln!(f, "_{sym}")?;
804 }
805 };
806 if let Err(error) = res {
807 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
808 }
809 } else if is_windows {
810 let res: io::Result<()> = try {
811 let mut f = File::create_buffered(&path)?;
812
813 writeln!(f, "EXPORTS")?;
816 for symbol in symbols {
817 debug!(" _{symbol}");
818 writeln!(f, " {symbol}")?;
819 }
820 };
821 if let Err(error) = res {
822 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
823 }
824 } else {
825 let res: io::Result<()> = try {
827 let mut f = File::create_buffered(&path)?;
828 writeln!(f, "{{")?;
829 if !symbols.is_empty() {
830 writeln!(f, " global:")?;
831 for sym in symbols {
832 debug!(" {sym};");
833 writeln!(f, " {sym};")?;
834 }
835 }
836 writeln!(f, "\n local:\n *;\n}};")?;
837 };
838 if let Err(error) = res {
839 self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
840 }
841 }
842
843 if self.sess.target.is_like_osx {
844 self.link_arg("-exported_symbols_list").link_arg(path);
845 } else if self.sess.target.is_like_solaris {
846 self.link_arg("-M").link_arg(path);
847 } else if is_windows {
848 self.link_arg(path);
849 } else {
850 let mut arg = OsString::from("--version-script=");
851 arg.push(path);
852 self.link_arg(arg).link_arg("--no-undefined-version");
853 }
854 }
855
856 fn subsystem(&mut self, subsystem: &str) {
857 self.link_args(&["--subsystem", subsystem]);
858 }
859
860 fn reset_per_library_state(&mut self) {
861 self.hint_dynamic(); }
863
864 fn linker_plugin_lto(&mut self) {
865 match self.sess.opts.cg.linker_plugin_lto {
866 LinkerPluginLto::Disabled => {
867 }
869 LinkerPluginLto::LinkerPluginAuto => {
870 self.push_linker_plugin_lto_args(None);
871 }
872 LinkerPluginLto::LinkerPlugin(ref path) => {
873 self.push_linker_plugin_lto_args(Some(path.as_os_str()));
874 }
875 }
876 }
877
878 fn add_eh_frame_header(&mut self) {
882 self.link_arg("--eh-frame-hdr");
883 }
884
885 fn add_no_exec(&mut self) {
886 if self.sess.target.is_like_windows {
887 self.link_arg("--nxcompat");
888 } else if self.is_gnu {
889 self.link_args(&["-z", "noexecstack"]);
890 }
891 }
892
893 fn add_as_needed(&mut self) {
894 if self.is_gnu && !self.sess.target.is_like_windows {
895 self.link_arg("--as-needed");
896 } else if self.sess.target.is_like_solaris {
897 self.link_args(&["-z", "ignore"]);
899 }
900 }
901}
902
903struct MsvcLinker<'a> {
904 cmd: Command,
905 sess: &'a Session,
906}
907
908impl<'a> Linker for MsvcLinker<'a> {
909 fn cmd(&mut self) -> &mut Command {
910 &mut self.cmd
911 }
912
913 fn set_output_kind(
914 &mut self,
915 output_kind: LinkOutputKind,
916 _crate_type: CrateType,
917 out_filename: &Path,
918 ) {
919 match output_kind {
920 LinkOutputKind::DynamicNoPicExe
921 | LinkOutputKind::DynamicPicExe
922 | LinkOutputKind::StaticNoPicExe
923 | LinkOutputKind::StaticPicExe => {}
924 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
925 self.link_arg("/DLL");
926 let mut arg: OsString = "/IMPLIB:".into();
927 arg.push(out_filename.with_extension("dll.lib"));
928 self.link_arg(arg);
929 }
930 LinkOutputKind::WasiReactorExe => {
931 panic!("can't link as reactor on non-wasi target");
932 }
933 }
934 }
935
936 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
937 if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) {
940 self.link_arg(path);
941 } else {
942 self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
943 }
944 }
945
946 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
947 let implib_path = path.with_extension("dll.lib");
950 if implib_path.exists() {
951 self.link_or_cc_arg(implib_path);
952 }
953 }
954
955 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
956 if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
959 self.link_staticlib_by_path(&path, whole_archive);
960 } else {
961 let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
962 let suffix = if verbatim { "" } else { ".lib" };
963 self.link_arg(format!("{prefix}{name}{suffix}"));
964 }
965 }
966
967 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
968 if !whole_archive {
969 self.link_arg(path);
970 } else {
971 let mut arg = OsString::from("/WHOLEARCHIVE:");
972 arg.push(path);
973 self.link_arg(arg);
974 }
975 }
976
977 fn gc_sections(&mut self, _keep_metadata: bool) {
978 if self.sess.opts.optimize != config::OptLevel::No {
982 self.link_arg("/OPT:REF,ICF");
983 } else {
984 self.link_arg("/OPT:REF,NOICF");
987 }
988 }
989
990 fn no_gc_sections(&mut self) {
991 self.link_arg("/OPT:NOREF,NOICF");
992 }
993
994 fn full_relro(&mut self) {
995 }
997
998 fn partial_relro(&mut self) {
999 }
1001
1002 fn no_relro(&mut self) {
1003 }
1005
1006 fn no_crt_objects(&mut self) {
1007 }
1009
1010 fn no_default_libraries(&mut self) {
1011 self.link_arg("/NODEFAULTLIB");
1012 }
1013
1014 fn include_path(&mut self, path: &Path) {
1015 let mut arg = OsString::from("/LIBPATH:");
1016 arg.push(path);
1017 self.link_arg(&arg);
1018 }
1019
1020 fn output_filename(&mut self, path: &Path) {
1021 let mut arg = OsString::from("/OUT:");
1022 arg.push(path);
1023 self.link_arg(&arg);
1024 }
1025
1026 fn optimize(&mut self) {
1027 }
1029
1030 fn pgo_gen(&mut self) {
1031 }
1033
1034 fn control_flow_guard(&mut self) {
1035 self.link_arg("/guard:cf");
1036 }
1037
1038 fn ehcont_guard(&mut self) {
1039 if self.sess.target.pointer_width == 64 {
1040 self.link_arg("/guard:ehcont");
1041 }
1042 }
1043
1044 fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
1045 self.link_arg("/DEBUG");
1048
1049 self.link_arg("/PDBALTPATH:%_PDB%");
1057
1058 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
1060 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
1061 for entry in natvis_dir {
1062 match entry {
1063 Ok(entry) => {
1064 let path = entry.path();
1065 if path.extension() == Some("natvis".as_ref()) {
1066 let mut arg = OsString::from("/NATVIS:");
1067 arg.push(path);
1068 self.link_arg(arg);
1069 }
1070 }
1071 Err(error) => {
1072 self.sess.dcx().emit_warn(errors::NoNatvisDirectory { error });
1073 }
1074 }
1075 }
1076 }
1077
1078 for path in natvis_debugger_visualizers {
1080 let mut arg = OsString::from("/NATVIS:");
1081 arg.push(path);
1082 self.link_arg(arg);
1083 }
1084 }
1085
1086 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
1099 if crate_type == CrateType::Executable {
1101 let should_export_executable_symbols =
1102 self.sess.opts.unstable_opts.export_executable_symbols;
1103 if !should_export_executable_symbols {
1104 return;
1105 }
1106 }
1107
1108 let path = tmpdir.join("lib.def");
1109 let res: io::Result<()> = try {
1110 let mut f = File::create_buffered(&path)?;
1111
1112 writeln!(f, "LIBRARY")?;
1115 writeln!(f, "EXPORTS")?;
1116 for symbol in symbols {
1117 debug!(" _{symbol}");
1118 writeln!(f, " {symbol}")?;
1119 }
1120 };
1121 if let Err(error) = res {
1122 self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
1123 }
1124 let mut arg = OsString::from("/DEF:");
1125 arg.push(path);
1126 self.link_arg(&arg);
1127 }
1128
1129 fn subsystem(&mut self, subsystem: &str) {
1130 self.link_arg(&format!("/SUBSYSTEM:{subsystem}"));
1133
1134 if subsystem == "windows" {
1149 self.link_arg("/ENTRY:mainCRTStartup");
1150 }
1151 }
1152
1153 fn linker_plugin_lto(&mut self) {
1154 }
1156
1157 fn add_no_exec(&mut self) {
1158 self.link_arg("/NXCOMPAT");
1159 }
1160}
1161
1162struct EmLinker<'a> {
1163 cmd: Command,
1164 sess: &'a Session,
1165}
1166
1167impl<'a> Linker for EmLinker<'a> {
1168 fn cmd(&mut self) -> &mut Command {
1169 &mut self.cmd
1170 }
1171
1172 fn is_cc(&self) -> bool {
1173 true
1174 }
1175
1176 fn set_output_kind(
1177 &mut self,
1178 _output_kind: LinkOutputKind,
1179 _crate_type: CrateType,
1180 _out_filename: &Path,
1181 ) {
1182 }
1183
1184 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1185 self.link_or_cc_args(&["-l", name]);
1187 }
1188
1189 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1190 self.link_or_cc_arg(path);
1191 }
1192
1193 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) {
1194 self.link_or_cc_args(&["-l", name]);
1195 }
1196
1197 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1198 self.link_or_cc_arg(path);
1199 }
1200
1201 fn full_relro(&mut self) {
1202 }
1204
1205 fn partial_relro(&mut self) {
1206 }
1208
1209 fn no_relro(&mut self) {
1210 }
1212
1213 fn gc_sections(&mut self, _keep_metadata: bool) {
1214 }
1216
1217 fn no_gc_sections(&mut self) {
1218 }
1220
1221 fn optimize(&mut self) {
1222 self.cc_arg(match self.sess.opts.optimize {
1224 OptLevel::No => "-O0",
1225 OptLevel::Less => "-O1",
1226 OptLevel::More => "-O2",
1227 OptLevel::Aggressive => "-O3",
1228 OptLevel::Size => "-Os",
1229 OptLevel::SizeMin => "-Oz",
1230 });
1231 }
1232
1233 fn pgo_gen(&mut self) {
1234 }
1236
1237 fn control_flow_guard(&mut self) {}
1238
1239 fn ehcont_guard(&mut self) {}
1240
1241 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1242 self.cc_arg(match self.sess.opts.debuginfo {
1245 DebugInfo::None => "-g0",
1246 DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => {
1247 "--profiling-funcs"
1248 }
1249 DebugInfo::Full => "-g",
1250 });
1251 }
1252
1253 fn no_crt_objects(&mut self) {}
1254
1255 fn no_default_libraries(&mut self) {
1256 self.cc_arg("-nodefaultlibs");
1257 }
1258
1259 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1260 debug!("EXPORTED SYMBOLS:");
1261
1262 self.cc_arg("-s");
1263
1264 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
1265 let encoded = serde_json::to_string(
1266 &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
1267 )
1268 .unwrap();
1269 debug!("{encoded}");
1270
1271 arg.push(encoded);
1272
1273 self.cc_arg(arg);
1274 }
1275
1276 fn subsystem(&mut self, _subsystem: &str) {
1277 }
1279
1280 fn linker_plugin_lto(&mut self) {
1281 }
1283}
1284
1285struct WasmLd<'a> {
1286 cmd: Command,
1287 sess: &'a Session,
1288}
1289
1290impl<'a> WasmLd<'a> {
1291 fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
1292 let mut wasm_ld = WasmLd { cmd, sess };
1311 if sess.target_features.contains(&sym::atomics) {
1312 wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
1313 if sess.target.os == "unknown" || sess.target.os == "none" {
1314 wasm_ld.link_args(&[
1315 "--export=__wasm_init_tls",
1316 "--export=__tls_size",
1317 "--export=__tls_align",
1318 "--export=__tls_base",
1319 ]);
1320 }
1321 }
1322 wasm_ld
1323 }
1324}
1325
1326impl<'a> Linker for WasmLd<'a> {
1327 fn cmd(&mut self) -> &mut Command {
1328 &mut self.cmd
1329 }
1330
1331 fn set_output_kind(
1332 &mut self,
1333 output_kind: LinkOutputKind,
1334 _crate_type: CrateType,
1335 _out_filename: &Path,
1336 ) {
1337 match output_kind {
1338 LinkOutputKind::DynamicNoPicExe
1339 | LinkOutputKind::DynamicPicExe
1340 | LinkOutputKind::StaticNoPicExe
1341 | LinkOutputKind::StaticPicExe => {}
1342 LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1343 self.link_arg("--no-entry");
1344 }
1345 LinkOutputKind::WasiReactorExe => {
1346 self.link_args(&["--entry", "_initialize"]);
1347 }
1348 }
1349 }
1350
1351 fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
1352 self.link_or_cc_args(&["-l", name]);
1353 }
1354
1355 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1356 self.link_or_cc_arg(path);
1357 }
1358
1359 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1360 if !whole_archive {
1361 self.link_or_cc_args(&["-l", name]);
1362 } else {
1363 self.link_arg("--whole-archive")
1364 .link_or_cc_args(&["-l", name])
1365 .link_arg("--no-whole-archive");
1366 }
1367 }
1368
1369 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1370 if !whole_archive {
1371 self.link_or_cc_arg(path);
1372 } else {
1373 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1374 }
1375 }
1376
1377 fn full_relro(&mut self) {}
1378
1379 fn partial_relro(&mut self) {}
1380
1381 fn no_relro(&mut self) {}
1382
1383 fn gc_sections(&mut self, _keep_metadata: bool) {
1384 self.link_arg("--gc-sections");
1385 }
1386
1387 fn no_gc_sections(&mut self) {
1388 self.link_arg("--no-gc-sections");
1389 }
1390
1391 fn optimize(&mut self) {
1392 self.link_arg(match self.sess.opts.optimize {
1395 OptLevel::No => "-O0",
1396 OptLevel::Less => "-O1",
1397 OptLevel::More => "-O2",
1398 OptLevel::Aggressive => "-O3",
1399 OptLevel::Size => "-O2",
1402 OptLevel::SizeMin => "-O2",
1403 });
1404 }
1405
1406 fn pgo_gen(&mut self) {}
1407
1408 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1409 match strip {
1410 Strip::None => {}
1411 Strip::Debuginfo => {
1412 self.link_arg("--strip-debug");
1413 }
1414 Strip::Symbols => {
1415 self.link_arg("--strip-all");
1416 }
1417 }
1418 }
1419
1420 fn control_flow_guard(&mut self) {}
1421
1422 fn ehcont_guard(&mut self) {}
1423
1424 fn no_crt_objects(&mut self) {}
1425
1426 fn no_default_libraries(&mut self) {}
1427
1428 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1429 for sym in symbols {
1430 self.link_args(&["--export", sym]);
1431 }
1432
1433 if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
1438 self.link_args(&["--export=__heap_base", "--export=__data_end"]);
1439 }
1440 }
1441
1442 fn subsystem(&mut self, _subsystem: &str) {}
1443
1444 fn linker_plugin_lto(&mut self) {
1445 match self.sess.opts.cg.linker_plugin_lto {
1446 LinkerPluginLto::Disabled => {
1447 }
1449 LinkerPluginLto::LinkerPluginAuto => {
1450 self.push_linker_plugin_lto_args();
1451 }
1452 LinkerPluginLto::LinkerPlugin(_) => {
1453 self.push_linker_plugin_lto_args();
1454 }
1455 }
1456 }
1457}
1458
1459impl<'a> WasmLd<'a> {
1460 fn push_linker_plugin_lto_args(&mut self) {
1461 let opt_level = match self.sess.opts.optimize {
1462 config::OptLevel::No => "O0",
1463 config::OptLevel::Less => "O1",
1464 config::OptLevel::More => "O2",
1465 config::OptLevel::Aggressive => "O3",
1466 config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
1468 };
1469 self.link_arg(&format!("--lto-{opt_level}"));
1470 }
1471}
1472
1473struct L4Bender<'a> {
1475 cmd: Command,
1476 sess: &'a Session,
1477 hinted_static: bool,
1478}
1479
1480impl<'a> Linker for L4Bender<'a> {
1481 fn cmd(&mut self) -> &mut Command {
1482 &mut self.cmd
1483 }
1484
1485 fn set_output_kind(
1486 &mut self,
1487 _output_kind: LinkOutputKind,
1488 _crate_type: CrateType,
1489 _out_filename: &Path,
1490 ) {
1491 }
1492
1493 fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
1494 self.hint_static();
1495 if !whole_archive {
1496 self.link_arg(format!("-PC{name}"));
1497 } else {
1498 self.link_arg("--whole-archive")
1499 .link_or_cc_arg(format!("-l{name}"))
1500 .link_arg("--no-whole-archive");
1501 }
1502 }
1503
1504 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1505 self.hint_static();
1506 if !whole_archive {
1507 self.link_or_cc_arg(path);
1508 } else {
1509 self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive");
1510 }
1511 }
1512
1513 fn full_relro(&mut self) {
1514 self.link_args(&["-z", "relro", "-z", "now"]);
1515 }
1516
1517 fn partial_relro(&mut self) {
1518 self.link_args(&["-z", "relro"]);
1519 }
1520
1521 fn no_relro(&mut self) {
1522 self.link_args(&["-z", "norelro"]);
1523 }
1524
1525 fn gc_sections(&mut self, keep_metadata: bool) {
1526 if !keep_metadata {
1527 self.link_arg("--gc-sections");
1528 }
1529 }
1530
1531 fn no_gc_sections(&mut self) {
1532 self.link_arg("--no-gc-sections");
1533 }
1534
1535 fn optimize(&mut self) {
1536 if self.sess.opts.optimize == config::OptLevel::More
1539 || self.sess.opts.optimize == config::OptLevel::Aggressive
1540 {
1541 self.link_arg("-O1");
1542 }
1543 }
1544
1545 fn pgo_gen(&mut self) {}
1546
1547 fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
1548 match strip {
1549 Strip::None => {}
1550 Strip::Debuginfo => {
1551 self.link_arg("--strip-debug");
1552 }
1553 Strip::Symbols => {
1554 self.link_arg("--strip-all");
1555 }
1556 }
1557 }
1558
1559 fn no_default_libraries(&mut self) {
1560 self.cc_arg("-nostdlib");
1561 }
1562
1563 fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
1564 self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
1566 }
1567
1568 fn subsystem(&mut self, subsystem: &str) {
1569 self.link_arg(&format!("--subsystem {subsystem}"));
1570 }
1571
1572 fn reset_per_library_state(&mut self) {
1573 self.hint_static(); }
1575
1576 fn linker_plugin_lto(&mut self) {}
1577
1578 fn control_flow_guard(&mut self) {}
1579
1580 fn ehcont_guard(&mut self) {}
1581
1582 fn no_crt_objects(&mut self) {}
1583}
1584
1585impl<'a> L4Bender<'a> {
1586 fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
1587 L4Bender { cmd, sess, hinted_static: false }
1588 }
1589
1590 fn hint_static(&mut self) {
1591 if !self.hinted_static {
1592 self.link_or_cc_arg("-static");
1593 self.hinted_static = true;
1594 }
1595 }
1596}
1597
1598struct AixLinker<'a> {
1600 cmd: Command,
1601 sess: &'a Session,
1602 hinted_static: Option<bool>,
1603}
1604
1605impl<'a> AixLinker<'a> {
1606 fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
1607 AixLinker { cmd, sess, hinted_static: None }
1608 }
1609
1610 fn hint_static(&mut self) {
1611 if self.hinted_static != Some(true) {
1612 self.link_arg("-bstatic");
1613 self.hinted_static = Some(true);
1614 }
1615 }
1616
1617 fn hint_dynamic(&mut self) {
1618 if self.hinted_static != Some(false) {
1619 self.link_arg("-bdynamic");
1620 self.hinted_static = Some(false);
1621 }
1622 }
1623
1624 fn build_dylib(&mut self, _out_filename: &Path) {
1625 self.link_args(&["-bM:SRE", "-bnoentry"]);
1626 self.link_arg("-bexpfull");
1629 }
1630}
1631
1632impl<'a> Linker for AixLinker<'a> {
1633 fn cmd(&mut self) -> &mut Command {
1634 &mut self.cmd
1635 }
1636
1637 fn set_output_kind(
1638 &mut self,
1639 output_kind: LinkOutputKind,
1640 _crate_type: CrateType,
1641 out_filename: &Path,
1642 ) {
1643 match output_kind {
1644 LinkOutputKind::DynamicDylib => {
1645 self.hint_dynamic();
1646 self.build_dylib(out_filename);
1647 }
1648 LinkOutputKind::StaticDylib => {
1649 self.hint_static();
1650 self.build_dylib(out_filename);
1651 }
1652 _ => {}
1653 }
1654 }
1655
1656 fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
1657 self.hint_dynamic();
1658 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1659 }
1660
1661 fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) {
1662 self.hint_dynamic();
1663 self.link_or_cc_arg(path);
1664 }
1665
1666 fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
1667 self.hint_static();
1668 if !whole_archive {
1669 self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") });
1670 } else {
1671 let mut arg = OsString::from("-bkeepfile:");
1672 arg.push(find_native_static_library(name, verbatim, self.sess));
1673 self.link_or_cc_arg(arg);
1674 }
1675 }
1676
1677 fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
1678 self.hint_static();
1679 if !whole_archive {
1680 self.link_or_cc_arg(path);
1681 } else {
1682 let mut arg = OsString::from("-bkeepfile:");
1683 arg.push(path);
1684 self.link_arg(arg);
1685 }
1686 }
1687
1688 fn full_relro(&mut self) {}
1689
1690 fn partial_relro(&mut self) {}
1691
1692 fn no_relro(&mut self) {}
1693
1694 fn gc_sections(&mut self, _keep_metadata: bool) {
1695 self.link_arg("-bgc");
1696 }
1697
1698 fn no_gc_sections(&mut self) {
1699 self.link_arg("-bnogc");
1700 }
1701
1702 fn optimize(&mut self) {}
1703
1704 fn pgo_gen(&mut self) {
1705 self.link_arg("-bdbg:namedsects:ss");
1706 self.link_arg("-u");
1707 self.link_arg("__llvm_profile_runtime");
1708 }
1709
1710 fn control_flow_guard(&mut self) {}
1711
1712 fn ehcont_guard(&mut self) {}
1713
1714 fn debuginfo(&mut self, _: Strip, _: &[PathBuf]) {}
1715
1716 fn no_crt_objects(&mut self) {}
1717
1718 fn no_default_libraries(&mut self) {}
1719
1720 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1721 let path = tmpdir.join("list.exp");
1722 let res: io::Result<()> = try {
1723 let mut f = File::create_buffered(&path)?;
1724 for symbol in symbols {
1726 debug!(" _{symbol}");
1727 writeln!(f, " {symbol}")?;
1728 }
1729 };
1730 if let Err(e) = res {
1731 self.sess.dcx().fatal(format!("failed to write export file: {e}"));
1732 }
1733 self.link_arg(format!("-bE:{}", path.to_str().unwrap()));
1734 }
1735
1736 fn subsystem(&mut self, _subsystem: &str) {}
1737
1738 fn reset_per_library_state(&mut self) {
1739 self.hint_dynamic();
1740 }
1741
1742 fn linker_plugin_lto(&mut self) {}
1743
1744 fn add_eh_frame_header(&mut self) {}
1745
1746 fn add_no_exec(&mut self) {}
1747
1748 fn add_as_needed(&mut self) {}
1749}
1750
1751fn for_each_exported_symbols_include_dep<'tcx>(
1752 tcx: TyCtxt<'tcx>,
1753 crate_type: CrateType,
1754 mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
1755) {
1756 let formats = tcx.dependency_formats(());
1757 let deps = &formats[&crate_type];
1758
1759 for (cnum, dep_format) in deps.iter_enumerated() {
1760 if *dep_format == Linkage::Static {
1762 for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
1763 callback(symbol, info, cnum);
1764 }
1765 }
1766 }
1767}
1768
1769pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1770 if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1771 return exports.iter().map(ToString::to_string).collect();
1772 }
1773
1774 if let CrateType::ProcMacro = crate_type {
1775 exported_symbols_for_proc_macro_crate(tcx)
1776 } else {
1777 exported_symbols_for_non_proc_macro(tcx, crate_type)
1778 }
1779}
1780
1781fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1782 let mut symbols = Vec::new();
1783 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1784 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1785 if info.level.is_below_threshold(export_threshold) {
1786 symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1787 tcx, symbol, cnum,
1788 ));
1789 symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1790 }
1791 });
1792
1793 symbols
1794}
1795
1796fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
1797 if !tcx.sess.opts.output_types.should_codegen() {
1799 return Vec::new();
1800 }
1801
1802 let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
1803 let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
1804 let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
1805
1806 vec![proc_macro_decls_name, metadata_symbol_name]
1807}
1808
1809pub(crate) fn linked_symbols(
1810 tcx: TyCtxt<'_>,
1811 crate_type: CrateType,
1812) -> Vec<(String, SymbolExportKind)> {
1813 match crate_type {
1814 CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
1815 CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
1816 return Vec::new();
1817 }
1818 }
1819
1820 let mut symbols = Vec::new();
1821
1822 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1823 for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
1824 if info.level.is_below_threshold(export_threshold) || info.used {
1825 symbols.push((
1826 symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1827 info.kind,
1828 ));
1829 }
1830 });
1831
1832 symbols
1833}
1834
1835struct PtxLinker<'a> {
1838 cmd: Command,
1839 sess: &'a Session,
1840}
1841
1842impl<'a> Linker for PtxLinker<'a> {
1843 fn cmd(&mut self) -> &mut Command {
1844 &mut self.cmd
1845 }
1846
1847 fn set_output_kind(
1848 &mut self,
1849 _output_kind: LinkOutputKind,
1850 _crate_type: CrateType,
1851 _out_filename: &Path,
1852 ) {
1853 }
1854
1855 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1856 panic!("staticlibs not supported")
1857 }
1858
1859 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1860 self.link_arg("--rlib").link_arg(path);
1861 }
1862
1863 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1864 self.link_arg("--debug");
1865 }
1866
1867 fn add_object(&mut self, path: &Path) {
1868 self.link_arg("--bitcode").link_arg(path);
1869 }
1870
1871 fn optimize(&mut self) {
1872 match self.sess.lto() {
1873 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1874 self.link_arg("-Olto");
1875 }
1876
1877 Lto::No => {}
1878 }
1879 }
1880
1881 fn full_relro(&mut self) {}
1882
1883 fn partial_relro(&mut self) {}
1884
1885 fn no_relro(&mut self) {}
1886
1887 fn gc_sections(&mut self, _keep_metadata: bool) {}
1888
1889 fn no_gc_sections(&mut self) {}
1890
1891 fn pgo_gen(&mut self) {}
1892
1893 fn no_crt_objects(&mut self) {}
1894
1895 fn no_default_libraries(&mut self) {}
1896
1897 fn control_flow_guard(&mut self) {}
1898
1899 fn ehcont_guard(&mut self) {}
1900
1901 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1902
1903 fn subsystem(&mut self, _subsystem: &str) {}
1904
1905 fn linker_plugin_lto(&mut self) {}
1906}
1907
1908struct LlbcLinker<'a> {
1910 cmd: Command,
1911 sess: &'a Session,
1912}
1913
1914impl<'a> Linker for LlbcLinker<'a> {
1915 fn cmd(&mut self) -> &mut Command {
1916 &mut self.cmd
1917 }
1918
1919 fn set_output_kind(
1920 &mut self,
1921 _output_kind: LinkOutputKind,
1922 _crate_type: CrateType,
1923 _out_filename: &Path,
1924 ) {
1925 }
1926
1927 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
1928 panic!("staticlibs not supported")
1929 }
1930
1931 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
1932 self.link_or_cc_arg(path);
1933 }
1934
1935 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
1936 self.link_arg("--debug");
1937 }
1938
1939 fn optimize(&mut self) {
1940 self.link_arg(match self.sess.opts.optimize {
1941 OptLevel::No => "-O0",
1942 OptLevel::Less => "-O1",
1943 OptLevel::More => "-O2",
1944 OptLevel::Aggressive => "-O3",
1945 OptLevel::Size => "-Os",
1946 OptLevel::SizeMin => "-Oz",
1947 });
1948 }
1949
1950 fn full_relro(&mut self) {}
1951
1952 fn partial_relro(&mut self) {}
1953
1954 fn no_relro(&mut self) {}
1955
1956 fn gc_sections(&mut self, _keep_metadata: bool) {}
1957
1958 fn no_gc_sections(&mut self) {}
1959
1960 fn pgo_gen(&mut self) {}
1961
1962 fn no_crt_objects(&mut self) {}
1963
1964 fn no_default_libraries(&mut self) {}
1965
1966 fn control_flow_guard(&mut self) {}
1967
1968 fn ehcont_guard(&mut self) {}
1969
1970 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1971 match _crate_type {
1972 CrateType::Cdylib => {
1973 for sym in symbols {
1974 self.link_args(&["--export-symbol", sym]);
1975 }
1976 }
1977 _ => (),
1978 }
1979 }
1980
1981 fn subsystem(&mut self, _subsystem: &str) {}
1982
1983 fn linker_plugin_lto(&mut self) {}
1984}
1985
1986struct BpfLinker<'a> {
1987 cmd: Command,
1988 sess: &'a Session,
1989}
1990
1991impl<'a> Linker for BpfLinker<'a> {
1992 fn cmd(&mut self) -> &mut Command {
1993 &mut self.cmd
1994 }
1995
1996 fn set_output_kind(
1997 &mut self,
1998 _output_kind: LinkOutputKind,
1999 _crate_type: CrateType,
2000 _out_filename: &Path,
2001 ) {
2002 }
2003
2004 fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
2005 panic!("staticlibs not supported")
2006 }
2007
2008 fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
2009 self.link_or_cc_arg(path);
2010 }
2011
2012 fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) {
2013 self.link_arg("--debug");
2014 }
2015
2016 fn optimize(&mut self) {
2017 self.link_arg(match self.sess.opts.optimize {
2018 OptLevel::No => "-O0",
2019 OptLevel::Less => "-O1",
2020 OptLevel::More => "-O2",
2021 OptLevel::Aggressive => "-O3",
2022 OptLevel::Size => "-Os",
2023 OptLevel::SizeMin => "-Oz",
2024 });
2025 }
2026
2027 fn full_relro(&mut self) {}
2028
2029 fn partial_relro(&mut self) {}
2030
2031 fn no_relro(&mut self) {}
2032
2033 fn gc_sections(&mut self, _keep_metadata: bool) {}
2034
2035 fn no_gc_sections(&mut self) {}
2036
2037 fn pgo_gen(&mut self) {}
2038
2039 fn no_crt_objects(&mut self) {}
2040
2041 fn no_default_libraries(&mut self) {}
2042
2043 fn control_flow_guard(&mut self) {}
2044
2045 fn ehcont_guard(&mut self) {}
2046
2047 fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2048 let path = tmpdir.join("symbols");
2049 let res: io::Result<()> = try {
2050 let mut f = File::create_buffered(&path)?;
2051 for sym in symbols {
2052 writeln!(f, "{sym}")?;
2053 }
2054 };
2055 if let Err(error) = res {
2056 self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
2057 } else {
2058 self.link_arg("--export-symbols").link_arg(&path);
2059 }
2060 }
2061
2062 fn subsystem(&mut self, _subsystem: &str) {}
2063
2064 fn linker_plugin_lto(&mut self) {}
2065}