]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 | 1 | use super::archive; |
dfeec247 XL |
2 | use super::command::Command; |
3 | use super::symbol_export; | |
f035d41b | 4 | use rustc_span::symbol::sym; |
a1dfa0c6 | 5 | |
cc61c64b | 6 | use std::ffi::{OsStr, OsString}; |
e9174d1e | 7 | use std::fs::{self, File}; |
e9174d1e | 8 | use std::io::prelude::*; |
9e0c209e | 9 | use std::io::{self, BufWriter}; |
62682a34 | 10 | use std::path::{Path, PathBuf}; |
136023e0 | 11 | use std::{env, mem, str}; |
3157f602 | 12 | |
dfeec247 | 13 | use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; |
ba9703b0 | 14 | use rustc_middle::middle::dependency_format::Linkage; |
04454e1e | 15 | use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; |
ba9703b0 | 16 | use rustc_middle::ty::TyCtxt; |
f9f354fc | 17 | use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; |
ba9703b0 | 18 | use rustc_session::Session; |
dfeec247 | 19 | use rustc_span::symbol::Symbol; |
f9f354fc XL |
20 | use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; |
21 | ||
136023e0 XL |
22 | use cc::windows_registry; |
23 | ||
f9f354fc XL |
24 | /// Disables non-English messages from localized linkers. |
25 | /// Such messages may cause issues with text encoding on Windows (#35785) | |
26 | /// and prevent inspection of linker output in case of errors, which we occasionally do. | |
27 | /// This should be acceptable because other messages from rustc are in English anyway, | |
28 | /// and may also be desirable to improve searchability of the linker diagnostics. | |
29 | pub fn disable_localization(linker: &mut Command) { | |
30 | // No harm in setting both env vars simultaneously. | |
31 | // Unix-style linkers. | |
32 | linker.env("LC_ALL", "C"); | |
33 | // MSVC's `link.exe`. | |
34 | linker.env("VSLANG", "1033"); | |
35 | } | |
3157f602 | 36 | |
136023e0 XL |
37 | // The third parameter is for env vars, used on windows to set up the |
38 | // path for MSVC to find its DLLs, and gcc to find its bundled | |
39 | // toolchain | |
40 | pub fn get_linker<'a>( | |
41 | sess: &'a Session, | |
42 | linker: &Path, | |
43 | flavor: LinkerFlavor, | |
44 | self_contained: bool, | |
45 | target_cpu: &'a str, | |
46 | ) -> Box<dyn Linker + 'a> { | |
47 | let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); | |
48 | ||
49 | // If our linker looks like a batch script on Windows then to execute this | |
50 | // we'll need to spawn `cmd` explicitly. This is primarily done to handle | |
51 | // emscripten where the linker is `emcc.bat` and needs to be spawned as | |
52 | // `cmd /c emcc.bat ...`. | |
53 | // | |
54 | // This worked historically but is needed manually since #42436 (regression | |
55 | // was tagged as #42791) and some more info can be found on #44443 for | |
56 | // emscripten itself. | |
57 | let mut cmd = match linker.to_str() { | |
58 | Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker), | |
59 | _ => match flavor { | |
60 | LinkerFlavor::Lld(f) => Command::lld(linker, f), | |
61 | LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => { | |
62 | Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path())) | |
63 | } | |
64 | _ => Command::new(linker), | |
65 | }, | |
66 | }; | |
67 | ||
68 | // UWP apps have API restrictions enforced during Store submissions. | |
69 | // To comply with the Windows App Certification Kit, | |
70 | // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). | |
71 | let t = &sess.target; | |
72 | if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link)) | |
73 | && t.vendor == "uwp" | |
74 | { | |
75 | if let Some(ref tool) = msvc_tool { | |
76 | let original_path = tool.path(); | |
77 | if let Some(ref root_lib_path) = original_path.ancestors().nth(4) { | |
5e7ed085 | 78 | let arch = match t.arch.as_ref() { |
136023e0 XL |
79 | "x86_64" => Some("x64"), |
80 | "x86" => Some("x86"), | |
81 | "aarch64" => Some("arm64"), | |
82 | "arm" => Some("arm"), | |
83 | _ => None, | |
84 | }; | |
85 | if let Some(ref a) = arch { | |
86 | // FIXME: Move this to `fn linker_with_args`. | |
87 | let mut arg = OsString::from("/LIBPATH:"); | |
88 | arg.push(format!("{}\\lib\\{}\\store", root_lib_path.display(), a)); | |
89 | cmd.arg(&arg); | |
90 | } else { | |
91 | warn!("arch is not supported"); | |
92 | } | |
93 | } else { | |
94 | warn!("MSVC root path lib location not found"); | |
95 | } | |
96 | } else { | |
97 | warn!("link.exe not found"); | |
3157f602 XL |
98 | } |
99 | } | |
100 | ||
136023e0 XL |
101 | // The compiler's sysroot often has some bundled tools, so add it to the |
102 | // PATH for the child. | |
c295e0f8 | 103 | let mut new_path = sess.get_tools_search_paths(self_contained); |
136023e0 XL |
104 | let mut msvc_changed_path = false; |
105 | if sess.target.is_like_msvc { | |
106 | if let Some(ref tool) = msvc_tool { | |
107 | cmd.args(tool.args()); | |
108 | for &(ref k, ref v) in tool.env() { | |
109 | if k == "PATH" { | |
110 | new_path.extend(env::split_paths(v)); | |
111 | msvc_changed_path = true; | |
112 | } else { | |
113 | cmd.env(k, v); | |
114 | } | |
17df50a5 | 115 | } |
136023e0 XL |
116 | } |
117 | } | |
dfeec247 | 118 | |
136023e0 XL |
119 | if !msvc_changed_path { |
120 | if let Some(path) = env::var_os("PATH") { | |
121 | new_path.extend(env::split_paths(&path)); | |
122 | } | |
123 | } | |
124 | cmd.env("PATH", env::join_paths(new_path).unwrap()); | |
0531ce1d | 125 | |
136023e0 XL |
126 | // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction |
127 | // to the linker args construction. | |
128 | assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); | |
136023e0 XL |
129 | match flavor { |
130 | LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { | |
131 | Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker> | |
132 | } | |
133 | LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>, | |
134 | LinkerFlavor::Gcc => { | |
135 | Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false }) | |
136 | as Box<dyn Linker> | |
137 | } | |
17df50a5 | 138 | |
136023e0 XL |
139 | LinkerFlavor::Lld(LldFlavor::Ld) |
140 | | LinkerFlavor::Lld(LldFlavor::Ld64) | |
141 | | LinkerFlavor::Ld => { | |
142 | Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true }) | |
143 | as Box<dyn Linker> | |
3157f602 | 144 | } |
136023e0 XL |
145 | |
146 | LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>, | |
147 | ||
148 | LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>, | |
149 | ||
150 | LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>, | |
5099ac24 FG |
151 | |
152 | LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>, | |
3157f602 XL |
153 | } |
154 | } | |
62682a34 | 155 | |
9fa01778 | 156 | /// Linker abstraction used by `back::link` to build up the command to invoke a |
62682a34 SL |
157 | /// linker. |
158 | /// | |
159 | /// This trait is the total list of requirements needed by `back::link` and | |
160 | /// represents the meaning of each option being passed down. This trait is then | |
161 | /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an | |
0731742a | 162 | /// MSVC linker (e.g., `link.exe`) is being used. |
62682a34 | 163 | pub trait Linker { |
ba9703b0 | 164 | fn cmd(&mut self) -> &mut Command; |
f9f354fc | 165 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); |
17df50a5 | 166 | fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool); |
e1599b0c | 167 | fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); |
17df50a5 XL |
168 | fn link_framework(&mut self, framework: Symbol, as_needed: bool); |
169 | fn link_staticlib(&mut self, lib: Symbol, verbatim: bool); | |
62682a34 | 170 | fn link_rlib(&mut self, lib: &Path); |
c1a9b12d | 171 | fn link_whole_rlib(&mut self, lib: &Path); |
17df50a5 | 172 | fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]); |
62682a34 SL |
173 | fn include_path(&mut self, path: &Path); |
174 | fn framework_path(&mut self, path: &Path); | |
175 | fn output_filename(&mut self, path: &Path); | |
176 | fn add_object(&mut self, path: &Path); | |
a7813a04 | 177 | fn gc_sections(&mut self, keep_metadata: bool); |
17df50a5 | 178 | fn no_gc_sections(&mut self); |
3b2f2976 | 179 | fn full_relro(&mut self); |
0531ce1d XL |
180 | fn partial_relro(&mut self); |
181 | fn no_relro(&mut self); | |
62682a34 | 182 | fn optimize(&mut self); |
0531ce1d | 183 | fn pgo_gen(&mut self); |
74b04a01 | 184 | fn control_flow_guard(&mut self); |
923072b8 | 185 | fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); |
f9f354fc | 186 | fn no_crt_objects(&mut self); |
62682a34 | 187 | fn no_default_libraries(&mut self); |
136023e0 | 188 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); |
c30ab7b3 | 189 | fn subsystem(&mut self, subsystem: &str); |
0531ce1d XL |
190 | fn group_start(&mut self); |
191 | fn group_end(&mut self); | |
9fa01778 | 192 | fn linker_plugin_lto(&mut self); |
f035d41b | 193 | fn add_eh_frame_header(&mut self) {} |
cdc7bbd5 XL |
194 | fn add_no_exec(&mut self) {} |
195 | fn add_as_needed(&mut self) {} | |
17df50a5 | 196 | fn reset_per_library_state(&mut self) {} |
ba9703b0 XL |
197 | } |
198 | ||
199 | impl dyn Linker + '_ { | |
200 | pub fn arg(&mut self, arg: impl AsRef<OsStr>) { | |
201 | self.cmd().arg(arg); | |
202 | } | |
203 | ||
204 | pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) { | |
205 | self.cmd().args(args); | |
206 | } | |
207 | ||
208 | pub fn take_cmd(&mut self) -> Command { | |
209 | mem::replace(self.cmd(), Command::new("")) | |
210 | } | |
62682a34 SL |
211 | } |
212 | ||
cc61c64b XL |
213 | pub struct GccLinker<'a> { |
214 | cmd: Command, | |
3157f602 | 215 | sess: &'a Session, |
136023e0 | 216 | target_cpu: &'a str, |
cc61c64b XL |
217 | hinted_static: bool, // Keeps track of the current hinting mode. |
218 | // Link as ld | |
219 | is_ld: bool, | |
62682a34 SL |
220 | } |
221 | ||
cc61c64b | 222 | impl<'a> GccLinker<'a> { |
3c0e092e | 223 | /// Passes an argument directly to the linker. |
cc61c64b | 224 | /// |
3c0e092e XL |
225 | /// When the linker is not ld-like such as when using a compiler as a linker, the argument is |
226 | /// prepended by `-Wl,`. | |
227 | fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { | |
228 | self.linker_args(&[arg]); | |
229 | self | |
230 | } | |
231 | ||
232 | /// Passes a series of arguments directly to the linker. | |
233 | /// | |
234 | /// When the linker is ld-like, the arguments are simply appended to the command. When the | |
235 | /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by | |
236 | /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a | |
237 | /// single argument is appended to the command to ensure that the order of the arguments is | |
238 | /// preserved by the compiler. | |
239 | fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self { | |
240 | if self.is_ld { | |
241 | args.into_iter().for_each(|a| { | |
242 | self.cmd.arg(a); | |
243 | }); | |
cc61c64b | 244 | } else { |
3c0e092e XL |
245 | if !args.is_empty() { |
246 | let mut s = OsString::from("-Wl"); | |
247 | for a in args { | |
248 | s.push(","); | |
249 | s.push(a); | |
250 | } | |
251 | self.cmd.arg(s); | |
252 | } | |
cc61c64b XL |
253 | } |
254 | self | |
255 | } | |
256 | ||
62682a34 | 257 | fn takes_hints(&self) -> bool { |
532ac7d7 XL |
258 | // Really this function only returns true if the underlying linker |
259 | // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We | |
260 | // don't really have a foolproof way to detect that, so rule out some | |
261 | // platforms where currently this is guaranteed to *not* be the case: | |
262 | // | |
263 | // * On OSX they have their own linker, not binutils' | |
264 | // * For WebAssembly the only functional linker is LLD, which doesn't | |
265 | // support hint flags | |
cdc7bbd5 | 266 | !self.sess.target.is_like_osx && !self.sess.target.is_like_wasm |
62682a34 | 267 | } |
cc61c64b XL |
268 | |
269 | // Some platforms take hints about whether a library is static or dynamic. | |
270 | // For those that support this, we ensure we pass the option if the library | |
271 | // was flagged "static" (most defaults are dynamic) to ensure that if | |
272 | // libfoo.a and libfoo.so both exist that the right one is chosen. | |
273 | fn hint_static(&mut self) { | |
dfeec247 XL |
274 | if !self.takes_hints() { |
275 | return; | |
276 | } | |
cc61c64b XL |
277 | if !self.hinted_static { |
278 | self.linker_arg("-Bstatic"); | |
279 | self.hinted_static = true; | |
280 | } | |
281 | } | |
282 | ||
283 | fn hint_dynamic(&mut self) { | |
dfeec247 XL |
284 | if !self.takes_hints() { |
285 | return; | |
286 | } | |
cc61c64b XL |
287 | if self.hinted_static { |
288 | self.linker_arg("-Bdynamic"); | |
289 | self.hinted_static = false; | |
290 | } | |
291 | } | |
8faf50e0 | 292 | |
9fa01778 | 293 | fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) { |
8faf50e0 XL |
294 | if let Some(plugin_path) = plugin_path { |
295 | let mut arg = OsString::from("-plugin="); | |
296 | arg.push(plugin_path); | |
297 | self.linker_arg(&arg); | |
298 | } | |
299 | ||
300 | let opt_level = match self.sess.opts.optimize { | |
301 | config::OptLevel::No => "O0", | |
302 | config::OptLevel::Less => "O1", | |
29967ef6 | 303 | config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2", |
8faf50e0 | 304 | config::OptLevel::Aggressive => "O3", |
8faf50e0 XL |
305 | }; |
306 | ||
c295e0f8 XL |
307 | if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use { |
308 | self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); | |
309 | }; | |
3c0e092e XL |
310 | self.linker_args(&[ |
311 | &format!("-plugin-opt={}", opt_level), | |
312 | &format!("-plugin-opt=mcpu={}", self.target_cpu), | |
313 | ]); | |
8faf50e0 | 314 | } |
f9f354fc XL |
315 | |
316 | fn build_dylib(&mut self, out_filename: &Path) { | |
317 | // On mac we need to tell the linker to let this library be rpathed | |
29967ef6 | 318 | if self.sess.target.is_like_osx { |
3c0e092e XL |
319 | if !self.is_ld { |
320 | self.cmd.arg("-dynamiclib"); | |
321 | } | |
322 | ||
f9f354fc XL |
323 | self.linker_arg("-dylib"); |
324 | ||
325 | // Note that the `osx_rpath_install_name` option here is a hack | |
326 | // purely to support rustbuild right now, we should get a more | |
327 | // principled solution at some point to force the compiler to pass | |
328 | // the right `-Wl,-install_name` with an `@rpath` in it. | |
329 | if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { | |
3c0e092e XL |
330 | let mut rpath = OsString::from("@rpath/"); |
331 | rpath.push(out_filename.file_name().unwrap()); | |
332 | self.linker_args(&[OsString::from("-install_name"), rpath]); | |
f9f354fc XL |
333 | } |
334 | } else { | |
335 | self.cmd.arg("-shared"); | |
29967ef6 | 336 | if self.sess.target.is_like_windows { |
f9f354fc XL |
337 | // The output filename already contains `dll_suffix` so |
338 | // the resulting import library will have a name in the | |
339 | // form of libfoo.dll.a | |
340 | let implib_name = | |
341 | out_filename.file_name().and_then(|file| file.to_str()).map(|file| { | |
342 | format!( | |
343 | "{}{}{}", | |
29967ef6 | 344 | self.sess.target.staticlib_prefix, |
f9f354fc | 345 | file, |
29967ef6 | 346 | self.sess.target.staticlib_suffix |
f9f354fc XL |
347 | ) |
348 | }); | |
349 | if let Some(implib_name) = implib_name { | |
350 | let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); | |
351 | if let Some(implib) = implib { | |
3dfed10e | 352 | self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); |
f9f354fc XL |
353 | } |
354 | } | |
355 | } | |
356 | } | |
357 | } | |
62682a34 SL |
358 | } |
359 | ||
cc61c64b | 360 | impl<'a> Linker for GccLinker<'a> { |
ba9703b0 XL |
361 | fn cmd(&mut self) -> &mut Command { |
362 | &mut self.cmd | |
363 | } | |
f9f354fc XL |
364 | |
365 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { | |
366 | match output_kind { | |
367 | LinkOutputKind::DynamicNoPicExe => { | |
29967ef6 | 368 | if !self.is_ld && self.sess.target.linker_is_gnu { |
f9f354fc XL |
369 | self.cmd.arg("-no-pie"); |
370 | } | |
371 | } | |
372 | LinkOutputKind::DynamicPicExe => { | |
17df50a5 XL |
373 | // noop on windows w/ gcc & ld, error w/ lld |
374 | if !self.sess.target.is_like_windows { | |
375 | // `-pie` works for both gcc wrapper and ld. | |
376 | self.cmd.arg("-pie"); | |
377 | } | |
f9f354fc XL |
378 | } |
379 | LinkOutputKind::StaticNoPicExe => { | |
380 | // `-static` works for both gcc wrapper and ld. | |
381 | self.cmd.arg("-static"); | |
29967ef6 | 382 | if !self.is_ld && self.sess.target.linker_is_gnu { |
f9f354fc XL |
383 | self.cmd.arg("-no-pie"); |
384 | } | |
385 | } | |
386 | LinkOutputKind::StaticPicExe => { | |
387 | if !self.is_ld { | |
388 | // Note that combination `-static -pie` doesn't work as expected | |
389 | // for the gcc wrapper, `-static` in that case suppresses `-pie`. | |
390 | self.cmd.arg("-static-pie"); | |
391 | } else { | |
392 | // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing | |
393 | // a static pie, but currently passed because gcc and clang pass them. | |
394 | // The former suppresses the `INTERP` ELF header specifying dynamic linker, | |
395 | // which is otherwise implicitly injected by ld (but not lld). | |
396 | // The latter doesn't change anything, only ensures that everything is pic. | |
397 | self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); | |
398 | } | |
399 | } | |
400 | LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), | |
401 | LinkOutputKind::StaticDylib => { | |
402 | self.cmd.arg("-static"); | |
403 | self.build_dylib(out_filename); | |
404 | } | |
5869c6ff | 405 | LinkOutputKind::WasiReactorExe => { |
3c0e092e | 406 | self.linker_args(&["--entry", "_initialize"]); |
5869c6ff | 407 | } |
f9f354fc | 408 | } |
f035d41b XL |
409 | // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, |
410 | // it switches linking for libc and similar system libraries to static without using | |
411 | // any `#[link]` attributes in the `libc` crate, see #72782 for details. | |
412 | // FIXME: Switch to using `#[link]` attributes in the `libc` crate | |
413 | // similarly to other targets. | |
29967ef6 | 414 | if self.sess.target.os == "vxworks" |
f035d41b XL |
415 | && matches!( |
416 | output_kind, | |
417 | LinkOutputKind::StaticNoPicExe | |
418 | | LinkOutputKind::StaticPicExe | |
419 | | LinkOutputKind::StaticDylib | |
420 | ) | |
421 | { | |
422 | self.cmd.arg("--static-crt"); | |
423 | } | |
f9f354fc XL |
424 | } |
425 | ||
17df50a5 XL |
426 | fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) { |
427 | if self.sess.target.os == "illumos" && lib.as_str() == "c" { | |
428 | // libc will be added via late_link_args on illumos so that it will | |
429 | // appear last in the library search order. | |
430 | // FIXME: This should be replaced by a more complete and generic | |
431 | // mechanism for controlling the order of library arguments passed | |
432 | // to the linker. | |
433 | return; | |
434 | } | |
435 | if !as_needed { | |
436 | if self.sess.target.is_like_osx { | |
437 | // FIXME(81490): ld64 doesn't support these flags but macOS 11 | |
438 | // has -needed-l{} / -needed_library {} | |
439 | // but we have no way to detect that here. | |
440 | self.sess.warn("`as-needed` modifier not implemented yet for ld64"); | |
441 | } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { | |
442 | self.linker_arg("--no-as-needed"); | |
443 | } else { | |
444 | self.sess.warn("`as-needed` modifier not supported for current linker"); | |
445 | } | |
446 | } | |
e1599b0c | 447 | self.hint_dynamic(); |
17df50a5 XL |
448 | self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); |
449 | if !as_needed { | |
450 | if self.sess.target.is_like_osx { | |
451 | // See above FIXME comment | |
452 | } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { | |
453 | self.linker_arg("--as-needed"); | |
454 | } | |
455 | } | |
e1599b0c | 456 | } |
17df50a5 | 457 | fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { |
e1599b0c | 458 | self.hint_static(); |
17df50a5 | 459 | self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); |
8faf50e0 | 460 | } |
dfeec247 XL |
461 | fn link_rlib(&mut self, lib: &Path) { |
462 | self.hint_static(); | |
463 | self.cmd.arg(lib); | |
464 | } | |
465 | fn include_path(&mut self, path: &Path) { | |
466 | self.cmd.arg("-L").arg(path); | |
467 | } | |
468 | fn framework_path(&mut self, path: &Path) { | |
469 | self.cmd.arg("-F").arg(path); | |
470 | } | |
471 | fn output_filename(&mut self, path: &Path) { | |
472 | self.cmd.arg("-o").arg(path); | |
473 | } | |
474 | fn add_object(&mut self, path: &Path) { | |
475 | self.cmd.arg(path); | |
476 | } | |
dfeec247 | 477 | fn full_relro(&mut self) { |
3c0e092e | 478 | self.linker_args(&["-zrelro", "-znow"]); |
dfeec247 XL |
479 | } |
480 | fn partial_relro(&mut self) { | |
481 | self.linker_arg("-zrelro"); | |
482 | } | |
483 | fn no_relro(&mut self) { | |
484 | self.linker_arg("-znorelro"); | |
485 | } | |
62682a34 | 486 | |
e1599b0c | 487 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
cc61c64b | 488 | self.hint_dynamic(); |
a1dfa0c6 | 489 | self.cmd.arg(format!("-l{}", lib)); |
c1a9b12d SL |
490 | } |
491 | ||
17df50a5 | 492 | fn link_framework(&mut self, framework: Symbol, as_needed: bool) { |
cc61c64b | 493 | self.hint_dynamic(); |
17df50a5 XL |
494 | if !as_needed { |
495 | // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework | |
496 | // flag but we have no way to detect that here. | |
497 | // self.cmd.arg("-needed_framework").sym_arg(framework); | |
498 | self.sess.warn("`as-needed` modifier not implemented yet for ld64"); | |
499 | } | |
e1599b0c | 500 | self.cmd.arg("-framework").sym_arg(framework); |
62682a34 SL |
501 | } |
502 | ||
cc61c64b XL |
503 | // Here we explicitly ask that the entire archive is included into the |
504 | // result artifact. For more details see #15460, but the gist is that | |
505 | // the linker will strip away any unused objects in the archive if we | |
506 | // don't otherwise explicitly reference them. This can occur for | |
507 | // libraries which are just providing bindings, libraries with generic | |
508 | // functions, etc. | |
17df50a5 | 509 | fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) { |
cc61c64b | 510 | self.hint_static(); |
29967ef6 XL |
511 | let target = &self.sess.target; |
512 | if !target.is_like_osx { | |
17df50a5 XL |
513 | self.linker_arg("--whole-archive").cmd.arg(format!( |
514 | "-l{}{}", | |
515 | if verbatim { ":" } else { "" }, | |
516 | lib | |
517 | )); | |
cc61c64b | 518 | self.linker_arg("--no-whole-archive"); |
62682a34 | 519 | } else { |
cc61c64b | 520 | // -force_load is the macOS equivalent of --whole-archive, but it |
62682a34 | 521 | // involves passing the full path to the library to link. |
8faf50e0 | 522 | self.linker_arg("-force_load"); |
17df50a5 | 523 | let lib = archive::find_library(lib, verbatim, search_path, &self.sess); |
8faf50e0 | 524 | self.linker_arg(&lib); |
c1a9b12d SL |
525 | } |
526 | } | |
527 | ||
528 | fn link_whole_rlib(&mut self, lib: &Path) { | |
cc61c64b | 529 | self.hint_static(); |
29967ef6 | 530 | if self.sess.target.is_like_osx { |
8faf50e0 XL |
531 | self.linker_arg("-force_load"); |
532 | self.linker_arg(&lib); | |
c1a9b12d | 533 | } else { |
cc61c64b XL |
534 | self.linker_arg("--whole-archive").cmd.arg(lib); |
535 | self.linker_arg("--no-whole-archive"); | |
62682a34 SL |
536 | } |
537 | } | |
538 | ||
a7813a04 | 539 | fn gc_sections(&mut self, keep_metadata: bool) { |
62682a34 SL |
540 | // The dead_strip option to the linker specifies that functions and data |
541 | // unreachable by the entry point will be removed. This is quite useful | |
542 | // with Rust's compilation model of compiling libraries at a time into | |
543 | // one object file. For example, this brings hello world from 1.7MB to | |
544 | // 458K. | |
545 | // | |
546 | // Note that this is done for both executables and dynamic libraries. We | |
547 | // won't get much benefit from dylibs because LLVM will have already | |
548 | // stripped away as much as it could. This has not been seen to impact | |
549 | // link times negatively. | |
550 | // | |
551 | // -dead_strip can't be part of the pre_link_args because it's also used | |
552 | // for partial linking when using multiple codegen units (-r). So we | |
553 | // insert it here. | |
29967ef6 | 554 | if self.sess.target.is_like_osx { |
cc61c64b | 555 | self.linker_arg("-dead_strip"); |
62682a34 SL |
556 | |
557 | // If we're building a dylib, we don't use --gc-sections because LLVM | |
558 | // has already done the best it can do, and we also don't want to | |
559 | // eliminate the metadata. If we're building an executable, however, | |
560 | // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% | |
561 | // reduction. | |
17df50a5 XL |
562 | } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm) |
563 | && !keep_metadata | |
564 | { | |
cc61c64b | 565 | self.linker_arg("--gc-sections"); |
62682a34 SL |
566 | } |
567 | } | |
568 | ||
17df50a5 XL |
569 | fn no_gc_sections(&mut self) { |
570 | if self.sess.target.is_like_osx { | |
571 | self.linker_arg("-no_dead_strip"); | |
572 | } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm { | |
573 | self.linker_arg("--no-gc-sections"); | |
574 | } | |
575 | } | |
576 | ||
62682a34 | 577 | fn optimize(&mut self) { |
17df50a5 | 578 | if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm { |
dfeec247 XL |
579 | return; |
580 | } | |
62682a34 SL |
581 | |
582 | // GNU-style linkers support optimization with -O. GNU ld doesn't | |
583 | // need a numeric argument, but other linkers do. | |
dfeec247 XL |
584 | if self.sess.opts.optimize == config::OptLevel::Default |
585 | || self.sess.opts.optimize == config::OptLevel::Aggressive | |
586 | { | |
cc61c64b | 587 | self.linker_arg("-O1"); |
62682a34 SL |
588 | } |
589 | } | |
590 | ||
0531ce1d | 591 | fn pgo_gen(&mut self) { |
29967ef6 | 592 | if !self.sess.target.linker_is_gnu { |
dfeec247 XL |
593 | return; |
594 | } | |
0531ce1d XL |
595 | |
596 | // If we're doing PGO generation stuff and on a GNU-like linker, use the | |
597 | // "-u" flag to properly pull in the profiler runtime bits. | |
598 | // | |
599 | // This is because LLVM otherwise won't add the needed initialization | |
600 | // for us on Linux (though the extra flag should be harmless if it | |
601 | // does). | |
602 | // | |
603 | // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. | |
604 | // | |
605 | // Though it may be worth to try to revert those changes upstream, since | |
606 | // the overhead of the initialization should be minor. | |
607 | self.cmd.arg("-u"); | |
608 | self.cmd.arg("__llvm_profile_runtime"); | |
609 | } | |
610 | ||
f035d41b | 611 | fn control_flow_guard(&mut self) {} |
74b04a01 | 612 | |
04454e1e | 613 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
17df50a5 XL |
614 | // MacOS linker doesn't support stripping symbols directly anymore. |
615 | if self.sess.target.is_like_osx { | |
616 | return; | |
617 | } | |
618 | ||
f9f354fc XL |
619 | match strip { |
620 | Strip::None => {} | |
621 | Strip::Debuginfo => { | |
17df50a5 | 622 | self.linker_arg("--strip-debug"); |
a1dfa0c6 | 623 | } |
f9f354fc | 624 | Strip::Symbols => { |
17df50a5 | 625 | self.linker_arg("--strip-all"); |
f9f354fc XL |
626 | } |
627 | } | |
c1a9b12d SL |
628 | } |
629 | ||
f9f354fc | 630 | fn no_crt_objects(&mut self) { |
cc61c64b | 631 | if !self.is_ld { |
f9f354fc | 632 | self.cmd.arg("-nostartfiles"); |
cc61c64b | 633 | } |
62682a34 SL |
634 | } |
635 | ||
f9f354fc XL |
636 | fn no_default_libraries(&mut self) { |
637 | if !self.is_ld { | |
638 | self.cmd.arg("-nodefaultlibs"); | |
62682a34 SL |
639 | } |
640 | } | |
641 | ||
136023e0 | 642 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { |
48663c56 | 643 | // Symbol visibility in object files typically takes care of this. |
29967ef6 | 644 | if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none() |
dfeec247 | 645 | { |
48663c56 XL |
646 | return; |
647 | } | |
648 | ||
dc9dc135 XL |
649 | // We manually create a list of exported symbols to ensure we don't expose any more. |
650 | // The object files have far more public symbols than we actually want to export, | |
651 | // so we hide them all here. | |
a7813a04 | 652 | |
29967ef6 | 653 | if !self.sess.target.limit_rdylib_exports { |
532ac7d7 XL |
654 | return; |
655 | } | |
656 | ||
dc9dc135 | 657 | if crate_type == CrateType::ProcMacro { |
dfeec247 | 658 | return; |
dc9dc135 XL |
659 | } |
660 | ||
29967ef6 | 661 | let is_windows = self.sess.target.is_like_windows; |
3dfed10e | 662 | let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); |
9e0c209e | 663 | |
476ff2be SL |
664 | debug!("EXPORTED SYMBOLS:"); |
665 | ||
29967ef6 | 666 | if self.sess.target.is_like_osx { |
476ff2be | 667 | // Write a plain, newline-separated list of symbols |
532ac7d7 | 668 | let res: io::Result<()> = try { |
9e0c209e | 669 | let mut f = BufWriter::new(File::create(&path)?); |
136023e0 | 670 | for sym in symbols { |
476ff2be SL |
671 | debug!(" _{}", sym); |
672 | writeln!(f, "_{}", sym)?; | |
9e0c209e | 673 | } |
532ac7d7 | 674 | }; |
9e0c209e | 675 | if let Err(e) = res { |
476ff2be | 676 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
a7813a04 | 677 | } |
3dfed10e XL |
678 | } else if is_windows { |
679 | let res: io::Result<()> = try { | |
680 | let mut f = BufWriter::new(File::create(&path)?); | |
681 | ||
682 | // .def file similar to MSVC one but without LIBRARY section | |
683 | // because LD doesn't like when it's empty | |
684 | writeln!(f, "EXPORTS")?; | |
136023e0 | 685 | for symbol in symbols { |
3dfed10e XL |
686 | debug!(" _{}", symbol); |
687 | writeln!(f, " {}", symbol)?; | |
688 | } | |
689 | }; | |
690 | if let Err(e) = res { | |
691 | self.sess.fatal(&format!("failed to write list.def file: {}", e)); | |
692 | } | |
a7813a04 | 693 | } else { |
476ff2be | 694 | // Write an LD version script |
532ac7d7 | 695 | let res: io::Result<()> = try { |
9e0c209e | 696 | let mut f = BufWriter::new(File::create(&path)?); |
e1599b0c | 697 | writeln!(f, "{{")?; |
136023e0 | 698 | if !symbols.is_empty() { |
e1599b0c | 699 | writeln!(f, " global:")?; |
136023e0 | 700 | for sym in symbols { |
e1599b0c XL |
701 | debug!(" {};", sym); |
702 | writeln!(f, " {};", sym)?; | |
703 | } | |
9e0c209e | 704 | } |
476ff2be | 705 | writeln!(f, "\n local:\n *;\n}};")?; |
532ac7d7 | 706 | }; |
9e0c209e | 707 | if let Err(e) = res { |
476ff2be | 708 | self.sess.fatal(&format!("failed to write version script: {}", e)); |
9e0c209e | 709 | } |
a7813a04 | 710 | } |
9e0c209e | 711 | |
29967ef6 | 712 | if self.sess.target.is_like_osx { |
3c0e092e | 713 | self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); |
29967ef6 | 714 | } else if self.sess.target.is_like_solaris { |
3c0e092e | 715 | self.linker_args(&[OsString::from("-M"), path.into()]); |
476ff2be | 716 | } else { |
3c0e092e XL |
717 | if is_windows { |
718 | self.linker_arg(path); | |
719 | } else { | |
720 | let mut arg = OsString::from("--version-script="); | |
721 | arg.push(path); | |
722 | self.linker_arg(arg); | |
3dfed10e | 723 | } |
476ff2be | 724 | } |
e9174d1e | 725 | } |
c30ab7b3 SL |
726 | |
727 | fn subsystem(&mut self, subsystem: &str) { | |
8faf50e0 XL |
728 | self.linker_arg("--subsystem"); |
729 | self.linker_arg(&subsystem); | |
cc61c64b XL |
730 | } |
731 | ||
17df50a5 | 732 | fn reset_per_library_state(&mut self) { |
cc61c64b | 733 | self.hint_dynamic(); // Reset to default before returning the composed command line. |
c30ab7b3 | 734 | } |
0531ce1d XL |
735 | |
736 | fn group_start(&mut self) { | |
532ac7d7 | 737 | if self.takes_hints() { |
0531ce1d XL |
738 | self.linker_arg("--start-group"); |
739 | } | |
740 | } | |
741 | ||
742 | fn group_end(&mut self) { | |
532ac7d7 | 743 | if self.takes_hints() { |
0531ce1d XL |
744 | self.linker_arg("--end-group"); |
745 | } | |
746 | } | |
94b46f34 | 747 | |
9fa01778 XL |
748 | fn linker_plugin_lto(&mut self) { |
749 | match self.sess.opts.cg.linker_plugin_lto { | |
750 | LinkerPluginLto::Disabled => { | |
94b46f34 XL |
751 | // Nothing to do |
752 | } | |
9fa01778 XL |
753 | LinkerPluginLto::LinkerPluginAuto => { |
754 | self.push_linker_plugin_lto_args(None); | |
8faf50e0 | 755 | } |
9fa01778 XL |
756 | LinkerPluginLto::LinkerPlugin(ref path) => { |
757 | self.push_linker_plugin_lto_args(Some(path.as_os_str())); | |
94b46f34 XL |
758 | } |
759 | } | |
760 | } | |
f035d41b XL |
761 | |
762 | // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information. | |
763 | // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, | |
764 | // so we just always add it. | |
765 | fn add_eh_frame_header(&mut self) { | |
f9652781 | 766 | self.linker_arg("--eh-frame-hdr"); |
f035d41b | 767 | } |
cdc7bbd5 XL |
768 | |
769 | fn add_no_exec(&mut self) { | |
770 | if self.sess.target.is_like_windows { | |
771 | self.linker_arg("--nxcompat"); | |
772 | } else if self.sess.target.linker_is_gnu { | |
773 | self.linker_arg("-znoexecstack"); | |
774 | } | |
775 | } | |
776 | ||
777 | fn add_as_needed(&mut self) { | |
17df50a5 | 778 | if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { |
cdc7bbd5 | 779 | self.linker_arg("--as-needed"); |
17df50a5 XL |
780 | } else if self.sess.target.is_like_solaris { |
781 | // -z ignore is the Solaris equivalent to the GNU ld --as-needed option | |
3c0e092e | 782 | self.linker_args(&["-z", "ignore"]); |
cdc7bbd5 XL |
783 | } |
784 | } | |
62682a34 SL |
785 | } |
786 | ||
787 | pub struct MsvcLinker<'a> { | |
cc61c64b | 788 | cmd: Command, |
3157f602 | 789 | sess: &'a Session, |
62682a34 SL |
790 | } |
791 | ||
792 | impl<'a> Linker for MsvcLinker<'a> { | |
ba9703b0 XL |
793 | fn cmd(&mut self) -> &mut Command { |
794 | &mut self.cmd | |
795 | } | |
f9f354fc XL |
796 | |
797 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { | |
798 | match output_kind { | |
799 | LinkOutputKind::DynamicNoPicExe | |
800 | | LinkOutputKind::DynamicPicExe | |
801 | | LinkOutputKind::StaticNoPicExe | |
802 | | LinkOutputKind::StaticPicExe => {} | |
803 | LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { | |
804 | self.cmd.arg("/DLL"); | |
805 | let mut arg: OsString = "/IMPLIB:".into(); | |
806 | arg.push(out_filename.with_extension("dll.lib")); | |
807 | self.cmd.arg(arg); | |
808 | } | |
5869c6ff XL |
809 | LinkOutputKind::WasiReactorExe => { |
810 | panic!("can't link as reactor on non-wasi target"); | |
811 | } | |
f9f354fc XL |
812 | } |
813 | } | |
814 | ||
dfeec247 XL |
815 | fn link_rlib(&mut self, lib: &Path) { |
816 | self.cmd.arg(lib); | |
817 | } | |
818 | fn add_object(&mut self, path: &Path) { | |
819 | self.cmd.arg(path); | |
820 | } | |
7453a54e | 821 | |
a7813a04 | 822 | fn gc_sections(&mut self, _keep_metadata: bool) { |
476ff2be SL |
823 | // MSVC's ICF (Identical COMDAT Folding) link optimization is |
824 | // slow for Rust and thus we disable it by default when not in | |
825 | // optimization build. | |
826 | if self.sess.opts.optimize != config::OptLevel::No { | |
827 | self.cmd.arg("/OPT:REF,ICF"); | |
828 | } else { | |
829 | // It is necessary to specify NOICF here, because /OPT:REF | |
830 | // implies ICF by default. | |
831 | self.cmd.arg("/OPT:REF,NOICF"); | |
832 | } | |
a7813a04 | 833 | } |
62682a34 | 834 | |
17df50a5 XL |
835 | fn no_gc_sections(&mut self) { |
836 | self.cmd.arg("/OPT:NOREF,NOICF"); | |
837 | } | |
838 | ||
839 | fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { | |
840 | self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); | |
62682a34 | 841 | } |
c1a9b12d | 842 | |
e1599b0c | 843 | fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) { |
c1a9b12d SL |
844 | // When producing a dll, the MSVC linker may not actually emit a |
845 | // `foo.lib` file if the dll doesn't actually export any symbols, so we | |
846 | // check to see if the file is there and just omit linking to it if it's | |
847 | // not present. | |
7453a54e | 848 | let name = format!("{}.dll.lib", lib); |
17df50a5 | 849 | if path.join(&name).exists() { |
c1a9b12d SL |
850 | self.cmd.arg(name); |
851 | } | |
852 | } | |
853 | ||
17df50a5 XL |
854 | fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { |
855 | self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); | |
62682a34 SL |
856 | } |
857 | ||
3b2f2976 XL |
858 | fn full_relro(&mut self) { |
859 | // noop | |
860 | } | |
861 | ||
0531ce1d XL |
862 | fn partial_relro(&mut self) { |
863 | // noop | |
864 | } | |
865 | ||
866 | fn no_relro(&mut self) { | |
867 | // noop | |
868 | } | |
869 | ||
f9f354fc XL |
870 | fn no_crt_objects(&mut self) { |
871 | // noop | |
872 | } | |
873 | ||
62682a34 | 874 | fn no_default_libraries(&mut self) { |
ba9703b0 | 875 | self.cmd.arg("/NODEFAULTLIB"); |
62682a34 SL |
876 | } |
877 | ||
878 | fn include_path(&mut self, path: &Path) { | |
879 | let mut arg = OsString::from("/LIBPATH:"); | |
880 | arg.push(path); | |
881 | self.cmd.arg(&arg); | |
882 | } | |
883 | ||
884 | fn output_filename(&mut self, path: &Path) { | |
885 | let mut arg = OsString::from("/OUT:"); | |
886 | arg.push(path); | |
887 | self.cmd.arg(&arg); | |
888 | } | |
889 | ||
890 | fn framework_path(&mut self, _path: &Path) { | |
54a0048b | 891 | bug!("frameworks are not supported on windows") |
62682a34 | 892 | } |
17df50a5 | 893 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { |
54a0048b | 894 | bug!("frameworks are not supported on windows") |
62682a34 SL |
895 | } |
896 | ||
17df50a5 XL |
897 | fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { |
898 | self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); | |
62682a34 | 899 | } |
c1a9b12d | 900 | fn link_whole_rlib(&mut self, path: &Path) { |
f035d41b XL |
901 | let mut arg = OsString::from("/WHOLEARCHIVE:"); |
902 | arg.push(path); | |
903 | self.cmd.arg(arg); | |
c1a9b12d | 904 | } |
62682a34 SL |
905 | fn optimize(&mut self) { |
906 | // Needs more investigation of `/OPT` arguments | |
907 | } | |
c1a9b12d | 908 | |
0531ce1d XL |
909 | fn pgo_gen(&mut self) { |
910 | // Nothing needed here. | |
911 | } | |
912 | ||
74b04a01 XL |
913 | fn control_flow_guard(&mut self) { |
914 | self.cmd.arg("/guard:cf"); | |
915 | } | |
916 | ||
923072b8 | 917 | fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { |
f9f354fc XL |
918 | match strip { |
919 | Strip::None => { | |
920 | // This will cause the Microsoft linker to generate a PDB file | |
921 | // from the CodeView line tables in the object files. | |
922 | self.cmd.arg("/DEBUG"); | |
923 | ||
924 | // This will cause the Microsoft linker to embed .natvis info into the PDB file | |
925 | let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); | |
926 | if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { | |
927 | for entry in natvis_dir { | |
928 | match entry { | |
929 | Ok(entry) => { | |
930 | let path = entry.path(); | |
931 | if path.extension() == Some("natvis".as_ref()) { | |
932 | let mut arg = OsString::from("/NATVIS:"); | |
933 | arg.push(path); | |
934 | self.cmd.arg(arg); | |
935 | } | |
936 | } | |
937 | Err(err) => { | |
938 | self.sess | |
939 | .warn(&format!("error enumerating natvis directory: {}", err)); | |
940 | } | |
3b2f2976 | 941 | } |
dfeec247 | 942 | } |
3b2f2976 | 943 | } |
04454e1e FG |
944 | |
945 | // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file | |
923072b8 | 946 | for path in natvis_debugger_visualizers { |
04454e1e FG |
947 | let mut arg = OsString::from("/NATVIS:"); |
948 | arg.push(path); | |
949 | self.cmd.arg(arg); | |
950 | } | |
3b2f2976 | 951 | } |
f9f354fc XL |
952 | Strip::Debuginfo | Strip::Symbols => { |
953 | self.cmd.arg("/DEBUG:NONE"); | |
954 | } | |
3b2f2976 | 955 | } |
c1a9b12d SL |
956 | } |
957 | ||
e9174d1e SL |
958 | // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to |
959 | // export symbols from a dynamic library. When building a dynamic library, | |
960 | // however, we're going to want some symbols exported, so this function | |
961 | // generates a DEF file which lists all the symbols. | |
962 | // | |
963 | // The linker will read this `*.def` file and export all the symbols from | |
964 | // the dynamic library. Note that this is not as simple as just exporting | |
94b46f34 | 965 | // all the symbols in the current crate (as specified by `codegen.reachable`) |
e9174d1e SL |
966 | // but rather we also need to possibly export the symbols of upstream |
967 | // crates. Upstream rlibs may be linked statically to this dynamic library, | |
968 | // in which case they may continue to transitively be used and hence need | |
969 | // their symbols exported. | |
136023e0 | 970 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) { |
48663c56 XL |
971 | // Symbol visibility takes care of this typically |
972 | if crate_type == CrateType::Executable { | |
973 | return; | |
974 | } | |
975 | ||
e9174d1e | 976 | let path = tmpdir.join("lib.def"); |
532ac7d7 | 977 | let res: io::Result<()> = try { |
54a0048b | 978 | let mut f = BufWriter::new(File::create(&path)?); |
e9174d1e SL |
979 | |
980 | // Start off with the standard module name header and then go | |
981 | // straight to exports. | |
54a0048b SL |
982 | writeln!(f, "LIBRARY")?; |
983 | writeln!(f, "EXPORTS")?; | |
136023e0 | 984 | for symbol in symbols { |
8bb4bdeb | 985 | debug!(" _{}", symbol); |
3157f602 | 986 | writeln!(f, " {}", symbol)?; |
e9174d1e | 987 | } |
532ac7d7 | 988 | }; |
e9174d1e | 989 | if let Err(e) = res { |
3157f602 | 990 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
e9174d1e SL |
991 | } |
992 | let mut arg = OsString::from("/DEF:"); | |
993 | arg.push(path); | |
994 | self.cmd.arg(&arg); | |
995 | } | |
c30ab7b3 SL |
996 | |
997 | fn subsystem(&mut self, subsystem: &str) { | |
998 | // Note that previous passes of the compiler validated this subsystem, | |
999 | // so we just blindly pass it to the linker. | |
1000 | self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); | |
1001 | ||
1002 | // Windows has two subsystems we're interested in right now, the console | |
1003 | // and windows subsystems. These both implicitly have different entry | |
1004 | // points (starting symbols). The console entry point starts with | |
1005 | // `mainCRTStartup` and the windows entry point starts with | |
1006 | // `WinMainCRTStartup`. These entry points, defined in system libraries, | |
1007 | // will then later probe for either `main` or `WinMain`, respectively to | |
1008 | // start the application. | |
1009 | // | |
1010 | // In Rust we just always generate a `main` function so we want control | |
1011 | // to always start there, so we force the entry point on the windows | |
1012 | // subsystem to be `mainCRTStartup` to get everything booted up | |
1013 | // correctly. | |
1014 | // | |
1015 | // For more information see RFC #1665 | |
1016 | if subsystem == "windows" { | |
1017 | self.cmd.arg("/ENTRY:mainCRTStartup"); | |
1018 | } | |
1019 | } | |
cc61c64b | 1020 | |
0531ce1d XL |
1021 | // MSVC doesn't need group indicators |
1022 | fn group_start(&mut self) {} | |
1023 | fn group_end(&mut self) {} | |
94b46f34 | 1024 | |
9fa01778 | 1025 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1026 | // Do nothing |
1027 | } | |
cdc7bbd5 XL |
1028 | |
1029 | fn add_no_exec(&mut self) { | |
1030 | self.cmd.arg("/NXCOMPAT"); | |
1031 | } | |
62682a34 | 1032 | } |
a7813a04 | 1033 | |
8bb4bdeb | 1034 | pub struct EmLinker<'a> { |
cc61c64b | 1035 | cmd: Command, |
8bb4bdeb | 1036 | sess: &'a Session, |
8bb4bdeb XL |
1037 | } |
1038 | ||
1039 | impl<'a> Linker for EmLinker<'a> { | |
ba9703b0 XL |
1040 | fn cmd(&mut self) -> &mut Command { |
1041 | &mut self.cmd | |
1042 | } | |
f9f354fc XL |
1043 | |
1044 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1045 | ||
8bb4bdeb XL |
1046 | fn include_path(&mut self, path: &Path) { |
1047 | self.cmd.arg("-L").arg(path); | |
1048 | } | |
1049 | ||
17df50a5 | 1050 | fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { |
e1599b0c | 1051 | self.cmd.arg("-l").sym_arg(lib); |
8bb4bdeb XL |
1052 | } |
1053 | ||
1054 | fn output_filename(&mut self, path: &Path) { | |
1055 | self.cmd.arg("-o").arg(path); | |
1056 | } | |
1057 | ||
1058 | fn add_object(&mut self, path: &Path) { | |
1059 | self.cmd.arg(path); | |
1060 | } | |
1061 | ||
17df50a5 | 1062 | fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { |
8bb4bdeb | 1063 | // Emscripten always links statically |
17df50a5 | 1064 | self.link_staticlib(lib, verbatim); |
8bb4bdeb XL |
1065 | } |
1066 | ||
17df50a5 | 1067 | fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { |
8bb4bdeb | 1068 | // not supported? |
17df50a5 | 1069 | self.link_staticlib(lib, verbatim); |
8bb4bdeb XL |
1070 | } |
1071 | ||
1072 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1073 | // not supported? | |
1074 | self.link_rlib(lib); | |
1075 | } | |
1076 | ||
e1599b0c | 1077 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
17df50a5 | 1078 | self.link_dylib(lib, false, true); |
8bb4bdeb XL |
1079 | } |
1080 | ||
1081 | fn link_rlib(&mut self, lib: &Path) { | |
1082 | self.add_object(lib); | |
1083 | } | |
1084 | ||
3b2f2976 XL |
1085 | fn full_relro(&mut self) { |
1086 | // noop | |
1087 | } | |
1088 | ||
0531ce1d XL |
1089 | fn partial_relro(&mut self) { |
1090 | // noop | |
1091 | } | |
1092 | ||
1093 | fn no_relro(&mut self) { | |
1094 | // noop | |
1095 | } | |
1096 | ||
8bb4bdeb XL |
1097 | fn framework_path(&mut self, _path: &Path) { |
1098 | bug!("frameworks are not supported on Emscripten") | |
1099 | } | |
1100 | ||
17df50a5 | 1101 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { |
8bb4bdeb XL |
1102 | bug!("frameworks are not supported on Emscripten") |
1103 | } | |
1104 | ||
1105 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
1106 | // noop | |
1107 | } | |
1108 | ||
17df50a5 XL |
1109 | fn no_gc_sections(&mut self) { |
1110 | // noop | |
1111 | } | |
1112 | ||
8bb4bdeb XL |
1113 | fn optimize(&mut self) { |
1114 | // Emscripten performs own optimizations | |
1115 | self.cmd.arg(match self.sess.opts.optimize { | |
1116 | OptLevel::No => "-O0", | |
1117 | OptLevel::Less => "-O1", | |
1118 | OptLevel::Default => "-O2", | |
1119 | OptLevel::Aggressive => "-O3", | |
1120 | OptLevel::Size => "-Os", | |
dfeec247 | 1121 | OptLevel::SizeMin => "-Oz", |
8bb4bdeb | 1122 | }); |
8bb4bdeb XL |
1123 | } |
1124 | ||
0531ce1d XL |
1125 | fn pgo_gen(&mut self) { |
1126 | // noop, but maybe we need something like the gnu linker? | |
1127 | } | |
1128 | ||
f035d41b | 1129 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1130 | |
04454e1e | 1131 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
8bb4bdeb XL |
1132 | // Preserve names or generate source maps depending on debug info |
1133 | self.cmd.arg(match self.sess.opts.debuginfo { | |
b7449926 | 1134 | DebugInfo::None => "-g0", |
923072b8 FG |
1135 | DebugInfo::Limited => "--profiling-funcs", |
1136 | DebugInfo::Full => "-g", | |
8bb4bdeb XL |
1137 | }); |
1138 | } | |
1139 | ||
f9f354fc XL |
1140 | fn no_crt_objects(&mut self) {} |
1141 | ||
8bb4bdeb | 1142 | fn no_default_libraries(&mut self) { |
923072b8 | 1143 | self.cmd.arg("-nodefaultlibs"); |
8bb4bdeb XL |
1144 | } |
1145 | ||
136023e0 | 1146 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
8bb4bdeb XL |
1147 | debug!("EXPORTED SYMBOLS:"); |
1148 | ||
1149 | self.cmd.arg("-s"); | |
1150 | ||
1151 | let mut arg = OsString::from("EXPORTED_FUNCTIONS="); | |
923072b8 FG |
1152 | let encoded = serde_json::to_string( |
1153 | &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(), | |
1154 | ) | |
1155 | .unwrap(); | |
8bb4bdeb | 1156 | debug!("{}", encoded); |
923072b8 | 1157 | |
8bb4bdeb XL |
1158 | arg.push(encoded); |
1159 | ||
1160 | self.cmd.arg(arg); | |
1161 | } | |
1162 | ||
1163 | fn subsystem(&mut self, _subsystem: &str) { | |
1164 | // noop | |
1165 | } | |
cc61c64b | 1166 | |
0531ce1d XL |
1167 | // Appears not necessary on Emscripten |
1168 | fn group_start(&mut self) {} | |
1169 | fn group_end(&mut self) {} | |
94b46f34 | 1170 | |
9fa01778 | 1171 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1172 | // Do nothing |
1173 | } | |
8bb4bdeb XL |
1174 | } |
1175 | ||
8faf50e0 | 1176 | pub struct WasmLd<'a> { |
0531ce1d | 1177 | cmd: Command, |
8faf50e0 | 1178 | sess: &'a Session, |
0531ce1d XL |
1179 | } |
1180 | ||
0731742a | 1181 | impl<'a> WasmLd<'a> { |
136023e0 | 1182 | fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { |
416331ca XL |
1183 | // If the atomics feature is enabled for wasm then we need a whole bunch |
1184 | // of flags: | |
1185 | // | |
1186 | // * `--shared-memory` - the link won't even succeed without this, flags | |
1187 | // the one linear memory as `shared` | |
1188 | // | |
1189 | // * `--max-memory=1G` - when specifying a shared memory this must also | |
1190 | // be specified. We conservatively choose 1GB but users should be able | |
1191 | // to override this with `-C link-arg`. | |
1192 | // | |
1193 | // * `--import-memory` - it doesn't make much sense for memory to be | |
1194 | // exported in a threaded module because typically you're | |
1195 | // sharing memory and instantiating the module multiple times. As a | |
1196 | // result if it were exported then we'd just have no sharing. | |
1197 | // | |
416331ca XL |
1198 | // * `--export=__wasm_init_memory` - when using `--passive-segments` the |
1199 | // linker will synthesize this function, and so we need to make sure | |
1200 | // that our usage of `--export` below won't accidentally cause this | |
1201 | // function to get deleted. | |
1202 | // | |
1203 | // * `--export=*tls*` - when `#[thread_local]` symbols are used these | |
1204 | // symbols are how the TLS segments are initialized and configured. | |
f035d41b | 1205 | if sess.target_features.contains(&sym::atomics) { |
416331ca XL |
1206 | cmd.arg("--shared-memory"); |
1207 | cmd.arg("--max-memory=1073741824"); | |
1208 | cmd.arg("--import-memory"); | |
416331ca XL |
1209 | cmd.arg("--export=__wasm_init_memory"); |
1210 | cmd.arg("--export=__wasm_init_tls"); | |
1211 | cmd.arg("--export=__tls_size"); | |
1212 | cmd.arg("--export=__tls_align"); | |
1213 | cmd.arg("--export=__tls_base"); | |
1214 | } | |
136023e0 | 1215 | WasmLd { cmd, sess } |
0731742a XL |
1216 | } |
1217 | } | |
1218 | ||
8faf50e0 | 1219 | impl<'a> Linker for WasmLd<'a> { |
ba9703b0 XL |
1220 | fn cmd(&mut self) -> &mut Command { |
1221 | &mut self.cmd | |
1222 | } | |
1223 | ||
f9f354fc XL |
1224 | fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { |
1225 | match output_kind { | |
1226 | LinkOutputKind::DynamicNoPicExe | |
1227 | | LinkOutputKind::DynamicPicExe | |
1228 | | LinkOutputKind::StaticNoPicExe | |
1229 | | LinkOutputKind::StaticPicExe => {} | |
1230 | LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { | |
1231 | self.cmd.arg("--no-entry"); | |
1232 | } | |
5869c6ff XL |
1233 | LinkOutputKind::WasiReactorExe => { |
1234 | self.cmd.arg("--entry"); | |
1235 | self.cmd.arg("_initialize"); | |
1236 | } | |
f9f354fc XL |
1237 | } |
1238 | } | |
1239 | ||
17df50a5 | 1240 | fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) { |
e1599b0c | 1241 | self.cmd.arg("-l").sym_arg(lib); |
0531ce1d XL |
1242 | } |
1243 | ||
17df50a5 | 1244 | fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { |
e1599b0c | 1245 | self.cmd.arg("-l").sym_arg(lib); |
0531ce1d XL |
1246 | } |
1247 | ||
1248 | fn link_rlib(&mut self, lib: &Path) { | |
1249 | self.cmd.arg(lib); | |
1250 | } | |
1251 | ||
1252 | fn include_path(&mut self, path: &Path) { | |
1253 | self.cmd.arg("-L").arg(path); | |
1254 | } | |
1255 | ||
1256 | fn framework_path(&mut self, _path: &Path) { | |
1257 | panic!("frameworks not supported") | |
1258 | } | |
1259 | ||
1260 | fn output_filename(&mut self, path: &Path) { | |
1261 | self.cmd.arg("-o").arg(path); | |
1262 | } | |
1263 | ||
1264 | fn add_object(&mut self, path: &Path) { | |
1265 | self.cmd.arg(path); | |
1266 | } | |
1267 | ||
dfeec247 | 1268 | fn full_relro(&mut self) {} |
0531ce1d | 1269 | |
dfeec247 | 1270 | fn partial_relro(&mut self) {} |
0531ce1d | 1271 | |
dfeec247 | 1272 | fn no_relro(&mut self) {} |
0531ce1d | 1273 | |
e1599b0c XL |
1274 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
1275 | self.cmd.arg("-l").sym_arg(lib); | |
0531ce1d XL |
1276 | } |
1277 | ||
17df50a5 | 1278 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { |
0531ce1d XL |
1279 | panic!("frameworks not supported") |
1280 | } | |
1281 | ||
17df50a5 | 1282 | fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { |
e1599b0c | 1283 | self.cmd.arg("-l").sym_arg(lib); |
0531ce1d XL |
1284 | } |
1285 | ||
1286 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1287 | self.cmd.arg(lib); | |
1288 | } | |
1289 | ||
1290 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
8faf50e0 | 1291 | self.cmd.arg("--gc-sections"); |
0531ce1d XL |
1292 | } |
1293 | ||
17df50a5 XL |
1294 | fn no_gc_sections(&mut self) { |
1295 | self.cmd.arg("--no-gc-sections"); | |
1296 | } | |
1297 | ||
0531ce1d | 1298 | fn optimize(&mut self) { |
8faf50e0 XL |
1299 | self.cmd.arg(match self.sess.opts.optimize { |
1300 | OptLevel::No => "-O0", | |
1301 | OptLevel::Less => "-O1", | |
1302 | OptLevel::Default => "-O2", | |
1303 | OptLevel::Aggressive => "-O3", | |
1304 | // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` | |
1305 | // instead. | |
1306 | OptLevel::Size => "-O2", | |
dfeec247 | 1307 | OptLevel::SizeMin => "-O2", |
8faf50e0 | 1308 | }); |
0531ce1d XL |
1309 | } |
1310 | ||
dfeec247 | 1311 | fn pgo_gen(&mut self) {} |
0531ce1d | 1312 | |
04454e1e | 1313 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
f9f354fc XL |
1314 | match strip { |
1315 | Strip::None => {} | |
1316 | Strip::Debuginfo => { | |
1317 | self.cmd.arg("--strip-debug"); | |
1318 | } | |
1319 | Strip::Symbols => { | |
1320 | self.cmd.arg("--strip-all"); | |
1321 | } | |
1322 | } | |
1323 | } | |
0531ce1d | 1324 | |
f035d41b | 1325 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1326 | |
f9f354fc | 1327 | fn no_crt_objects(&mut self) {} |
0531ce1d | 1328 | |
f9f354fc | 1329 | fn no_default_libraries(&mut self) {} |
0531ce1d | 1330 | |
136023e0 XL |
1331 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
1332 | for sym in symbols { | |
0bf4aa26 XL |
1333 | self.cmd.arg("--export").arg(&sym); |
1334 | } | |
416331ca | 1335 | |
f035d41b | 1336 | // LLD will hide these otherwise-internal symbols since it only exports |
5e7ed085 | 1337 | // symbols explicitly passed via the `--export` flags above and hides all |
f035d41b XL |
1338 | // others. Various bits and pieces of tooling use this, so be sure these |
1339 | // symbols make their way out of the linker as well. | |
416331ca XL |
1340 | self.cmd.arg("--export=__heap_base"); |
1341 | self.cmd.arg("--export=__data_end"); | |
0531ce1d XL |
1342 | } |
1343 | ||
dfeec247 | 1344 | fn subsystem(&mut self, _subsystem: &str) {} |
0531ce1d | 1345 | |
0531ce1d XL |
1346 | // Not needed for now with LLD |
1347 | fn group_start(&mut self) {} | |
1348 | fn group_end(&mut self) {} | |
94b46f34 | 1349 | |
9fa01778 | 1350 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1351 | // Do nothing for now |
1352 | } | |
0531ce1d | 1353 | } |
a1dfa0c6 | 1354 | |
5099ac24 FG |
1355 | /// Linker shepherd script for L4Re (Fiasco) |
1356 | pub struct L4Bender<'a> { | |
1357 | cmd: Command, | |
1358 | sess: &'a Session, | |
1359 | hinted_static: bool, | |
1360 | } | |
1361 | ||
1362 | impl<'a> Linker for L4Bender<'a> { | |
1363 | fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { | |
1364 | bug!("dylibs are not supported on L4Re"); | |
1365 | } | |
1366 | fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { | |
1367 | self.hint_static(); | |
1368 | self.cmd.arg(format!("-PC{}", lib)); | |
1369 | } | |
1370 | fn link_rlib(&mut self, lib: &Path) { | |
1371 | self.hint_static(); | |
1372 | self.cmd.arg(lib); | |
1373 | } | |
1374 | fn include_path(&mut self, path: &Path) { | |
1375 | self.cmd.arg("-L").arg(path); | |
1376 | } | |
1377 | fn framework_path(&mut self, _: &Path) { | |
1378 | bug!("frameworks are not supported on L4Re"); | |
1379 | } | |
1380 | fn output_filename(&mut self, path: &Path) { | |
1381 | self.cmd.arg("-o").arg(path); | |
1382 | } | |
1383 | ||
1384 | fn add_object(&mut self, path: &Path) { | |
1385 | self.cmd.arg(path); | |
1386 | } | |
1387 | ||
1388 | fn full_relro(&mut self) { | |
1389 | self.cmd.arg("-zrelro"); | |
1390 | self.cmd.arg("-znow"); | |
1391 | } | |
1392 | ||
1393 | fn partial_relro(&mut self) { | |
1394 | self.cmd.arg("-zrelro"); | |
1395 | } | |
1396 | ||
1397 | fn no_relro(&mut self) { | |
1398 | self.cmd.arg("-znorelro"); | |
1399 | } | |
1400 | ||
1401 | fn cmd(&mut self) -> &mut Command { | |
1402 | &mut self.cmd | |
1403 | } | |
1404 | ||
1405 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1406 | ||
1407 | fn link_rust_dylib(&mut self, _: Symbol, _: &Path) { | |
1408 | panic!("Rust dylibs not supported"); | |
1409 | } | |
1410 | ||
1411 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { | |
1412 | bug!("frameworks not supported on L4Re"); | |
1413 | } | |
1414 | ||
1415 | fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { | |
1416 | self.hint_static(); | |
1417 | self.cmd.arg("--whole-archive").arg(format!("-l{}", lib)); | |
1418 | self.cmd.arg("--no-whole-archive"); | |
1419 | } | |
1420 | ||
1421 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1422 | self.hint_static(); | |
1423 | self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); | |
1424 | } | |
1425 | ||
1426 | fn gc_sections(&mut self, keep_metadata: bool) { | |
1427 | if !keep_metadata { | |
1428 | self.cmd.arg("--gc-sections"); | |
1429 | } | |
1430 | } | |
1431 | ||
1432 | fn no_gc_sections(&mut self) { | |
1433 | self.cmd.arg("--no-gc-sections"); | |
1434 | } | |
1435 | ||
1436 | fn optimize(&mut self) { | |
1437 | // GNU-style linkers support optimization with -O. GNU ld doesn't | |
1438 | // need a numeric argument, but other linkers do. | |
1439 | if self.sess.opts.optimize == config::OptLevel::Default | |
1440 | || self.sess.opts.optimize == config::OptLevel::Aggressive | |
1441 | { | |
1442 | self.cmd.arg("-O1"); | |
1443 | } | |
1444 | } | |
1445 | ||
1446 | fn pgo_gen(&mut self) {} | |
1447 | ||
04454e1e | 1448 | fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { |
5099ac24 FG |
1449 | match strip { |
1450 | Strip::None => {} | |
1451 | Strip::Debuginfo => { | |
1452 | self.cmd().arg("--strip-debug"); | |
1453 | } | |
1454 | Strip::Symbols => { | |
1455 | self.cmd().arg("--strip-all"); | |
1456 | } | |
1457 | } | |
1458 | } | |
1459 | ||
1460 | fn no_default_libraries(&mut self) { | |
1461 | self.cmd.arg("-nostdlib"); | |
1462 | } | |
1463 | ||
1464 | fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { | |
1465 | // ToDo, not implemented, copy from GCC | |
1466 | self.sess.warn("exporting symbols not implemented yet for L4Bender"); | |
1467 | return; | |
1468 | } | |
1469 | ||
1470 | fn subsystem(&mut self, subsystem: &str) { | |
1471 | self.cmd.arg(&format!("--subsystem {}", subsystem)); | |
1472 | } | |
1473 | ||
1474 | fn reset_per_library_state(&mut self) { | |
1475 | self.hint_static(); // Reset to default before returning the composed command line. | |
1476 | } | |
1477 | ||
1478 | fn group_start(&mut self) { | |
1479 | self.cmd.arg("--start-group"); | |
1480 | } | |
1481 | ||
1482 | fn group_end(&mut self) { | |
1483 | self.cmd.arg("--end-group"); | |
1484 | } | |
1485 | ||
1486 | fn linker_plugin_lto(&mut self) {} | |
1487 | ||
1488 | fn control_flow_guard(&mut self) {} | |
1489 | ||
1490 | fn no_crt_objects(&mut self) {} | |
1491 | } | |
1492 | ||
1493 | impl<'a> L4Bender<'a> { | |
1494 | pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { | |
1495 | L4Bender { cmd: cmd, sess: sess, hinted_static: false } | |
1496 | } | |
1497 | ||
1498 | fn hint_static(&mut self) { | |
1499 | if !self.hinted_static { | |
1500 | self.cmd.arg("-static"); | |
1501 | self.hinted_static = true; | |
1502 | } | |
1503 | } | |
1504 | } | |
1505 | ||
04454e1e FG |
1506 | fn for_each_exported_symbols_include_dep<'tcx>( |
1507 | tcx: TyCtxt<'tcx>, | |
1508 | crate_type: CrateType, | |
1509 | mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), | |
1510 | ) { | |
1511 | for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { | |
1512 | callback(symbol, info, LOCAL_CRATE); | |
1513 | } | |
1514 | ||
1515 | let formats = tcx.dependency_formats(()); | |
1516 | let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap(); | |
1517 | ||
1518 | for (index, dep_format) in deps.iter().enumerate() { | |
1519 | let cnum = CrateNum::new(index + 1); | |
1520 | // For each dependency that we are linking to statically ... | |
1521 | if *dep_format == Linkage::Static { | |
1522 | for &(symbol, info) in tcx.exported_symbols(cnum).iter() { | |
1523 | callback(symbol, info, cnum); | |
1524 | } | |
1525 | } | |
1526 | } | |
1527 | } | |
1528 | ||
136023e0 | 1529 | pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { |
29967ef6 | 1530 | if let Some(ref exports) = tcx.sess.target.override_export_symbols { |
5e7ed085 | 1531 | return exports.iter().map(ToString::to_string).collect(); |
a1dfa0c6 XL |
1532 | } |
1533 | ||
1534 | let mut symbols = Vec::new(); | |
1535 | ||
1536 | let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); | |
04454e1e FG |
1537 | for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { |
1538 | if info.level.is_below_threshold(export_threshold) { | |
1539 | symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum)); | |
a1dfa0c6 | 1540 | } |
04454e1e | 1541 | }); |
a1dfa0c6 | 1542 | |
04454e1e FG |
1543 | symbols |
1544 | } | |
e74abb32 | 1545 | |
04454e1e FG |
1546 | pub(crate) fn linked_symbols( |
1547 | tcx: TyCtxt<'_>, | |
1548 | crate_type: CrateType, | |
1549 | ) -> Vec<(String, SymbolExportKind)> { | |
1550 | match crate_type { | |
1551 | CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (), | |
1552 | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { | |
1553 | return Vec::new(); | |
a1dfa0c6 XL |
1554 | } |
1555 | } | |
1556 | ||
04454e1e FG |
1557 | let mut symbols = Vec::new(); |
1558 | ||
1559 | let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); | |
1560 | for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { | |
1561 | if info.level.is_below_threshold(export_threshold) || info.used { | |
1562 | symbols.push(( | |
1563 | symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), | |
1564 | info.kind, | |
1565 | )); | |
1566 | } | |
1567 | }); | |
1568 | ||
a1dfa0c6 XL |
1569 | symbols |
1570 | } | |
9fa01778 XL |
1571 | |
1572 | /// Much simplified and explicit CLI for the NVPTX linker. The linker operates | |
1573 | /// with bitcode and uses LLVM backend to generate a PTX assembly. | |
1574 | pub struct PtxLinker<'a> { | |
1575 | cmd: Command, | |
1576 | sess: &'a Session, | |
1577 | } | |
1578 | ||
1579 | impl<'a> Linker for PtxLinker<'a> { | |
ba9703b0 XL |
1580 | fn cmd(&mut self) -> &mut Command { |
1581 | &mut self.cmd | |
1582 | } | |
1583 | ||
f9f354fc XL |
1584 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} |
1585 | ||
9fa01778 XL |
1586 | fn link_rlib(&mut self, path: &Path) { |
1587 | self.cmd.arg("--rlib").arg(path); | |
1588 | } | |
1589 | ||
1590 | fn link_whole_rlib(&mut self, path: &Path) { | |
1591 | self.cmd.arg("--rlib").arg(path); | |
1592 | } | |
1593 | ||
1594 | fn include_path(&mut self, path: &Path) { | |
1595 | self.cmd.arg("-L").arg(path); | |
1596 | } | |
1597 | ||
04454e1e | 1598 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
9fa01778 XL |
1599 | self.cmd.arg("--debug"); |
1600 | } | |
1601 | ||
1602 | fn add_object(&mut self, path: &Path) { | |
1603 | self.cmd.arg("--bitcode").arg(path); | |
1604 | } | |
1605 | ||
9fa01778 XL |
1606 | fn optimize(&mut self) { |
1607 | match self.sess.lto() { | |
1608 | Lto::Thin | Lto::Fat | Lto::ThinLocal => { | |
1609 | self.cmd.arg("-Olto"); | |
dfeec247 | 1610 | } |
9fa01778 | 1611 | |
dfeec247 | 1612 | Lto::No => {} |
9fa01778 XL |
1613 | }; |
1614 | } | |
1615 | ||
1616 | fn output_filename(&mut self, path: &Path) { | |
1617 | self.cmd.arg("-o").arg(path); | |
1618 | } | |
1619 | ||
17df50a5 XL |
1620 | fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { |
1621 | panic!("external dylibs not supported") | |
1622 | } | |
1623 | ||
1624 | fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { | |
1625 | panic!("external dylibs not supported") | |
1626 | } | |
1627 | ||
1628 | fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { | |
1629 | panic!("staticlibs not supported") | |
1630 | } | |
1631 | ||
1632 | fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { | |
1633 | panic!("staticlibs not supported") | |
1634 | } | |
1635 | ||
1636 | fn framework_path(&mut self, _path: &Path) { | |
1637 | panic!("frameworks not supported") | |
1638 | } | |
1639 | ||
1640 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { | |
1641 | panic!("frameworks not supported") | |
1642 | } | |
1643 | ||
1644 | fn full_relro(&mut self) {} | |
1645 | ||
1646 | fn partial_relro(&mut self) {} | |
1647 | ||
1648 | fn no_relro(&mut self) {} | |
1649 | ||
1650 | fn gc_sections(&mut self, _keep_metadata: bool) {} | |
1651 | ||
1652 | fn no_gc_sections(&mut self) {} | |
1653 | ||
1654 | fn pgo_gen(&mut self) {} | |
1655 | ||
1656 | fn no_crt_objects(&mut self) {} | |
1657 | ||
1658 | fn no_default_libraries(&mut self) {} | |
1659 | ||
1660 | fn control_flow_guard(&mut self) {} | |
1661 | ||
136023e0 | 1662 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} |
17df50a5 XL |
1663 | |
1664 | fn subsystem(&mut self, _subsystem: &str) {} | |
1665 | ||
1666 | fn group_start(&mut self) {} | |
1667 | ||
1668 | fn group_end(&mut self) {} | |
1669 | ||
1670 | fn linker_plugin_lto(&mut self) {} | |
1671 | } | |
1672 | ||
1673 | pub struct BpfLinker<'a> { | |
1674 | cmd: Command, | |
1675 | sess: &'a Session, | |
17df50a5 XL |
1676 | } |
1677 | ||
1678 | impl<'a> Linker for BpfLinker<'a> { | |
1679 | fn cmd(&mut self) -> &mut Command { | |
1680 | &mut self.cmd | |
1681 | } | |
1682 | ||
1683 | fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} | |
1684 | ||
1685 | fn link_rlib(&mut self, path: &Path) { | |
1686 | self.cmd.arg(path); | |
1687 | } | |
1688 | ||
1689 | fn link_whole_rlib(&mut self, path: &Path) { | |
1690 | self.cmd.arg(path); | |
1691 | } | |
1692 | ||
1693 | fn include_path(&mut self, path: &Path) { | |
1694 | self.cmd.arg("-L").arg(path); | |
1695 | } | |
1696 | ||
04454e1e | 1697 | fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { |
17df50a5 XL |
1698 | self.cmd.arg("--debug"); |
1699 | } | |
1700 | ||
1701 | fn add_object(&mut self, path: &Path) { | |
1702 | self.cmd.arg(path); | |
1703 | } | |
1704 | ||
1705 | fn optimize(&mut self) { | |
1706 | self.cmd.arg(match self.sess.opts.optimize { | |
1707 | OptLevel::No => "-O0", | |
1708 | OptLevel::Less => "-O1", | |
1709 | OptLevel::Default => "-O2", | |
1710 | OptLevel::Aggressive => "-O3", | |
1711 | OptLevel::Size => "-Os", | |
1712 | OptLevel::SizeMin => "-Oz", | |
9fa01778 | 1713 | }); |
9fa01778 XL |
1714 | } |
1715 | ||
17df50a5 XL |
1716 | fn output_filename(&mut self, path: &Path) { |
1717 | self.cmd.arg("-o").arg(path); | |
1718 | } | |
1719 | ||
1720 | fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { | |
9fa01778 XL |
1721 | panic!("external dylibs not supported") |
1722 | } | |
1723 | ||
e1599b0c | 1724 | fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { |
9fa01778 XL |
1725 | panic!("external dylibs not supported") |
1726 | } | |
1727 | ||
17df50a5 | 1728 | fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { |
9fa01778 XL |
1729 | panic!("staticlibs not supported") |
1730 | } | |
1731 | ||
17df50a5 | 1732 | fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { |
9fa01778 XL |
1733 | panic!("staticlibs not supported") |
1734 | } | |
1735 | ||
1736 | fn framework_path(&mut self, _path: &Path) { | |
1737 | panic!("frameworks not supported") | |
1738 | } | |
1739 | ||
17df50a5 | 1740 | fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { |
9fa01778 XL |
1741 | panic!("frameworks not supported") |
1742 | } | |
1743 | ||
dfeec247 | 1744 | fn full_relro(&mut self) {} |
9fa01778 | 1745 | |
dfeec247 | 1746 | fn partial_relro(&mut self) {} |
9fa01778 | 1747 | |
dfeec247 | 1748 | fn no_relro(&mut self) {} |
9fa01778 | 1749 | |
dfeec247 | 1750 | fn gc_sections(&mut self, _keep_metadata: bool) {} |
9fa01778 | 1751 | |
17df50a5 XL |
1752 | fn no_gc_sections(&mut self) {} |
1753 | ||
dfeec247 | 1754 | fn pgo_gen(&mut self) {} |
9fa01778 | 1755 | |
f9f354fc XL |
1756 | fn no_crt_objects(&mut self) {} |
1757 | ||
dfeec247 | 1758 | fn no_default_libraries(&mut self) {} |
9fa01778 | 1759 | |
f035d41b | 1760 | fn control_flow_guard(&mut self) {} |
74b04a01 | 1761 | |
136023e0 | 1762 | fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { |
17df50a5 XL |
1763 | let path = tmpdir.join("symbols"); |
1764 | let res: io::Result<()> = try { | |
1765 | let mut f = BufWriter::new(File::create(&path)?); | |
136023e0 | 1766 | for sym in symbols { |
17df50a5 XL |
1767 | writeln!(f, "{}", sym)?; |
1768 | } | |
1769 | }; | |
1770 | if let Err(e) = res { | |
1771 | self.sess.fatal(&format!("failed to write symbols file: {}", e)); | |
1772 | } else { | |
1773 | self.cmd.arg("--export-symbols").arg(&path); | |
1774 | } | |
1775 | } | |
9fa01778 | 1776 | |
dfeec247 | 1777 | fn subsystem(&mut self, _subsystem: &str) {} |
9fa01778 | 1778 | |
dfeec247 | 1779 | fn group_start(&mut self) {} |
9fa01778 | 1780 | |
dfeec247 | 1781 | fn group_end(&mut self) {} |
9fa01778 | 1782 | |
dfeec247 | 1783 | fn linker_plugin_lto(&mut self) {} |
9fa01778 | 1784 | } |