linker.rs 44.7 KB
Newer Older
1
use super::archive;
M
Mark Rousskov 已提交
2 3
use super::command::Command;
use super::symbol_export;
4
use rustc_span::symbol::sym;
5

J
Jorge Aparicio 已提交
6
use std::ffi::{OsStr, OsString};
7 8
use std::fs::{self, File};
use std::io::prelude::*;
9
use std::io::{self, BufWriter};
10
use std::mem;
11 12
use std::path::{Path, PathBuf};

13
use rustc_data_structures::fx::FxHashMap;
14
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
15 16
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::ty::TyCtxt;
17
use rustc_serialize::{json, Encoder};
Y
YI 已提交
18
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
19
use rustc_session::Session;
20
use rustc_span::symbol::Symbol;
21
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
22

23 24 25 26 27 28 29 30
/// Disables non-English messages from localized linkers.
/// Such messages may cause issues with text encoding on Windows (#35785)
/// and prevent inspection of linker output in case of errors, which we occasionally do.
/// This should be acceptable because other messages from rustc are in English anyway,
/// and may also be desirable to improve searchability of the linker diagnostics.
pub fn disable_localization(linker: &mut Command) {
    // No harm in setting both env vars simultaneously.
    // Unix-style linkers.
31
    linker.env("LC_ALL", "C");
32 33 34 35
    // MSVC's `link.exe`.
    linker.env("VSLANG", "1033");
}

36 37
/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
M
Matthew Jasper 已提交
38
#[derive(Encodable, Decodable)]
39
pub struct LinkerInfo {
40
    exports: FxHashMap<CrateType, Vec<String>>,
41 42
}

43
impl LinkerInfo {
44
    pub fn new(tcx: TyCtxt<'_>) -> LinkerInfo {
45
        LinkerInfo {
M
Mark Rousskov 已提交
46 47
            exports: tcx
                .sess
48
                .crate_types()
M
Mark Rousskov 已提交
49 50 51
                .iter()
                .map(|&c| (c, exported_symbols(tcx, c)))
                .collect(),
52 53 54
        }
    }

B
bjorn3 已提交
55 56 57 58 59 60
    pub fn to_linker<'a>(
        &'a self,
        cmd: Command,
        sess: &'a Session,
        flavor: LinkerFlavor,
        target_cpu: &'a str,
M
Mark Rousskov 已提交
61
    ) -> Box<dyn Linker + 'a> {
62
        match flavor {
M
Mark Rousskov 已提交
63 64
            LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
                Box::new(MsvcLinker { cmd, sess, info: self }) as Box<dyn Linker>
J
Jorge Aparicio 已提交
65
            }
M
Mark Rousskov 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
            LinkerFlavor::Em => Box::new(EmLinker { cmd, sess, info: self }) as Box<dyn Linker>,
            LinkerFlavor::Gcc => Box::new(GccLinker {
                cmd,
                sess,
                info: self,
                hinted_static: false,
                is_ld: false,
                target_cpu,
            }) as Box<dyn Linker>,

            LinkerFlavor::Lld(LldFlavor::Ld)
            | LinkerFlavor::Lld(LldFlavor::Ld64)
            | LinkerFlavor::Ld => Box::new(GccLinker {
                cmd,
                sess,
                info: self,
                hinted_static: false,
                is_ld: true,
                target_cpu,
            }) as Box<dyn Linker>,
86 87

            LinkerFlavor::Lld(LldFlavor::Wasm) => {
88
                Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
89
            }
90

M
Mark Rousskov 已提交
91
            LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
92 93 94
        }
    }
}
95

A
Alexander Regueiro 已提交
96
/// Linker abstraction used by `back::link` to build up the command to invoke a
97 98 99 100 101
/// linker.
///
/// This trait is the total list of requirements needed by `back::link` and
/// represents the meaning of each option being passed down. This trait is then
/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
102
/// MSVC linker (e.g., `link.exe`) is being used.
103
pub trait Linker {
104
    fn cmd(&mut self) -> &mut Command;
105
    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
N
Nicholas Nethercote 已提交
106 107 108 109
    fn link_dylib(&mut self, lib: Symbol);
    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
    fn link_framework(&mut self, framework: Symbol);
    fn link_staticlib(&mut self, lib: Symbol);
110
    fn link_rlib(&mut self, lib: &Path);
111
    fn link_whole_rlib(&mut self, lib: &Path);
N
Nicholas Nethercote 已提交
112
    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
113 114 115 116
    fn include_path(&mut self, path: &Path);
    fn framework_path(&mut self, path: &Path);
    fn output_filename(&mut self, path: &Path);
    fn add_object(&mut self, path: &Path);
117
    fn gc_sections(&mut self, keep_metadata: bool);
J
Johannes Löthberg 已提交
118
    fn full_relro(&mut self);
119 120
    fn partial_relro(&mut self);
    fn no_relro(&mut self);
121
    fn optimize(&mut self);
122
    fn pgo_gen(&mut self);
123
    fn control_flow_guard(&mut self);
Y
YI 已提交
124
    fn debuginfo(&mut self, strip: Strip);
125
    fn no_crt_objects(&mut self);
126
    fn no_default_libraries(&mut self);
127
    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
128
    fn subsystem(&mut self, subsystem: &str);
129 130
    fn group_start(&mut self);
    fn group_end(&mut self);
131
    fn linker_plugin_lto(&mut self);
132
    fn add_eh_frame_header(&mut self) {}
133
    fn add_as_needed(&mut self) {}
134
    fn finalize(&mut self);
135 136
}

137 138 139 140 141 142 143 144
impl dyn Linker + '_ {
    pub fn arg(&mut self, arg: impl AsRef<OsStr>) {
        self.cmd().arg(arg);
    }

    pub fn args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) {
        self.cmd().args(args);
    }
145 146 147 148

    pub fn take_cmd(&mut self) -> Command {
        mem::replace(self.cmd(), Command::new(""))
    }
149 150
}

J
Jorge Aparicio 已提交
151
pub struct GccLinker<'a> {
152
    cmd: Command,
153
    sess: &'a Session,
154 155
    info: &'a LinkerInfo,
    hinted_static: bool, // Keeps track of the current hinting mode.
J
Jorge Aparicio 已提交
156 157
    // Link as ld
    is_ld: bool,
B
bjorn3 已提交
158
    target_cpu: &'a str,
159 160
}

J
Jorge Aparicio 已提交
161 162 163
impl<'a> GccLinker<'a> {
    /// Argument that must be passed *directly* to the linker
    ///
A
Alexander Regueiro 已提交
164
    /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
J
Jorge Aparicio 已提交
165
    fn linker_arg<S>(&mut self, arg: S) -> &mut Self
M
Mark Rousskov 已提交
166 167
    where
        S: AsRef<OsStr>,
J
Jorge Aparicio 已提交
168 169 170 171 172 173 174 175 176 177 178
    {
        if !self.is_ld {
            let mut os = OsString::from("-Wl,");
            os.push(arg.as_ref());
            self.cmd.arg(os);
        } else {
            self.cmd.arg(arg);
        }
        self
    }

179
    fn takes_hints(&self) -> bool {
180 181 182 183 184 185 186 187
        // Really this function only returns true if the underlying linker
        // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We
        // don't really have a foolproof way to detect that, so rule out some
        // platforms where currently this is guaranteed to *not* be the case:
        //
        // * On OSX they have their own linker, not binutils'
        // * For WebAssembly the only functional linker is LLD, which doesn't
        //   support hint flags
188
        !self.sess.target.is_like_osx && self.sess.target.arch != "wasm32"
189
    }
190 191 192 193 194 195

    // Some platforms take hints about whether a library is static or dynamic.
    // For those that support this, we ensure we pass the option if the library
    // was flagged "static" (most defaults are dynamic) to ensure that if
    // libfoo.a and libfoo.so both exist that the right one is chosen.
    fn hint_static(&mut self) {
M
Mark Rousskov 已提交
196 197 198
        if !self.takes_hints() {
            return;
        }
199
        if !self.hinted_static {
J
Jorge Aparicio 已提交
200
            self.linker_arg("-Bstatic");
201 202 203 204 205
            self.hinted_static = true;
        }
    }

    fn hint_dynamic(&mut self) {
M
Mark Rousskov 已提交
206 207 208
        if !self.takes_hints() {
            return;
        }
209
        if self.hinted_static {
J
Jorge Aparicio 已提交
210
            self.linker_arg("-Bdynamic");
211 212 213
            self.hinted_static = false;
        }
    }
214

215
    fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
216 217 218 219 220 221 222 223 224
        if let Some(plugin_path) = plugin_path {
            let mut arg = OsString::from("-plugin=");
            arg.push(plugin_path);
            self.linker_arg(&arg);
        }

        let opt_level = match self.sess.opts.optimize {
            config::OptLevel::No => "O0",
            config::OptLevel::Less => "O1",
225
            config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
226 227 228 229
            config::OptLevel::Aggressive => "O3",
        };

        self.linker_arg(&format!("-plugin-opt={}", opt_level));
B
bjorn3 已提交
230 231
        let target_cpu = self.target_cpu;
        self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu));
232
    }
233 234 235

    fn build_dylib(&mut self, out_filename: &Path) {
        // On mac we need to tell the linker to let this library be rpathed
236
        if self.sess.target.is_like_osx {
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
            self.cmd.arg("-dynamiclib");
            self.linker_arg("-dylib");

            // Note that the `osx_rpath_install_name` option here is a hack
            // purely to support rustbuild right now, we should get a more
            // principled solution at some point to force the compiler to pass
            // the right `-Wl,-install_name` with an `@rpath` in it.
            if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
                self.linker_arg("-install_name");
                let mut v = OsString::from("@rpath/");
                v.push(out_filename.file_name().unwrap());
                self.linker_arg(&v);
            }
        } else {
            self.cmd.arg("-shared");
252
            if self.sess.target.is_like_windows {
253 254 255 256 257 258 259
                // The output filename already contains `dll_suffix` so
                // the resulting import library will have a name in the
                // form of libfoo.dll.a
                let implib_name =
                    out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
                        format!(
                            "{}{}{}",
260
                            self.sess.target.staticlib_prefix,
261
                            file,
262
                            self.sess.target.staticlib_suffix
263 264 265 266 267
                        )
                    });
                if let Some(implib_name) = implib_name {
                    let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
                    if let Some(implib) = implib {
268
                        self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap()));
269 270 271 272 273
                    }
                }
            }
        }
    }
274 275
}

J
Jorge Aparicio 已提交
276
impl<'a> Linker for GccLinker<'a> {
277 278 279
    fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }
280 281 282 283

    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
        match output_kind {
            LinkOutputKind::DynamicNoPicExe => {
284
                if !self.is_ld && self.sess.target.linker_is_gnu {
285 286 287 288 289 290 291 292 293 294
                    self.cmd.arg("-no-pie");
                }
            }
            LinkOutputKind::DynamicPicExe => {
                // `-pie` works for both gcc wrapper and ld.
                self.cmd.arg("-pie");
            }
            LinkOutputKind::StaticNoPicExe => {
                // `-static` works for both gcc wrapper and ld.
                self.cmd.arg("-static");
295
                if !self.is_ld && self.sess.target.linker_is_gnu {
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
                    self.cmd.arg("-no-pie");
                }
            }
            LinkOutputKind::StaticPicExe => {
                if !self.is_ld {
                    // Note that combination `-static -pie` doesn't work as expected
                    // for the gcc wrapper, `-static` in that case suppresses `-pie`.
                    self.cmd.arg("-static-pie");
                } else {
                    // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
                    // a static pie, but currently passed because gcc and clang pass them.
                    // The former suppresses the `INTERP` ELF header specifying dynamic linker,
                    // which is otherwise implicitly injected by ld (but not lld).
                    // The latter doesn't change anything, only ensures that everything is pic.
                    self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
                }
            }
            LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
            LinkOutputKind::StaticDylib => {
                self.cmd.arg("-static");
                self.build_dylib(out_filename);
            }
318 319 320 321
            LinkOutputKind::WasiReactorExe => {
                self.linker_arg("--entry");
                self.linker_arg("_initialize");
            }
322
        }
323 324 325 326 327
        // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
        // it switches linking for libc and similar system libraries to static without using
        // any `#[link]` attributes in the `libc` crate, see #72782 for details.
        // FIXME: Switch to using `#[link]` attributes in the `libc` crate
        // similarly to other targets.
328
        if self.sess.target.os == "vxworks"
329 330 331 332 333 334 335 336 337
            && matches!(
                output_kind,
                LinkOutputKind::StaticNoPicExe
                    | LinkOutputKind::StaticPicExe
                    | LinkOutputKind::StaticDylib
            )
        {
            self.cmd.arg("--static-crt");
        }
338 339
    }

N
Nicholas Nethercote 已提交
340 341 342 343 344 345 346
    fn link_dylib(&mut self, lib: Symbol) {
        self.hint_dynamic();
        self.cmd.arg(format!("-l{}", lib));
    }
    fn link_staticlib(&mut self, lib: Symbol) {
        self.hint_static();
        self.cmd.arg(format!("-l{}", lib));
347
    }
M
Mark Rousskov 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
    fn link_rlib(&mut self, lib: &Path) {
        self.hint_static();
        self.cmd.arg(lib);
    }
    fn include_path(&mut self, path: &Path) {
        self.cmd.arg("-L").arg(path);
    }
    fn framework_path(&mut self, path: &Path) {
        self.cmd.arg("-F").arg(path);
    }
    fn output_filename(&mut self, path: &Path) {
        self.cmd.arg("-o").arg(path);
    }
    fn add_object(&mut self, path: &Path) {
        self.cmd.arg(path);
    }
    fn full_relro(&mut self) {
        self.linker_arg("-zrelro");
        self.linker_arg("-znow");
    }
    fn partial_relro(&mut self) {
        self.linker_arg("-zrelro");
    }
    fn no_relro(&mut self) {
        self.linker_arg("-znorelro");
    }
374

N
Nicholas Nethercote 已提交
375
    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
376
        self.hint_dynamic();
377
        self.cmd.arg(format!("-l{}", lib));
378 379
    }

N
Nicholas Nethercote 已提交
380
    fn link_framework(&mut self, framework: Symbol) {
381
        self.hint_dynamic();
N
Nicholas Nethercote 已提交
382
        self.cmd.arg("-framework").sym_arg(framework);
383 384
    }

385 386 387 388 389 390
    // Here we explicitly ask that the entire archive is included into the
    // result artifact. For more details see #15460, but the gist is that
    // the linker will strip away any unused objects in the archive if we
    // don't otherwise explicitly reference them. This can occur for
    // libraries which are just providing bindings, libraries with generic
    // functions, etc.
N
Nicholas Nethercote 已提交
391
    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
392
        self.hint_static();
393
        let target = &self.sess.target;
394
        if !target.is_like_osx {
395
            self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
J
Jorge Aparicio 已提交
396
            self.linker_arg("--no-whole-archive");
397
        } else {
398
            // -force_load is the macOS equivalent of --whole-archive, but it
399
            // involves passing the full path to the library to link.
400
            self.linker_arg("-force_load");
401
            let lib = archive::find_library(lib, search_path, &self.sess);
402
            self.linker_arg(&lib);
403 404 405
        }
    }

406
    fn link_whole_rlib(&mut self, lib: &Path) {
407
        self.hint_static();
408
        if self.sess.target.is_like_osx {
409 410
            self.linker_arg("-force_load");
            self.linker_arg(&lib);
411
        } else {
J
Jorge Aparicio 已提交
412 413
            self.linker_arg("--whole-archive").cmd.arg(lib);
            self.linker_arg("--no-whole-archive");
414 415 416
        }
    }

417
    fn gc_sections(&mut self, keep_metadata: bool) {
418 419 420 421 422 423 424 425 426 427 428 429 430 431
        // The dead_strip option to the linker specifies that functions and data
        // unreachable by the entry point will be removed. This is quite useful
        // with Rust's compilation model of compiling libraries at a time into
        // one object file. For example, this brings hello world from 1.7MB to
        // 458K.
        //
        // Note that this is done for both executables and dynamic libraries. We
        // won't get much benefit from dylibs because LLVM will have already
        // stripped away as much as it could. This has not been seen to impact
        // link times negatively.
        //
        // -dead_strip can't be part of the pre_link_args because it's also used
        // for partial linking when using multiple codegen units (-r).  So we
        // insert it here.
432
        if self.sess.target.is_like_osx {
J
Jorge Aparicio 已提交
433
            self.linker_arg("-dead_strip");
434
        } else if self.sess.target.is_like_solaris {
435
            self.linker_arg("-zignore");
436 437 438 439 440 441

        // If we're building a dylib, we don't use --gc-sections because LLVM
        // has already done the best it can do, and we also don't want to
        // eliminate the metadata. If we're building an executable, however,
        // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
        // reduction.
442
        } else if !keep_metadata {
J
Jorge Aparicio 已提交
443
            self.linker_arg("--gc-sections");
444 445 446 447
        }
    }

    fn optimize(&mut self) {
448
        if !self.sess.target.linker_is_gnu {
M
Mark Rousskov 已提交
449 450
            return;
        }
451 452 453

        // GNU-style linkers support optimization with -O. GNU ld doesn't
        // need a numeric argument, but other linkers do.
M
Mark Rousskov 已提交
454 455 456
        if self.sess.opts.optimize == config::OptLevel::Default
            || self.sess.opts.optimize == config::OptLevel::Aggressive
        {
J
Jorge Aparicio 已提交
457
            self.linker_arg("-O1");
458 459 460
        }
    }

461
    fn pgo_gen(&mut self) {
462
        if !self.sess.target.linker_is_gnu {
M
Mark Rousskov 已提交
463 464
            return;
        }
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

        // If we're doing PGO generation stuff and on a GNU-like linker, use the
        // "-u" flag to properly pull in the profiler runtime bits.
        //
        // This is because LLVM otherwise won't add the needed initialization
        // for us on Linux (though the extra flag should be harmless if it
        // does).
        //
        // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
        //
        // Though it may be worth to try to revert those changes upstream, since
        // the overhead of the initialization should be minor.
        self.cmd.arg("-u");
        self.cmd.arg("__llvm_profile_runtime");
    }

481
    fn control_flow_guard(&mut self) {}
482

Y
YI 已提交
483 484 485 486
    fn debuginfo(&mut self, strip: Strip) {
        match strip {
            Strip::None => {}
            Strip::Debuginfo => {
487 488
                // MacOS linker does not support longhand argument --strip-debug
                self.linker_arg("-S");
489
            }
Y
YI 已提交
490
            Strip::Symbols => {
491 492
                // MacOS linker does not support longhand argument --strip-all
                self.linker_arg("-s");
Y
YI 已提交
493 494
            }
        }
495 496
    }

497 498 499 500 501 502
    fn no_crt_objects(&mut self) {
        if !self.is_ld {
            self.cmd.arg("-nostartfiles");
        }
    }

503
    fn no_default_libraries(&mut self) {
J
Jorge Aparicio 已提交
504 505 506
        if !self.is_ld {
            self.cmd.arg("-nodefaultlibs");
        }
507 508
    }

509
    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
510
        // Symbol visibility in object files typically takes care of this.
511
        if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
M
Mark Rousskov 已提交
512
        {
513 514 515
            return;
        }

J
John Kåre Alsaker 已提交
516 517 518
        // We manually create a list of exported symbols to ensure we don't expose any more.
        // The object files have far more public symbols than we actually want to export,
        // so we hide them all here.
519

520
        if !self.sess.target.limit_rdylib_exports {
521 522 523
            return;
        }

524
        if crate_type == CrateType::ProcMacro {
M
Mark Rousskov 已提交
525
            return;
526 527
        }

528
        let is_windows = self.sess.target.is_like_windows;
N
Nikita Baksalyar 已提交
529
        let mut arg = OsString::new();
530
        let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
N
Nikita Baksalyar 已提交
531

532 533
        debug!("EXPORTED SYMBOLS:");

534
        if self.sess.target.is_like_osx {
535
            // Write a plain, newline-separated list of symbols
T
Taiki Endo 已提交
536
            let res: io::Result<()> = try {
N
Nikita Baksalyar 已提交
537
                let mut f = BufWriter::new(File::create(&path)?);
538
                for sym in self.info.exports[&crate_type].iter() {
539
                    debug!("  _{}", sym);
540
                    writeln!(f, "_{}", sym)?;
N
Nikita Baksalyar 已提交
541
                }
T
Taiki Endo 已提交
542
            };
N
Nikita Baksalyar 已提交
543
            if let Err(e) = res {
544
                self.sess.fatal(&format!("failed to write lib.def file: {}", e));
545
            }
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
        } else if is_windows {
            let res: io::Result<()> = try {
                let mut f = BufWriter::new(File::create(&path)?);

                // .def file similar to MSVC one but without LIBRARY section
                // because LD doesn't like when it's empty
                writeln!(f, "EXPORTS")?;
                for symbol in self.info.exports[&crate_type].iter() {
                    debug!("  _{}", symbol);
                    writeln!(f, "  {}", symbol)?;
                }
            };
            if let Err(e) = res {
                self.sess.fatal(&format!("failed to write list.def file: {}", e));
            }
561
        } else {
562
            // Write an LD version script
T
Taiki Endo 已提交
563
            let res: io::Result<()> = try {
N
Nikita Baksalyar 已提交
564
                let mut f = BufWriter::new(File::create(&path)?);
565 566 567 568 569 570 571
                writeln!(f, "{{")?;
                if !self.info.exports[&crate_type].is_empty() {
                    writeln!(f, "  global:")?;
                    for sym in self.info.exports[&crate_type].iter() {
                        debug!("    {};", sym);
                        writeln!(f, "    {};", sym)?;
                    }
N
Nikita Baksalyar 已提交
572
                }
573
                writeln!(f, "\n  local:\n    *;\n}};")?;
T
Taiki Endo 已提交
574
            };
N
Nikita Baksalyar 已提交
575
            if let Err(e) = res {
576
                self.sess.fatal(&format!("failed to write version script: {}", e));
N
Nikita Baksalyar 已提交
577
            }
578
        }
N
Nikita Baksalyar 已提交
579

580
        if self.sess.target.is_like_osx {
J
Jorge Aparicio 已提交
581 582 583 584
            if !self.is_ld {
                arg.push("-Wl,")
            }
            arg.push("-exported_symbols_list,");
585
        } else if self.sess.target.is_like_solaris {
J
Jorge Aparicio 已提交
586 587 588 589
            if !self.is_ld {
                arg.push("-Wl,")
            }
            arg.push("-M,");
590
        } else {
J
Jorge Aparicio 已提交
591 592 593
            if !self.is_ld {
                arg.push("-Wl,")
            }
594 595 596 597
            // Both LD and LLD accept export list in *.def file form, there are no flags required
            if !is_windows {
                arg.push("--version-script=")
            }
598 599 600
        }

        arg.push(&path);
601
        self.cmd.arg(arg);
602
    }
603 604

    fn subsystem(&mut self, subsystem: &str) {
605 606
        self.linker_arg("--subsystem");
        self.linker_arg(&subsystem);
607
    }
608

609
    fn finalize(&mut self) {
610 611
        self.hint_dynamic(); // Reset to default before returning the composed command line.
    }
612 613

    fn group_start(&mut self) {
614
        if self.takes_hints() {
615 616 617 618 619
            self.linker_arg("--start-group");
        }
    }

    fn group_end(&mut self) {
620
        if self.takes_hints() {
621 622 623
            self.linker_arg("--end-group");
        }
    }
624

625 626 627
    fn linker_plugin_lto(&mut self) {
        match self.sess.opts.cg.linker_plugin_lto {
            LinkerPluginLto::Disabled => {
628 629
                // Nothing to do
            }
630 631
            LinkerPluginLto::LinkerPluginAuto => {
                self.push_linker_plugin_lto_args(None);
632
            }
633 634
            LinkerPluginLto::LinkerPlugin(ref path) => {
                self.push_linker_plugin_lto_args(Some(path.as_os_str()));
635 636 637
            }
        }
    }
638 639 640 641 642

    // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information.
    // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
    // so we just always add it.
    fn add_eh_frame_header(&mut self) {
643
        self.linker_arg("--eh-frame-hdr");
644
    }
645 646 647 648 649 650

    fn add_as_needed(&mut self) {
        if self.sess.target.linker_is_gnu {
            self.linker_arg("--as-needed");
        }
    }
651
}
652 653

pub struct MsvcLinker<'a> {
654
    cmd: Command,
655
    sess: &'a Session,
M
Mark Rousskov 已提交
656
    info: &'a LinkerInfo,
657 658 659
}

impl<'a> Linker for MsvcLinker<'a> {
660 661 662
    fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }
663 664 665 666 667 668 669 670 671 672 673 674 675

    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
        match output_kind {
            LinkOutputKind::DynamicNoPicExe
            | LinkOutputKind::DynamicPicExe
            | LinkOutputKind::StaticNoPicExe
            | LinkOutputKind::StaticPicExe => {}
            LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
                self.cmd.arg("/DLL");
                let mut arg: OsString = "/IMPLIB:".into();
                arg.push(out_filename.with_extension("dll.lib"));
                self.cmd.arg(arg);
            }
676 677 678
            LinkOutputKind::WasiReactorExe => {
                panic!("can't link as reactor on non-wasi target");
            }
679 680 681
        }
    }

M
Mark Rousskov 已提交
682 683 684 685 686 687
    fn link_rlib(&mut self, lib: &Path) {
        self.cmd.arg(lib);
    }
    fn add_object(&mut self, path: &Path) {
        self.cmd.arg(path);
    }
688

689
    fn gc_sections(&mut self, _keep_metadata: bool) {
690 691 692 693 694 695 696 697 698 699
        // MSVC's ICF (Identical COMDAT Folding) link optimization is
        // slow for Rust and thus we disable it by default when not in
        // optimization build.
        if self.sess.opts.optimize != config::OptLevel::No {
            self.cmd.arg("/OPT:REF,ICF");
        } else {
            // It is necessary to specify NOICF here, because /OPT:REF
            // implies ICF by default.
            self.cmd.arg("/OPT:REF,NOICF");
        }
700
    }
701

N
Nicholas Nethercote 已提交
702
    fn link_dylib(&mut self, lib: Symbol) {
703 704
        self.cmd.arg(&format!("{}.lib", lib));
    }
705

N
Nicholas Nethercote 已提交
706
    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
707 708 709 710
        // When producing a dll, the MSVC linker may not actually emit a
        // `foo.lib` file if the dll doesn't actually export any symbols, so we
        // check to see if the file is there and just omit linking to it if it's
        // not present.
711
        let name = format!("{}.dll.lib", lib);
712 713 714 715 716
        if fs::metadata(&path.join(&name)).is_ok() {
            self.cmd.arg(name);
        }
    }

N
Nicholas Nethercote 已提交
717
    fn link_staticlib(&mut self, lib: Symbol) {
718 719 720
        self.cmd.arg(&format!("{}.lib", lib));
    }

721 722 723 724
    fn full_relro(&mut self) {
        // noop
    }

725 726 727 728
    fn partial_relro(&mut self) {
        // noop
    }

729
    fn no_relro(&mut self) {
J
Johannes Löthberg 已提交
730 731 732
        // noop
    }

733 734 735 736
    fn no_crt_objects(&mut self) {
        // noop
    }

737
    fn no_default_libraries(&mut self) {
738
        self.cmd.arg("/NODEFAULTLIB");
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
    }

    fn include_path(&mut self, path: &Path) {
        let mut arg = OsString::from("/LIBPATH:");
        arg.push(path);
        self.cmd.arg(&arg);
    }

    fn output_filename(&mut self, path: &Path) {
        let mut arg = OsString::from("/OUT:");
        arg.push(path);
        self.cmd.arg(&arg);
    }

    fn framework_path(&mut self, _path: &Path) {
754
        bug!("frameworks are not supported on windows")
755
    }
N
Nicholas Nethercote 已提交
756
    fn link_framework(&mut self, _framework: Symbol) {
757
        bug!("frameworks are not supported on windows")
758 759
    }

N
Nicholas Nethercote 已提交
760
    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
761
        self.link_staticlib(lib);
762
        self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
763
    }
764 765
    fn link_whole_rlib(&mut self, path: &Path) {
        self.link_rlib(path);
766 767 768
        let mut arg = OsString::from("/WHOLEARCHIVE:");
        arg.push(path);
        self.cmd.arg(arg);
769
    }
770 771 772
    fn optimize(&mut self) {
        // Needs more investigation of `/OPT` arguments
    }
773

774 775 776 777
    fn pgo_gen(&mut self) {
        // Nothing needed here.
    }

778 779 780 781
    fn control_flow_guard(&mut self) {
        self.cmd.arg("/guard:cf");
    }

Y
YI 已提交
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    fn debuginfo(&mut self, strip: Strip) {
        match strip {
            Strip::None => {
                // This will cause the Microsoft linker to generate a PDB file
                // from the CodeView line tables in the object files.
                self.cmd.arg("/DEBUG");

                // This will cause the Microsoft linker to embed .natvis info into the PDB file
                let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
                if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
                    for entry in natvis_dir {
                        match entry {
                            Ok(entry) => {
                                let path = entry.path();
                                if path.extension() == Some("natvis".as_ref()) {
                                    let mut arg = OsString::from("/NATVIS:");
                                    arg.push(path);
                                    self.cmd.arg(arg);
                                }
                            }
                            Err(err) => {
                                self.sess
                                    .warn(&format!("error enumerating natvis directory: {}", err));
                            }
806
                        }
M
Mark Rousskov 已提交
807
                    }
808 809
                }
            }
Y
YI 已提交
810 811 812
            Strip::Debuginfo | Strip::Symbols => {
                self.cmd.arg("/DEBUG:NONE");
            }
813
        }
814 815
    }

816 817 818 819 820 821 822
    // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
    // export symbols from a dynamic library. When building a dynamic library,
    // however, we're going to want some symbols exported, so this function
    // generates a DEF file which lists all the symbols.
    //
    // The linker will read this `*.def` file and export all the symbols from
    // the dynamic library. Note that this is not as simple as just exporting
I
Irina Popa 已提交
823
    // all the symbols in the current crate (as specified by `codegen.reachable`)
824 825 826 827
    // but rather we also need to possibly export the symbols of upstream
    // crates. Upstream rlibs may be linked statically to this dynamic library,
    // in which case they may continue to transitively be used and hence need
    // their symbols exported.
M
Mark Rousskov 已提交
828
    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
829 830 831 832 833
        // Symbol visibility takes care of this typically
        if crate_type == CrateType::Executable {
            return;
        }

834
        let path = tmpdir.join("lib.def");
T
Taiki Endo 已提交
835
        let res: io::Result<()> = try {
J
Jorge Aparicio 已提交
836
            let mut f = BufWriter::new(File::create(&path)?);
837 838 839

            // Start off with the standard module name header and then go
            // straight to exports.
J
Jorge Aparicio 已提交
840 841
            writeln!(f, "LIBRARY")?;
            writeln!(f, "EXPORTS")?;
842
            for symbol in self.info.exports[&crate_type].iter() {
V
 
Vadim Chugunov 已提交
843
                debug!("  _{}", symbol);
844
                writeln!(f, "  {}", symbol)?;
845
            }
T
Taiki Endo 已提交
846
        };
847
        if let Err(e) = res {
848
            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
849 850 851 852 853
        }
        let mut arg = OsString::from("/DEF:");
        arg.push(path);
        self.cmd.arg(&arg);
    }
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877

    fn subsystem(&mut self, subsystem: &str) {
        // Note that previous passes of the compiler validated this subsystem,
        // so we just blindly pass it to the linker.
        self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));

        // Windows has two subsystems we're interested in right now, the console
        // and windows subsystems. These both implicitly have different entry
        // points (starting symbols). The console entry point starts with
        // `mainCRTStartup` and the windows entry point starts with
        // `WinMainCRTStartup`. These entry points, defined in system libraries,
        // will then later probe for either `main` or `WinMain`, respectively to
        // start the application.
        //
        // In Rust we just always generate a `main` function so we want control
        // to always start there, so we force the entry point on the windows
        // subsystem to be `mainCRTStartup` to get everything booted up
        // correctly.
        //
        // For more information see RFC #1665
        if subsystem == "windows" {
            self.cmd.arg("/ENTRY:mainCRTStartup");
        }
    }
878

879
    fn finalize(&mut self) {}
880 881 882 883

    // MSVC doesn't need group indicators
    fn group_start(&mut self) {}
    fn group_end(&mut self) {}
884

885
    fn linker_plugin_lto(&mut self) {
886 887
        // Do nothing
    }
888
}
889

890
pub struct EmLinker<'a> {
891
    cmd: Command,
892
    sess: &'a Session,
M
Mark Rousskov 已提交
893
    info: &'a LinkerInfo,
894 895 896
}

impl<'a> Linker for EmLinker<'a> {
897 898 899
    fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }
900 901 902

    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}

903 904 905 906
    fn include_path(&mut self, path: &Path) {
        self.cmd.arg("-L").arg(path);
    }

N
Nicholas Nethercote 已提交
907 908
    fn link_staticlib(&mut self, lib: Symbol) {
        self.cmd.arg("-l").sym_arg(lib);
909 910 911 912 913 914 915 916 917 918
    }

    fn output_filename(&mut self, path: &Path) {
        self.cmd.arg("-o").arg(path);
    }

    fn add_object(&mut self, path: &Path) {
        self.cmd.arg(path);
    }

N
Nicholas Nethercote 已提交
919
    fn link_dylib(&mut self, lib: Symbol) {
920 921 922 923
        // Emscripten always links statically
        self.link_staticlib(lib);
    }

N
Nicholas Nethercote 已提交
924
    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
925 926 927 928 929 930 931 932 933
        // not supported?
        self.link_staticlib(lib);
    }

    fn link_whole_rlib(&mut self, lib: &Path) {
        // not supported?
        self.link_rlib(lib);
    }

N
Nicholas Nethercote 已提交
934
    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
935 936 937 938 939 940 941
        self.link_dylib(lib);
    }

    fn link_rlib(&mut self, lib: &Path) {
        self.add_object(lib);
    }

942 943 944 945
    fn full_relro(&mut self) {
        // noop
    }

946 947 948 949
    fn partial_relro(&mut self) {
        // noop
    }

950
    fn no_relro(&mut self) {
J
Johannes Löthberg 已提交
951 952 953
        // noop
    }

954 955 956 957
    fn framework_path(&mut self, _path: &Path) {
        bug!("frameworks are not supported on Emscripten")
    }

N
Nicholas Nethercote 已提交
958
    fn link_framework(&mut self, _framework: Symbol) {
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
        bug!("frameworks are not supported on Emscripten")
    }

    fn gc_sections(&mut self, _keep_metadata: bool) {
        // noop
    }

    fn optimize(&mut self) {
        // Emscripten performs own optimizations
        self.cmd.arg(match self.sess.opts.optimize {
            OptLevel::No => "-O0",
            OptLevel::Less => "-O1",
            OptLevel::Default => "-O2",
            OptLevel::Aggressive => "-O3",
            OptLevel::Size => "-Os",
M
Mark Rousskov 已提交
974
            OptLevel::SizeMin => "-Oz",
975
        });
976 977
        // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
        self.cmd.args(&["--memory-init-file", "0"]);
978 979
    }

980 981 982 983
    fn pgo_gen(&mut self) {
        // noop, but maybe we need something like the gnu linker?
    }

984
    fn control_flow_guard(&mut self) {}
985

Y
YI 已提交
986
    fn debuginfo(&mut self, _strip: Strip) {
987 988
        // Preserve names or generate source maps depending on debug info
        self.cmd.arg(match self.sess.opts.debuginfo {
989 990
            DebugInfo::None => "-g0",
            DebugInfo::Limited => "-g3",
M
Mark Rousskov 已提交
991
            DebugInfo::Full => "-g4",
992 993 994
        });
    }

995 996
    fn no_crt_objects(&mut self) {}

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
    fn no_default_libraries(&mut self) {
        self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
    }

    fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
        let symbols = &self.info.exports[&crate_type];

        debug!("EXPORTED SYMBOLS:");

        self.cmd.arg("-s");

        let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
        let mut encoded = String::new();

        {
            let mut encoder = json::Encoder::new(&mut encoded);
            let res = encoder.emit_seq(symbols.len(), |encoder| {
                for (i, sym) in symbols.iter().enumerate() {
M
Mark Rousskov 已提交
1015
                    encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
                }
                Ok(())
            });
            if let Err(e) = res {
                self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
            }
        }
        debug!("{}", encoded);
        arg.push(encoded);

        self.cmd.arg(arg);
    }

    fn subsystem(&mut self, _subsystem: &str) {
        // noop
    }
1032

1033
    fn finalize(&mut self) {}
1034 1035 1036 1037

    // Appears not necessary on Emscripten
    fn group_start(&mut self) {}
    fn group_end(&mut self) {}
1038

1039
    fn linker_plugin_lto(&mut self) {
1040 1041
        // Do nothing
    }
1042 1043
}

1044
pub struct WasmLd<'a> {
1045
    cmd: Command,
1046
    sess: &'a Session,
1047
    info: &'a LinkerInfo,
1048 1049
}

1050
impl<'a> WasmLd<'a> {
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
        // If the atomics feature is enabled for wasm then we need a whole bunch
        // of flags:
        //
        // * `--shared-memory` - the link won't even succeed without this, flags
        //   the one linear memory as `shared`
        //
        // * `--max-memory=1G` - when specifying a shared memory this must also
        //   be specified. We conservatively choose 1GB but users should be able
        //   to override this with `-C link-arg`.
        //
        // * `--import-memory` - it doesn't make much sense for memory to be
        //   exported in a threaded module because typically you're
        //   sharing memory and instantiating the module multiple times. As a
        //   result if it were exported then we'd just have no sharing.
        //
        // * `--export=__wasm_init_memory` - when using `--passive-segments` the
        //   linker will synthesize this function, and so we need to make sure
        //   that our usage of `--export` below won't accidentally cause this
        //   function to get deleted.
1071 1072 1073
        //
        // * `--export=*tls*` - when `#[thread_local]` symbols are used these
        //   symbols are how the TLS segments are initialized and configured.
1074
        if sess.target_features.contains(&sym::atomics) {
1075 1076 1077 1078
            cmd.arg("--shared-memory");
            cmd.arg("--max-memory=1073741824");
            cmd.arg("--import-memory");
            cmd.arg("--export=__wasm_init_memory");
1079 1080 1081 1082
            cmd.arg("--export=__wasm_init_tls");
            cmd.arg("--export=__tls_size");
            cmd.arg("--export=__tls_align");
            cmd.arg("--export=__tls_base");
1083
        }
1084 1085 1086 1087
        WasmLd { cmd, sess, info }
    }
}

1088
impl<'a> Linker for WasmLd<'a> {
1089 1090 1091 1092
    fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

1093 1094 1095 1096 1097 1098 1099 1100 1101
    fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
        match output_kind {
            LinkOutputKind::DynamicNoPicExe
            | LinkOutputKind::DynamicPicExe
            | LinkOutputKind::StaticNoPicExe
            | LinkOutputKind::StaticPicExe => {}
            LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
                self.cmd.arg("--no-entry");
            }
1102 1103 1104 1105
            LinkOutputKind::WasiReactorExe => {
                self.cmd.arg("--entry");
                self.cmd.arg("_initialize");
            }
1106 1107 1108
        }
    }

N
Nicholas Nethercote 已提交
1109 1110
    fn link_dylib(&mut self, lib: Symbol) {
        self.cmd.arg("-l").sym_arg(lib);
1111 1112
    }

N
Nicholas Nethercote 已提交
1113 1114
    fn link_staticlib(&mut self, lib: Symbol) {
        self.cmd.arg("-l").sym_arg(lib);
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
    }

    fn link_rlib(&mut self, lib: &Path) {
        self.cmd.arg(lib);
    }

    fn include_path(&mut self, path: &Path) {
        self.cmd.arg("-L").arg(path);
    }

    fn framework_path(&mut self, _path: &Path) {
        panic!("frameworks not supported")
    }

    fn output_filename(&mut self, path: &Path) {
        self.cmd.arg("-o").arg(path);
    }

    fn add_object(&mut self, path: &Path) {
        self.cmd.arg(path);
    }

M
Mark Rousskov 已提交
1137
    fn full_relro(&mut self) {}
1138

M
Mark Rousskov 已提交
1139
    fn partial_relro(&mut self) {}
1140

M
Mark Rousskov 已提交
1141
    fn no_relro(&mut self) {}
1142

N
Nicholas Nethercote 已提交
1143 1144
    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
        self.cmd.arg("-l").sym_arg(lib);
1145 1146
    }

N
Nicholas Nethercote 已提交
1147
    fn link_framework(&mut self, _framework: Symbol) {
1148 1149 1150
        panic!("frameworks not supported")
    }

N
Nicholas Nethercote 已提交
1151 1152
    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
        self.cmd.arg("-l").sym_arg(lib);
1153 1154 1155 1156 1157 1158 1159
    }

    fn link_whole_rlib(&mut self, lib: &Path) {
        self.cmd.arg(lib);
    }

    fn gc_sections(&mut self, _keep_metadata: bool) {
1160
        self.cmd.arg("--gc-sections");
1161 1162 1163
    }

    fn optimize(&mut self) {
1164 1165 1166 1167 1168 1169 1170 1171
        self.cmd.arg(match self.sess.opts.optimize {
            OptLevel::No => "-O0",
            OptLevel::Less => "-O1",
            OptLevel::Default => "-O2",
            OptLevel::Aggressive => "-O3",
            // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
            // instead.
            OptLevel::Size => "-O2",
M
Mark Rousskov 已提交
1172
            OptLevel::SizeMin => "-O2",
1173
        });
1174 1175
    }

M
Mark Rousskov 已提交
1176
    fn pgo_gen(&mut self) {}
1177

Y
YI 已提交
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
    fn debuginfo(&mut self, strip: Strip) {
        match strip {
            Strip::None => {}
            Strip::Debuginfo => {
                self.cmd.arg("--strip-debug");
            }
            Strip::Symbols => {
                self.cmd.arg("--strip-all");
            }
        }
    }
1189

1190
    fn control_flow_guard(&mut self) {}
1191

1192 1193
    fn no_crt_objects(&mut self) {}

M
Mark Rousskov 已提交
1194
    fn no_default_libraries(&mut self) {}
1195

1196 1197 1198 1199
    fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
        for sym in self.info.exports[&crate_type].iter() {
            self.cmd.arg("--export").arg(&sym);
        }
1200

T
Tamir Duberstein 已提交
1201 1202 1203 1204
        // LLD will hide these otherwise-internal symbols since it only exports
        // symbols explicity passed via the `--export` flags above and hides all
        // others. Various bits and pieces of tooling use this, so be sure these
        // symbols make their way out of the linker as well.
1205 1206
        self.cmd.arg("--export=__heap_base");
        self.cmd.arg("--export=__data_end");
1207 1208
    }

M
Mark Rousskov 已提交
1209
    fn subsystem(&mut self, _subsystem: &str) {}
1210

1211
    fn finalize(&mut self) {}
1212 1213 1214 1215

    // Not needed for now with LLD
    fn group_start(&mut self) {}
    fn group_end(&mut self) {}
1216

1217
    fn linker_plugin_lto(&mut self) {
1218 1219
        // Do nothing for now
    }
1220
}
1221

1222
fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1223
    if let Some(ref exports) = tcx.sess.target.override_export_symbols {
M
Mark Rousskov 已提交
1224
        return exports.clone();
1225 1226
    }

1227 1228 1229 1230 1231
    let mut symbols = Vec::new();

    let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
    for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
        if level.is_below_threshold(export_threshold) {
1232 1233 1234 1235 1236
            symbols.push(symbol_export::symbol_name_for_instance_in_crate(
                tcx,
                symbol,
                LOCAL_CRATE,
            ));
1237 1238 1239
        }
    }

1240
    let formats = tcx.dependency_formats(LOCAL_CRATE);
1241
    let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
1242

1243
    for (index, dep_format) in deps.iter().enumerate() {
1244 1245 1246 1247 1248
        let cnum = CrateNum::new(index + 1);
        // For each dependency that we are linking to statically ...
        if *dep_format == Linkage::Static {
            // ... we add its symbol list to our export list.
            for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
1249 1250
                if !level.is_below_threshold(export_threshold) {
                    continue;
1251
                }
1252

1253
                symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
1254 1255 1256 1257 1258 1259
            }
        }
    }

    symbols
}
1260 1261 1262 1263 1264 1265 1266 1267 1268

/// Much simplified and explicit CLI for the NVPTX linker. The linker operates
/// with bitcode and uses LLVM backend to generate a PTX assembly.
pub struct PtxLinker<'a> {
    cmd: Command,
    sess: &'a Session,
}

impl<'a> Linker for PtxLinker<'a> {
1269 1270 1271 1272
    fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

1273 1274
    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}

1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
    fn link_rlib(&mut self, path: &Path) {
        self.cmd.arg("--rlib").arg(path);
    }

    fn link_whole_rlib(&mut self, path: &Path) {
        self.cmd.arg("--rlib").arg(path);
    }

    fn include_path(&mut self, path: &Path) {
        self.cmd.arg("-L").arg(path);
    }

Y
YI 已提交
1287
    fn debuginfo(&mut self, _strip: Strip) {
1288 1289 1290 1291 1292 1293 1294 1295
        self.cmd.arg("--debug");
    }

    fn add_object(&mut self, path: &Path) {
        self.cmd.arg("--bitcode").arg(path);
    }

    fn optimize(&mut self) {
1296 1297 1298
        match self.sess.lto() {
            Lto::Thin | Lto::Fat | Lto::ThinLocal => {
                self.cmd.arg("-Olto");
M
Mark Rousskov 已提交
1299
            }
1300

M
Mark Rousskov 已提交
1301
            Lto::No => {}
1302
        };
1303 1304 1305 1306 1307 1308
    }

    fn output_filename(&mut self, path: &Path) {
        self.cmd.arg("-o").arg(path);
    }

1309
    fn finalize(&mut self) {
1310 1311 1312
        // Provide the linker with fallback to internal `target-cpu`.
        self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
            Some(ref s) => s,
1313
            None => &self.sess.target.cpu,
1314
        });
1315 1316
    }

N
Nicholas Nethercote 已提交
1317
    fn link_dylib(&mut self, _lib: Symbol) {
1318 1319 1320
        panic!("external dylibs not supported")
    }

N
Nicholas Nethercote 已提交
1321
    fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
1322 1323 1324
        panic!("external dylibs not supported")
    }

N
Nicholas Nethercote 已提交
1325
    fn link_staticlib(&mut self, _lib: Symbol) {
1326 1327 1328
        panic!("staticlibs not supported")
    }

N
Nicholas Nethercote 已提交
1329
    fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
1330 1331 1332 1333 1334 1335 1336
        panic!("staticlibs not supported")
    }

    fn framework_path(&mut self, _path: &Path) {
        panic!("frameworks not supported")
    }

N
Nicholas Nethercote 已提交
1337
    fn link_framework(&mut self, _framework: Symbol) {
1338 1339 1340
        panic!("frameworks not supported")
    }

M
Mark Rousskov 已提交
1341
    fn full_relro(&mut self) {}
1342

M
Mark Rousskov 已提交
1343
    fn partial_relro(&mut self) {}
1344

M
Mark Rousskov 已提交
1345
    fn no_relro(&mut self) {}
1346

M
Mark Rousskov 已提交
1347
    fn gc_sections(&mut self, _keep_metadata: bool) {}
1348

M
Mark Rousskov 已提交
1349
    fn pgo_gen(&mut self) {}
1350

1351 1352
    fn no_crt_objects(&mut self) {}

M
Mark Rousskov 已提交
1353
    fn no_default_libraries(&mut self) {}
1354

1355
    fn control_flow_guard(&mut self) {}
1356

M
Mark Rousskov 已提交
1357
    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
1358

M
Mark Rousskov 已提交
1359
    fn subsystem(&mut self, _subsystem: &str) {}
1360

M
Mark Rousskov 已提交
1361
    fn group_start(&mut self) {}
1362

M
Mark Rousskov 已提交
1363
    fn group_end(&mut self) {}
1364

M
Mark Rousskov 已提交
1365
    fn linker_plugin_lto(&mut self) {}
1366
}