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