Auto merge of #141750 - Noratrieb:gold-rush, r=bjorn3

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 rust-lang/rust#141748

r? bjorn3
This commit is contained in:
bors
2025-06-02 23:56:54 +00:00

View File

@@ -3,7 +3,7 @@ mod raw_dylib;
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs::{File, OpenOptions, read};
use std::io::{BufWriter, Write};
use std::io::{BufReader, BufWriter, Write};
use std::ops::{ControlFlow, Deref};
use std::path::{Path, PathBuf};
use std::process::{Output, Stdio};
@@ -184,6 +184,12 @@ pub fn link_binary(
);
}
if sess.target.binary_format == BinaryFormat::Elf {
if let Err(err) = warn_if_linked_with_gold(sess, &out_filename) {
info!(?err, "Error while checking if gold was the linker");
}
}
if output.is_stdout() {
if output.is_tty() {
sess.dcx().emit_err(errors::BinaryOutputToTty {
@@ -3375,3 +3381,54 @@ fn add_lld_args(
}
}
}
// gold has been deprecated with binutils 2.44
// and is known to behave incorrectly around Rust programs.
// There have been reports of being unable to bootstrap with gold:
// https://github.com/rust-lang/rust/issues/139425
// Additionally, gold miscompiles SHF_GNU_RETAIN sections, which are
// emitted with `#[used(linker)]`.
fn warn_if_linked_with_gold(sess: &Session, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
use object::read::elf::{FileHeader, SectionHeader};
use object::read::{ReadCache, ReadRef, Result};
use object::{Endianness, elf};
fn elf_has_gold_version_note<'a>(
elf: &impl FileHeader,
data: impl ReadRef<'a>,
) -> Result<bool> {
let endian = elf.endian()?;
let section =
elf.sections(endian, data)?.section_by_name(endian, b".note.gnu.gold-version");
if let Some((_, section)) = section {
if let Some(mut notes) = section.notes(endian, data)? {
return Ok(notes.any(|note| {
note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
}));
}
}
Ok(false)
}
let data = ReadCache::new(BufReader::new(File::open(path)?));
let was_linked_with_gold = if sess.target.pointer_width == 64 {
let elf = elf::FileHeader64::<Endianness>::parse(&data)?;
elf_has_gold_version_note(elf, &data)?
} else if sess.target.pointer_width == 32 {
let elf = elf::FileHeader32::<Endianness>::parse(&data)?;
elf_has_gold_version_note(elf, &data)?
} else {
return Ok(());
};
if was_linked_with_gold {
let mut warn =
sess.dcx().struct_warn("the gold linker is deprecated and has known bugs with Rust");
warn.help("consider using LLD or ld from GNU binutils instead");
warn.emit();
}
Ok(())
}