1use crate::args::parse;
2use args::Args;
3use tracing_subscriber::EnvFilter;
4use tracing_subscriber::fmt;
5use tracing_subscriber::layer::SubscriberExt;
6use tracing_subscriber::util::SubscriberInitExt;
7
8pub(crate) mod aarch64;
9pub(crate) mod alignment;
10pub(crate) mod arch;
11pub(crate) mod archive;
12pub(crate) mod archive_splitter;
13pub mod args;
14pub(crate) mod debug_trace;
15pub(crate) mod diff;
16pub(crate) mod elf;
17pub(crate) mod elf_writer;
18pub mod error;
19pub(crate) mod file_kind;
20pub(crate) mod fs;
21pub(crate) mod gc_stats;
22pub(crate) mod grouping;
23pub(crate) mod hash;
24pub(crate) mod identity;
25pub(crate) mod input_data;
26pub(crate) mod layout;
27pub(crate) mod linker_script;
28pub(crate) mod output_section_id;
29pub(crate) mod output_section_map;
30pub(crate) mod output_section_part_map;
31pub(crate) mod output_trace;
32pub(crate) mod parsing;
33pub(crate) mod part_id;
34pub(crate) mod program_segments;
35pub(crate) mod resolution;
36pub(crate) mod save_dir;
37pub(crate) mod sharding;
38pub(crate) mod shutdown;
39pub(crate) mod slice;
40pub(crate) mod storage;
41pub(crate) mod string_merging;
42#[cfg(feature = "fork")]
43pub(crate) mod subprocess;
44#[cfg(not(feature = "fork"))]
45#[path = "subprocess_unsupported.rs"]
46pub(crate) mod subprocess;
47pub(crate) mod symbol;
48pub(crate) mod symbol_db;
49pub(crate) mod timing;
50pub(crate) mod validation;
51pub(crate) mod verification;
52pub(crate) mod x86_64;
53
54pub use subprocess::run_in_subprocess;
55
56pub struct Linker {
57 args: Args,
58}
59
60impl Linker {
61 pub fn from_args<S: AsRef<str>, I: Iterator<Item = S>>(args: I) -> error::Result<Self> {
62 Ok(Linker { args: parse(args)? })
63 }
64
65 pub fn run(&self) -> error::Result {
66 self.run_with_callback(None)
67 }
68
69 pub(crate) fn run_with_callback(
72 &self,
73 done_closure: Option<Box<dyn FnOnce()>>,
74 ) -> error::Result {
75 let args = &self.args;
76 if args.time_phases {
77 timing::init_tracing();
78 } else if args.write_trace {
79 output_trace::init(args);
80 } else if args.print_allocations.is_some() {
81 debug_trace::init();
82 } else {
83 tracing_subscriber::registry()
84 .with(fmt::layer())
85 .with(EnvFilter::from_default_env())
86 .init();
87 }
88 if args.should_print_version {
89 println!(
90 "Wild version {} (compatible with GNU linkers)",
91 env!("CARGO_PKG_VERSION")
92 );
93 if args.inputs.is_empty() {
94 return Ok(());
95 }
96 }
97 match args.arch {
98 arch::Architecture::X86_64 => {
99 link::<storage::InMemory, x86_64::X86_64>(args, done_closure)
100 }
101 arch::Architecture::AArch64 => {
102 link::<storage::InMemory, aarch64::AArch64>(args, done_closure)
103 }
104 }
105 }
106
107 pub fn should_fork(&self) -> bool {
108 self.args.should_fork()
109 }
110}
111
112#[tracing::instrument(skip_all, name = "Link")]
113fn link<S: storage::StorageModel, A: arch::Arch>(
114 args: &Args,
115 done_closure: Option<Box<dyn FnOnce()>>,
116) -> error::Result {
117 args.setup_thread_pool()?;
118 let mut output = elf_writer::Output::new(args);
119 let input_data = input_data::InputData::from_args(args)?;
120 let inputs = archive_splitter::split_archives(&input_data)?;
121 let files = parsing::parse_input_files(&inputs, args)?;
122 let groups = grouping::group_files(files, args);
123 let herd = bumpalo_herd::Herd::new();
124 let mut symbol_db =
125 symbol_db::SymbolDb::<S>::build(&groups, input_data.version_script_data.as_ref(), args)?;
126 let resolved = resolution::resolve_symbols_and_sections(&groups, &mut symbol_db, &herd)?;
127 let layout = layout::compute::<S, A>(&symbol_db, resolved, &mut output)?;
128 let output_file = output.write::<S, A>(&layout)?;
129 diff::maybe_diff()?;
130
131 let scope = tracing::info_span!("Shutdown");
132 let _scope = scope.enter();
133 shutdown::free_output(output_file);
134 if let Some(done_callback) = done_closure {
136 done_callback();
137 }
138 shutdown::free_layout(layout);
139 shutdown::free_symbol_db(symbol_db);
140 shutdown::free_input_data(input_data);
141 Ok(())
142}