diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a8d917f0fdb58..80499f9ac6360 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -9,6 +9,7 @@ use std::{env, fmt, fs, io, mem, str}; use cc::windows_registry; use itertools::Itertools; +use object::read::archive::ArchiveFile; use regex::Regex; use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; @@ -78,6 +79,7 @@ pub fn link_binary( let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new(); + let mut tempfiles_for_linked_objects: Vec<PathBuf> = Vec::new(); for &crate_type in &codegen_results.crate_info.crate_types { // Ignore executable crates if we have -Z no-codegen, as they will error. if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen()) @@ -142,6 +144,8 @@ pub fn link_binary( &out_filename, &codegen_results, path.as_ref(), + &mut tempfiles_for_linked_objects, + outputs, ); } } @@ -214,6 +218,10 @@ pub fn link_binary( ensure_removed(sess.dcx(), &temp); } + for temp in tempfiles_for_linked_objects { + ensure_removed(sess.dcx(), &temp); + } + // If no requested outputs require linking, then the object temporaries should // be kept. if !sess.opts.output_types.should_link() { @@ -771,6 +779,8 @@ fn link_natively( out_filename: &Path, codegen_results: &CodegenResults, tmpdir: &Path, + tempfiles_for_linked_objects: &mut Vec<PathBuf>, + outputs: &OutputFilenames, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); @@ -795,6 +805,8 @@ fn link_natively( temp_filename, codegen_results, self_contained_components, + tempfiles_for_linked_objects, + outputs, ); linker::disable_localization(&mut cmd); @@ -2254,6 +2266,8 @@ fn linker_with_args( out_filename: &Path, codegen_results: &CodegenResults, self_contained_components: LinkSelfContainedComponents, + tempfiles_for_linked_objects: &mut Vec<PathBuf>, + outputs: &OutputFilenames, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( @@ -2329,6 +2343,13 @@ fn linker_with_args( add_local_crate_regular_objects(cmd, codegen_results); add_local_crate_metadata_objects(cmd, crate_type, codegen_results); add_local_crate_allocator_objects(cmd, codegen_results); + add_local_crate_linked_objects( + cmd, + codegen_results, + crate_type, + tempfiles_for_linked_objects, + outputs, + ); // Avoid linking to dynamic libraries unless they satisfy some undefined symbols // at the point at which they are specified on the command line. @@ -2925,6 +2946,35 @@ fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf { } } +fn add_local_crate_linked_objects( + cmd: &mut dyn Linker, + codegen_results: &CodegenResults, + crate_type: CrateType, + tempfiles_for_linked_objects: &mut Vec<PathBuf>, + outputs: &OutputFilenames, +) { + for (cnum, objects) in &codegen_results.crate_info.linked_objects[&crate_type] { + let src = &codegen_results.crate_info.used_crate_source[cnum]; + let cratepath = &src.rlib.as_ref().unwrap().0; + let archive_map = unsafe { Mmap::map(File::open(cratepath).unwrap()).unwrap() }; + let archive = ArchiveFile::parse(&*archive_map) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err)) + .unwrap(); + for member in archive.members() { + let member = member.unwrap(); + let name = std::str::from_utf8(member.name()).unwrap(); + if objects.contains(name) { + let data = member.data(&*archive_map).unwrap(); + let obj = + outputs.temp_path(OutputType::Object, Some(&format!("{name}.linked_object"))); + fs::write(&obj, data).unwrap(); + cmd.add_object(&obj); + tempfiles_for_linked_objects.push(obj); + } + } + } +} + // Adds the static "rlib" versions of all crates to the command line. // There's a bit of magic which happens here specifically related to LTO, // namely that we remove upstream object files. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8900405c1b8f8..72aedf212dbd4 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -5,14 +5,16 @@ use std::path::{Path, PathBuf}; use std::{env, io, iter, mem, str}; use cc::windows_registry; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::{ find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, }; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; -use rustc_middle::middle::exported_symbols; -use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}; +use rustc_middle::middle::exported_symbols::{ + self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, +}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; @@ -21,6 +23,7 @@ use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; use super::command::Command; +use super::link::are_upstream_rust_objects_already_included; use super::symbol_export; use crate::errors; @@ -1753,7 +1756,7 @@ impl<'a> Linker for AixLinker<'a> { fn for_each_exported_symbols_include_dep<'tcx>( tcx: TyCtxt<'tcx>, crate_type: CrateType, - mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), + mut callback: impl FnMut(&'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)], CrateNum), ) { let formats = tcx.dependency_formats(()); let deps = &formats[&crate_type]; @@ -1761,9 +1764,7 @@ fn for_each_exported_symbols_include_dep<'tcx>( for (cnum, dep_format) in deps.iter_enumerated() { // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { - for &(symbol, info) in tcx.exported_symbols(cnum).iter() { - callback(symbol, info, cnum); - } + callback(tcx.exported_symbols(cnum), cnum); } } } @@ -1783,12 +1784,14 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) { - symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( - tcx, symbol, cnum, - )); - symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); + for_each_exported_symbols_include_dep(tcx, crate_type, |exported_symbols, cnum| { + for &(symbol, info) in exported_symbols { + if info.level.is_below_threshold(export_threshold) { + symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate( + tcx, symbol, cnum, + )); + symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); + } } }); @@ -1808,30 +1811,84 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> { vec![proc_macro_decls_name, metadata_symbol_name] } -pub(crate) fn linked_symbols( +pub(crate) fn linked_objects( tcx: TyCtxt<'_>, crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { + linked_symbols: &mut Vec<(String, SymbolExportKind)>, +) -> FxIndexMap<CrateNum, FxHashSet<String>> { match crate_type { CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (), CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { - return Vec::new(); + return FxIndexMap::default(); } } - let mut symbols = Vec::new(); - + let mut objects = FxIndexMap::default(); + let upstream_rust_objects_already_included = + are_upstream_rust_objects_already_included(tcx.sess); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); - for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { - if info.level.is_below_threshold(export_threshold) || info.used { - symbols.push(( - symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), - info.kind, - )); + for_each_exported_symbols_include_dep(tcx, crate_type, |exported_symbols, cnum| { + let exported_symbols = exported_symbols.iter().filter(|(_, info)| { + (!matches!(crate_type, CrateType::Executable) + && info.level.is_below_threshold(export_threshold)) + || info.used + }); + if cnum == LOCAL_CRATE { + // Since the local crate is always linked directly to object files, `#[used]` works as expected, + // we only need add undefined symbols. + linked_symbols.extend( + exported_symbols + .filter(|(symbol, _)| match symbol { + ExportedSymbol::NonGeneric { cgu, .. } => cgu.is_none(), + ExportedSymbol::Generic(..) + | ExportedSymbol::DropGlue(..) + | ExportedSymbol::AsyncDropGlueCtorShim(..) => false, + ExportedSymbol::ThreadLocalShim(_def_id) => false, + ExportedSymbol::NoDefId(..) => true, + }) + .map(|&(symbol, info)| { + ( + symbol_export::linking_symbol_name_for_instance_in_crate( + tcx, symbol, cnum, + ), + info.kind, + ) + }), + ); + return; + } + if matches!(crate_type, CrateType::Executable) && tcx.is_compiler_builtins(cnum) { + return; } + let lto = upstream_rust_objects_already_included; + let mut cgus = FxHashSet::default(); + for &(symbol, info) in exported_symbols { + match symbol { + ExportedSymbol::NonGeneric { cgu: Some(cgu), .. } => { + if !lto { + cgus.insert(cgu.as_str().to_string()); + } + } + ExportedSymbol::NonGeneric { cgu: None, .. } | ExportedSymbol::NoDefId(..) => { + // Unresolved symbols may come from external libraries. + linked_symbols.push(( + symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), + info.kind, + )); + } + ExportedSymbol::Generic(..) + | ExportedSymbol::DropGlue(..) + | ExportedSymbol::AsyncDropGlueCtorShim(..) + | ExportedSymbol::ThreadLocalShim(..) => {} + }; + } + if cgus.is_empty() { + return; + } + objects.insert(cnum, cgus); }); - symbols + objects } /// Much simplified and explicit CLI for the NVPTX linker. The linker operates diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 459f4329d6e92..78c4819db7bd5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -9,10 +9,12 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, metadata_symbol_name, }; +use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, Ty, TyCtxt}; use rustc_middle::util::Providers; -use rustc_session::config::{CrateType, OomStrategy}; +use rustc_session::config::{CrateType, OomStrategy, OutputFilenames, OutputType}; +use rustc_span::Symbol; use rustc_target::callconv::Conv; use rustc_target::spec::{SanitizerSet, TlsModel}; use tracing::debug; @@ -168,6 +170,36 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } +fn find_codegen_unit<'tcx>( + tcx: TyCtxt<'tcx>, + codegen_units: &'tcx [CodegenUnit<'tcx>], + outputs: &'tcx OutputFilenames, + def_id: DefId, +) -> Option<Symbol> { + if !tcx.is_codegened_item(def_id) { + return None; + } + let item = if tcx.is_static(def_id) { + MonoItem::Static(def_id) + } else { + MonoItem::Fn(Instance::mono(tcx, def_id)) + }; + codegen_units.iter().find_map(|cgu| { + if cgu.contains_item(&item) { + Some(Symbol::intern( + outputs + .temp_path(OutputType::Object, Some(cgu.name().as_str())) + .file_name() + .unwrap() + .to_str() + .unwrap(), + )) + } else { + None + } + }) +} + fn exported_symbols_provider_local( tcx: TyCtxt<'_>, _: LocalCrate, @@ -182,8 +214,20 @@ fn exported_symbols_provider_local( tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true) }); - let mut symbols: Vec<_> = - sorted.iter().map(|&(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); + let outputs = tcx.output_filenames(()); + let codegen_units = tcx.collect_and_partition_mono_items(()).codegen_units; + let mut symbols: Vec<_> = sorted + .iter() + .map(|&(&def_id, &info)| { + ( + ExportedSymbol::NonGeneric { + def_id, + cgu: find_codegen_unit(tcx, codegen_units, outputs, def_id), + }, + info, + ) + }) + .collect(); // Export TLS shims if !tcx.sess.target.dll_tls_export { @@ -433,7 +477,7 @@ fn upstream_monomorphizations_provider( continue; } } - ExportedSymbol::NonGeneric(..) + ExportedSymbol::NonGeneric { .. } | ExportedSymbol::ThreadLocalShim(..) | ExportedSymbol::NoDefId(..) => { // These are no monomorphizations @@ -545,7 +589,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( // This is something instantiated in an upstream crate, so we have to use // the slower (because uncached) version of computing the symbol name. match symbol { - ExportedSymbol::NonGeneric(def_id) => { + ExportedSymbol::NonGeneric { def_id, .. } => { rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, Instance::mono(tcx, def_id), @@ -590,12 +634,12 @@ fn calling_convention_for_symbol<'tcx>( symbol: ExportedSymbol<'tcx>, ) -> (Conv, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) { let instance = match symbol { - ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) + ExportedSymbol::NonGeneric { def_id, .. } | ExportedSymbol::Generic(def_id, _) if tcx.is_static(def_id) => { None } - ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), + ExportedSymbol::NonGeneric { def_id, .. } => Some(Instance::mono(tcx, def_id)), ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)), // DropGlue always use the Rust calling convention and thus follow the target's default // symbol decoration scheme. @@ -711,7 +755,7 @@ fn maybe_emutls_symbol_name<'tcx>( undecorated: &str, ) -> Option<String> { if matches!(tcx.sess.tls_model(), TlsModel::Emulated) - && let ExportedSymbol::NonGeneric(def_id) = symbol + && let ExportedSymbol::NonGeneric { def_id, .. } = symbol && tcx.is_thread_local_static(def_id) { // When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 40238f4b4915a..2c35cbf828a7d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,7 +6,7 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_map; use rustc_data_structures::unord::UnordMap; @@ -872,8 +872,21 @@ impl CrateInfo { .iter() .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c))) .collect(); - let linked_symbols = - crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect(); + let mut linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>> = + crate_types.iter().map(|&c| (c, Vec::new())).collect(); + let linked_objects = crate_types + .iter() + .map(|&c| { + ( + c, + crate::back::linker::linked_objects( + tcx, + c, + linked_symbols.get_mut(&c).unwrap(), + ), + ) + }) + .collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let subsystem = @@ -919,6 +932,7 @@ impl CrateInfo { crate_types, exported_symbols, linked_symbols, + linked_objects, local_crate_name, compiler_builtins, profiler_runtime: None, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9d2ac219d592c..916215cf304e2 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -194,6 +194,7 @@ pub struct CrateInfo { pub crate_types: Vec<CrateType>, pub exported_symbols: UnordMap<CrateType, Vec<String>>, pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>, + pub linked_objects: FxIndexMap<CrateType, FxIndexMap<CrateNum, FxHashSet<String>>>, pub local_crate_name: Symbol, pub compiler_builtins: Option<CrateNum>, pub profiler_runtime: Option<CrateNum>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 776b081a4630f..c207dfc5cb246 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -367,7 +367,7 @@ provide! { tcx, def_id, other, cdata, .exported_symbols(cdata.cnum) .iter() .filter_map(|&(exported_symbol, export_info)| { - if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { + if let ExportedSymbol::NonGeneric { def_id, .. } = exported_symbol { Some((def_id, export_info)) } else { None diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 0bfbd39879747..ebf09ac6eeaa0 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -1,5 +1,6 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; +use rustc_span::Symbol; use crate::ty::{self, GenericArgsRef, Ty, TyCtxt}; @@ -40,7 +41,7 @@ pub struct SymbolExportInfo { #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub enum ExportedSymbol<'tcx> { - NonGeneric(DefId), + NonGeneric { def_id: DefId, cgu: Option<Symbol> }, Generic(DefId, GenericArgsRef<'tcx>), DropGlue(Ty<'tcx>), AsyncDropGlueCtorShim(Ty<'tcx>), @@ -53,7 +54,9 @@ impl<'tcx> ExportedSymbol<'tcx> { /// local crate. pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName<'tcx> { match *self { - ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)), + ExportedSymbol::NonGeneric { def_id, .. } => { + tcx.symbol_name(ty::Instance::mono(tcx, def_id)) + } ExportedSymbol::Generic(def_id, args) => { tcx.symbol_name(ty::Instance::new(def_id, args)) } diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 6b051da1b5a64..e90705830a7f4 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -29,8 +29,8 @@ use std::num::NonZero; use std::ops::Range; use std::path::PathBuf; use std::str::FromStr; -use std::sync::{Arc, Once}; use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; +use std::sync::{Arc, Once}; use miri::{ BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields, @@ -81,7 +81,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) { let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| { if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None } }); - if let Some(ExportedSymbol::NonGeneric(id)) = sym { + if let Some(ExportedSymbol::NonGeneric { def_id: id, .. }) = sym { let start_def_id = id.expect_local(); let start_span = tcx.def_span(start_def_id); @@ -265,7 +265,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { Some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + ExportedSymbol::NonGeneric { def_id: local_def_id.to_def_id(), cgu: None }, // Some dummy `SymbolExportInfo` here. We only use // `exported_symbols` in shims/foreign_items.rs and the export info // is ignored. diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index a26f12cdfb1e2..a6c86f934d091 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -162,7 +162,7 @@ pub fn iter_exported_symbols<'tcx>( // We can ignore `_export_info` here: we are a Rust crate, and everything is exported // from a Rust crate. for &(symbol, _export_info) in tcx.exported_symbols(cnum) { - if let ExportedSymbol::NonGeneric(def_id) = symbol { + if let ExportedSymbol::NonGeneric { def_id, .. } = symbol { f(cnum, def_id)?; } } diff --git a/tests/run-make/include-all-symbols-linking/lib.rs b/tests/run-make/include-all-symbols-linking/lib.rs index 99508bcdaf314..73186ee99e3d9 100644 --- a/tests/run-make/include-all-symbols-linking/lib.rs +++ b/tests/run-make/include-all-symbols-linking/lib.rs @@ -1,5 +1,6 @@ mod foo { - #[link_section = ".rodata.STATIC"] + #[cfg_attr(target_os = "linux", link_section = ".rodata.STATIC")] + #[cfg_attr(target_vendor = "apple", link_section = "__DATA,STATIC")] #[used] static STATIC: [u32; 10] = [1; 10]; } diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs index 77fd71ab20d21..bab510fb5be3c 100644 --- a/tests/run-make/include-all-symbols-linking/rmake.rs +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -7,15 +7,20 @@ // See https://github.com/rust-lang/rust/pull/95604 // See https://github.com/rust-lang/rust/issues/47384 -//@ only-linux -// Reason: differences in object file formats on OSX and Windows -// causes errors in the llvm_objdump step +//@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step. +//@ ignore-windows differences in object file formats causes errors in the llvm_objdump step. -use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc}; +use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc, target}; fn main() { rustc().crate_type("lib").input("lib.rs").run(); - rustc().crate_type("cdylib").link_args("-Tlinker.ld").input("main.rs").run(); + let mut main = rustc(); + main.crate_type("cdylib"); + if target().contains("linux") { + main.link_args("-Tlinker.ld"); + } + main.input("main.rs").run(); + // Ensure `#[used]` and `KEEP`-ed section is there llvm_objdump() .arg("--full-contents") diff --git a/tests/run-make/linker-warning/short-error.txt b/tests/run-make/linker-warning/short-error.txt index dd3b742bbfd56..238e25574fa48 100644 --- a/tests/run-make/linker-warning/short-error.txt +++ b/tests/run-make/linker-warning/short-error.txt @@ -1,6 +1,6 @@ error: linking with `./fake-linker` failed: exit status: 1 | - = note: "./fake-linker" "-m64" "/tmp/rustc/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" + = note: "./fake-linker" "-m64" "/tmp/rustc/symbols.o" "<5 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" = note: some arguments are omitted. use `--verbose` to show all linker arguments = note: error: baz diff --git a/tests/ui/attributes/auxiliary/used_pre_main_constructor.rs b/tests/ui/attributes/auxiliary/used_pre_main_constructor.rs new file mode 100644 index 0000000000000..6f9d7cc59e950 --- /dev/null +++ b/tests/ui/attributes/auxiliary/used_pre_main_constructor.rs @@ -0,0 +1,36 @@ +//! Add a constructor that runs pre-main, similar to what the `ctor` crate does. +//! +//! #[ctor] +//! fn constructor() { +//! printf(c"constructor\n"); +//! } + +//@ edition:2021 +//@ no-prefer-dynamic explicitly test with crates that are built as an archive +#![crate_type = "rlib"] + +#[cfg_attr( + any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "illumos", + target_os = "haiku" + ), + link_section = ".init_array" +)] +#[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func,mod_init_funcs")] +#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] +#[used] +static CONSTRUCTOR: extern "C" fn() = constructor; + +#[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")] +extern "C" fn constructor() { + extern "C" { + fn printf(format: *const std::ffi::c_char, ...) -> std::ffi::c_int; + } + unsafe { printf(c"constructor\n".as_ptr()) }; +} diff --git a/tests/ui/attributes/used_with_archive.rs b/tests/ui/attributes/used_with_archive.rs new file mode 100644 index 0000000000000..0a670a855d319 --- /dev/null +++ b/tests/ui/attributes/used_with_archive.rs @@ -0,0 +1,20 @@ +//! Ensure that `#[used]` in archives are correctly registered. +//! +//! Regression test for https://github.com/rust-lang/rust/issues/133491. + +//@ edition:2021 +//@ run-pass +//@ check-run-results +//@ aux-build: used_pre_main_constructor.rs + +//@ ignore-wasm ctor doesn't work on WASM + +// Make sure `rustc` links the archive, but intentionally do not import/use any items. +extern crate used_pre_main_constructor as _; + +fn main() { + extern "C" { + fn printf(format: *const std::ffi::c_char, ...) -> std::ffi::c_int; + } + unsafe { printf(c"main\n".as_ptr()) }; +} diff --git a/tests/ui/attributes/used_with_archive.run.stdout b/tests/ui/attributes/used_with_archive.run.stdout new file mode 100644 index 0000000000000..212372b3e5795 --- /dev/null +++ b/tests/ui/attributes/used_with_archive.run.stdout @@ -0,0 +1,2 @@ +constructor +main