Skip to content

Commit a1b2ee8

Browse files
committed
Auto merge of #141750 - Noratrieb:gold-rush, r=<try>
Warn when gold was used as the linker gold has been deprecated recently and is known to behave incorrectly around Rust programs, including miscompiling `#[used(linker)]`. Tell people to switch to a different linker instead. closes #141748 opening mostly for perf for now, but feel free to review r? bjorn3
2 parents 13718eb + 7c8e56f commit a1b2ee8

File tree

1 file changed

+62
-0
lines changed
  • compiler/rustc_codegen_ssa/src/back

1 file changed

+62
-0
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ pub fn link_binary(
184184
);
185185
}
186186

187+
if sess.target.binary_format == BinaryFormat::Elf {
188+
if let Err(err) = warn_if_linked_with_gold(sess, &out_filename) {
189+
info!(?err, "Error while checking if gold was the linker");
190+
}
191+
}
192+
187193
if output.is_stdout() {
188194
if output.is_tty() {
189195
sess.dcx().emit_err(errors::BinaryOutputToTty {
@@ -3425,3 +3431,59 @@ fn add_lld_args(
34253431
}
34263432
}
34273433
}
3434+
3435+
// gold has been deprecated with binutils 2.44
3436+
// and is known to behave incorrectly around Rust programs.
3437+
// There have been reports of being unable to bootstrap with gold:
3438+
// https://github.com/rust-lang/rust/issues/139425
3439+
// Additionally, gold miscompiles SHF_GNU_RETAIN sections, which are
3440+
// emitted with `#[used(linker)]`.
3441+
fn warn_if_linked_with_gold(sess: &Session, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
3442+
use object::elf;
3443+
use object::read::elf::FileHeader;
3444+
3445+
let data = std::fs::read(path)?;
3446+
3447+
let was_linked_with_gold = if sess.target.pointer_width == 64 {
3448+
let elf = elf::FileHeader64::<object::Endianness>::parse(&*data)?;
3449+
elf_has_gold_version_note(elf, &data)
3450+
} else if sess.target.pointer_width == 32 {
3451+
let elf = elf::FileHeader32::<object::Endianness>::parse(&*data)?;
3452+
elf_has_gold_version_note(elf, &data)
3453+
} else {
3454+
return Ok(());
3455+
};
3456+
3457+
match was_linked_with_gold {
3458+
Ok(true) => {
3459+
let mut warn = sess
3460+
.dcx()
3461+
.struct_warn("the gold linker is deprecated and has known bugs with Rust");
3462+
warn.help("consider using LLD or ld from GNU binutils instead");
3463+
warn.emit();
3464+
}
3465+
Ok(false) => {}
3466+
Err(err) => info!(?err, "Error while trying to detect whether binary was linked with gold"),
3467+
}
3468+
Ok(())
3469+
}
3470+
3471+
fn elf_has_gold_version_note(
3472+
elf: &impl object::read::elf::FileHeader,
3473+
data: &[u8],
3474+
) -> Result<bool, Box<dyn std::error::Error>> {
3475+
use object::read::elf::SectionHeader;
3476+
3477+
let endian = elf.endian()?;
3478+
3479+
let section = elf.sections(endian, data)?.section_by_name(endian, b".note.gnu.gold-version");
3480+
if let Some((_, section)) = section {
3481+
if let Some(mut notes) = section.notes(endian, data)? {
3482+
return Ok(notes.any(|note| {
3483+
note.is_ok_and(|note| note.n_type(endian) == object::elf::NT_GNU_GOLD_VERSION)
3484+
}));
3485+
}
3486+
}
3487+
3488+
Ok(false)
3489+
}

0 commit comments

Comments
 (0)