Skip to content

Rollup of 8 pull requests #144325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4563,7 +4563,10 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"serde",
"serde_derive",
"serde_json",
"serde_path_to_error",
"tracing",
]

Expand Down Expand Up @@ -4955,6 +4958,16 @@ dependencies = [
"serde",
]

[[package]]
name = "serde_path_to_error"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
dependencies = [
"itoa",
"serde",
]

[[package]]
name = "serde_spanned"
version = "0.6.9"
Expand Down
97 changes: 78 additions & 19 deletions compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};

use rustc_abi::Endian;
use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_hashes::Hash128;
use rustc_session::Session;
Expand Down Expand Up @@ -230,40 +230,66 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
Endian::Little => object::Endianness::Little,
Endian::Big => object::Endianness::Big,
};

let mut stub = write::Writer::new(endianness, true, &mut stub_buf);

let mut vers = Vec::new();
let mut vers_map = FxHashMap::default();
let mut syms = Vec::new();

for symbol in symbols {
let symbol_name = symbol.name.as_str();
if let Some((name, version_name)) = symbol_name.split_once('@') {
assert!(!version_name.contains('@'));
let dynstr = stub.add_dynamic_string(name.as_bytes());
let ver = if let Some(&ver_id) = vers_map.get(version_name) {
ver_id
} else {
let id = vers.len();
vers_map.insert(version_name, id);
let dynstr = stub.add_dynamic_string(version_name.as_bytes());
vers.push((version_name, dynstr));
id
};
syms.push((name, dynstr, Some(ver)));
} else {
let dynstr = stub.add_dynamic_string(symbol_name.as_bytes());
syms.push((symbol_name, dynstr, None));
}
}

let soname = stub.add_dynamic_string(soname.as_bytes());

// These initial reservations don't reserve any bytes in the binary yet,
// they just allocate in the internal data structures.

// First, we crate the dynamic symbol table. It starts with a null symbol
// First, we create the dynamic symbol table. It starts with a null symbol
// and then all the symbols and their dynamic strings.
stub.reserve_null_dynamic_symbol_index();

let dynstrs = symbols
.iter()
.map(|sym| {
stub.reserve_dynamic_symbol_index();
(sym, stub.add_dynamic_string(sym.name.as_str().as_bytes()))
})
.collect::<Vec<_>>();

let soname = stub.add_dynamic_string(soname.as_bytes());
for _ in syms.iter() {
stub.reserve_dynamic_symbol_index();
}

// Reserve the sections.
// We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to.
stub.reserve_shstrtab_section_index();
let text_section_name = stub.add_section_name(".text".as_bytes());
let text_section = stub.reserve_section_index();
stub.reserve_dynstr_section_index();
stub.reserve_dynsym_section_index();
stub.reserve_dynstr_section_index();
stub.reserve_gnu_versym_section_index();
stub.reserve_gnu_verdef_section_index();
stub.reserve_dynamic_section_index();

// These reservations now determine the actual layout order of the object file.
stub.reserve_file_header();
stub.reserve_shstrtab();
stub.reserve_section_headers();
stub.reserve_dynstr();
stub.reserve_dynsym();
stub.reserve_dynstr();
stub.reserve_gnu_versym();
stub.reserve_gnu_verdef(1 + vers.len(), 1 + vers.len());
stub.reserve_dynamic(2); // DT_SONAME, DT_NULL

// First write the ELF header with the arch information.
Expand Down Expand Up @@ -342,18 +368,17 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
sh_addralign: 1,
sh_entsize: 0,
});
stub.write_dynstr_section_header(0);
stub.write_dynsym_section_header(0, 1);
stub.write_dynstr_section_header(0);
stub.write_gnu_versym_section_header(0);
stub.write_gnu_verdef_section_header(0);
stub.write_dynamic_section_header(0);

// .dynstr
stub.write_dynstr();

// .dynsym
stub.write_null_dynamic_symbol();
for (_, name) in dynstrs {
for (_name, dynstr, _ver) in syms.iter().copied() {
stub.write_dynamic_symbol(&write::Sym {
name: Some(name),
name: Some(dynstr),
st_info: (elf::STB_GLOBAL << 4) | elf::STT_NOTYPE,
st_other: elf::STV_DEFAULT,
section: Some(text_section),
Expand All @@ -363,10 +388,44 @@ fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]
});
}

// .dynstr
stub.write_dynstr();

// .gnu_version
stub.write_null_gnu_versym();
for (_name, _dynstr, ver) in syms.iter().copied() {
stub.write_gnu_versym(if let Some(ver) = ver {
assert!((2 + ver as u16) < elf::VERSYM_HIDDEN);
elf::VERSYM_HIDDEN | (2 + ver as u16)
} else {
1
});
}

// .gnu_version_d
stub.write_align_gnu_verdef();
stub.write_gnu_verdef(&write::Verdef {
version: elf::VER_DEF_CURRENT,
flags: elf::VER_FLG_BASE,
index: 1,
aux_count: 1,
name: soname,
});
for (ver, (_name, dynstr)) in vers.into_iter().enumerate() {
stub.write_gnu_verdef(&write::Verdef {
version: elf::VER_DEF_CURRENT,
flags: 0,
index: 2 + ver as u16,
aux_count: 1,
name: dynstr,
});
}

// .dynamic
// the DT_SONAME will be used by the linker to populate DT_NEEDED
// which the loader uses to find the library.
// DT_NULL terminates the .dynamic table.
stub.write_align_dynamic();
stub.write_dynamic_string(elf::DT_SONAME, soname);
stub.write_dynamic(elf::DT_NULL, 0);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ptr: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (Ty<'tcx>, u64)> {
let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?;
let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else {
let Some(GlobalAlloc::TypeId { ty }) = self.tcx.try_get_global_alloc(alloc_id) else {
throw_ub_format!("invalid `TypeId` value: not all bytes carry type id metadata")
};
interp_ok((ty, offset.bytes()))
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_metadata/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,6 @@ metadata_wasm_import_form =

metadata_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind

metadata_raw_dylib_malformed =
link name must be well-formed if link kind is `raw-dylib`
7 changes: 7 additions & 0 deletions compiler/rustc_metadata/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,3 +815,10 @@ pub struct AsyncDropTypesInDependency {
pub extern_crate: Symbol,
pub local_crate: Symbol,
}

#[derive(Diagnostic)]
#[diag(metadata_raw_dylib_malformed)]
pub struct RawDylibMalformed {
#[primary_span]
pub span: Span,
}
15 changes: 14 additions & 1 deletion compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,8 +700,21 @@ impl<'tcx> Collector<'tcx> {
.link_ordinal
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));

let name = codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item));

if self.tcx.sess.target.binary_format == BinaryFormat::Elf {
let name = name.as_str();
if name.contains('\0') {
self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
} else if let Some((left, right)) = name.split_once('@')
&& (left.is_empty() || right.is_empty() || right.contains('@'))
{
self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
}
}

DllImport {
name: codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item)),
name,
import_name_type,
calling_convention,
span,
Expand Down
6 changes: 2 additions & 4 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,8 @@ impl<'tcx> MonoItem<'tcx> {
};

// Similarly, the executable entrypoint must be instantiated exactly once.
if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
if instance.def_id() == entry_def_id {
return InstantiationMode::GloballyShared { may_conflict: false };
}
if tcx.is_entrypoint(instance.def_id()) {
return InstantiationMode::GloballyShared { may_conflict: false };
}

// If the function is #[naked] or contains any other attribute that requires exactly-once
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3410,6 +3410,20 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
}

/// Whether this def is one of the special bin crate entrypoint functions that must have a
/// monomorphization and also not be internalized in the bin crate.
pub fn is_entrypoint(self, def_id: DefId) -> bool {
if self.is_lang_item(def_id, LangItem::Start) {
return true;
}
if let Some((entry_def_id, _)) = self.entry_fn(())
&& entry_def_id == def_id
{
return true;
}
false
}
}

/// Parameter attributes that can only be determined by examining the body of a function instead
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,15 @@ impl<'v> RootCollector<'_, 'v> {
return;
};

let main_instance = Instance::mono(self.tcx, main_def_id);
if self.tcx.should_codegen_locally(main_instance) {
self.output.push(create_fn_mono_item(
self.tcx,
main_instance,
self.tcx.def_span(main_def_id),
));
}

let Some(start_def_id) = self.tcx.lang_items().start_fn() else {
self.tcx.dcx().emit_fatal(errors::StartNotFound);
};
Expand Down
15 changes: 5 additions & 10 deletions compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,7 @@ where
// So even if its mode is LocalCopy, we need to treat it like a root.
match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => {
if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
continue;
}
}
InstantiationMode::LocalCopy => continue,
}

let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
Expand Down Expand Up @@ -821,10 +817,9 @@ fn mono_item_visibility<'tcx>(
| InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden,
};

// The `start_fn` lang item is actually a monomorphized instance of a
// function in the standard library, used for the `main` function. We don't
// want to export it so we tag it with `Hidden` visibility but this symbol
// is only referenced from the actual `main` symbol which we unfortunately
// Both the `start_fn` lang item and `main` itself should not be exported,
// so we give them with `Hidden` visibility but these symbols are
// only referenced from the actual `main` symbol which we unfortunately
// don't know anything about during partitioning/collection. As a result we
// forcibly keep this symbol out of the `internalization_candidates` set.
//
Expand All @@ -834,7 +829,7 @@ fn mono_item_visibility<'tcx>(
// from the `main` symbol we'll generate later.
//
// This may be fixable with a new `InstanceKind` perhaps? Unsure!
if tcx.is_lang_item(def_id, LangItem::Start) {
if tcx.is_entrypoint(def_id) {
*can_be_internalized = false;
return Visibility::Hidden;
}
Expand Down
Loading