Skip to content

Commit 699bfa8

Browse files
committed
Auto merge of #100404 - BelovDV:linker_group, r=petrochenkov
change stdlib circular dependencies handling Remove group_start and group_end, add dependencies to symbols.o Implements the suggestion from #85805 (comment) r? `@petrochenkov`
2 parents 78a891d + c34047c commit 699bfa8

File tree

5 files changed

+57
-122
lines changed

5 files changed

+57
-122
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+16-60
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_arena::TypedArena;
22
use rustc_ast::CRATE_NODE_ID;
3-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
3+
use rustc_data_structures::fx::FxIndexMap;
44
use rustc_data_structures::memmap::Mmap;
55
use rustc_data_structures::temp_dir::MaybeTempDir;
66
use rustc_errors::{ErrorGuaranteed, Handler};
@@ -1714,6 +1714,13 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
17141714
/// that are necessary for the linking. They are only present in symbol table but not actually
17151715
/// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
17161716
/// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
1717+
///
1718+
/// There's a few internal crates in the standard library (aka libcore and
1719+
/// libstd) which actually have a circular dependence upon one another. This
1720+
/// currently arises through "weak lang items" where libcore requires things
1721+
/// like `rust_begin_unwind` but libstd ends up defining it. To get this
1722+
/// circular dependence to work correctly we declare some of these things
1723+
/// in this synthetic object.
17171724
fn add_linked_symbol_object(
17181725
cmd: &mut dyn Linker,
17191726
sess: &Session,
@@ -2333,65 +2340,10 @@ fn add_upstream_rust_crates<'a>(
23332340
// crates.
23342341
let deps = &codegen_results.crate_info.used_crates;
23352342

2336-
// There's a few internal crates in the standard library (aka libcore and
2337-
// libstd) which actually have a circular dependence upon one another. This
2338-
// currently arises through "weak lang items" where libcore requires things
2339-
// like `rust_begin_unwind` but libstd ends up defining it. To get this
2340-
// circular dependence to work correctly in all situations we'll need to be
2341-
// sure to correctly apply the `--start-group` and `--end-group` options to
2342-
// GNU linkers, otherwise if we don't use any other symbol from the standard
2343-
// library it'll get discarded and the whole application won't link.
2344-
//
2345-
// In this loop we're calculating the `group_end`, after which crate to
2346-
// pass `--end-group` and `group_start`, before which crate to pass
2347-
// `--start-group`. We currently do this by passing `--end-group` after
2348-
// the first crate (when iterating backwards) that requires a lang item
2349-
// defined somewhere else. Once that's set then when we've defined all the
2350-
// necessary lang items we'll pass `--start-group`.
2351-
//
2352-
// Note that this isn't amazing logic for now but it should do the trick
2353-
// for the current implementation of the standard library.
2354-
let mut group_end = None;
2355-
let mut group_start = None;
2356-
// Crates available for linking thus far.
2357-
let mut available = FxHashSet::default();
2358-
// Crates required to satisfy dependencies discovered so far.
2359-
let mut required = FxHashSet::default();
2360-
2361-
let info = &codegen_results.crate_info;
2362-
for &cnum in deps.iter().rev() {
2363-
if let Some(missing) = info.missing_lang_items.get(&cnum) {
2364-
let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied());
2365-
required.extend(missing_crates);
2366-
}
2367-
2368-
required.insert(Some(cnum));
2369-
available.insert(Some(cnum));
2370-
2371-
if required.len() > available.len() && group_end.is_none() {
2372-
group_end = Some(cnum);
2373-
}
2374-
if required.len() == available.len() && group_end.is_some() {
2375-
group_start = Some(cnum);
2376-
break;
2377-
}
2378-
}
2379-
2380-
// If we didn't end up filling in all lang items from upstream crates then
2381-
// we'll be filling it in with our crate. This probably means we're the
2382-
// standard library itself, so skip this for now.
2383-
if group_end.is_some() && group_start.is_none() {
2384-
group_end = None;
2385-
}
2386-
23872343
let mut compiler_builtins = None;
23882344
let search_path = OnceCell::new();
23892345

23902346
for &cnum in deps.iter() {
2391-
if group_start == Some(cnum) {
2392-
cmd.group_start();
2393-
}
2394-
23952347
// We may not pass all crates through to the linker. Some crates may
23962348
// appear statically in an existing dylib, meaning we'll pick up all the
23972349
// symbols from the dylib.
@@ -2451,6 +2403,14 @@ fn add_upstream_rust_crates<'a>(
24512403
bundle: Some(false),
24522404
whole_archive: Some(false) | None,
24532405
} => {
2406+
// HACK/FIXME: Fixup a circular dependency between libgcc and libc
2407+
// with glibc. This logic should be moved to the libc crate.
2408+
if sess.target.os == "linux"
2409+
&& sess.target.env == "gnu"
2410+
&& name == "c"
2411+
{
2412+
cmd.link_staticlib("gcc", false);
2413+
}
24542414
cmd.link_staticlib(name, lib.verbatim.unwrap_or(false));
24552415
}
24562416
NativeLibKind::LinkArg => {
@@ -2470,10 +2430,6 @@ fn add_upstream_rust_crates<'a>(
24702430
}
24712431
Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
24722432
}
2473-
2474-
if group_end == Some(cnum) {
2475-
cmd.group_end();
2476-
}
24772433
}
24782434

24792435
// compiler-builtins are always placed last to ensure that they're

compiler/rustc_codegen_ssa/src/back/linker.rs

-42
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,6 @@ pub trait Linker {
183183
fn no_default_libraries(&mut self);
184184
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
185185
fn subsystem(&mut self, subsystem: &str);
186-
fn group_start(&mut self);
187-
fn group_end(&mut self);
188186
fn linker_plugin_lto(&mut self);
189187
fn add_eh_frame_header(&mut self) {}
190188
fn add_no_exec(&mut self) {}
@@ -730,18 +728,6 @@ impl<'a> Linker for GccLinker<'a> {
730728
self.hint_dynamic(); // Reset to default before returning the composed command line.
731729
}
732730

733-
fn group_start(&mut self) {
734-
if self.takes_hints() {
735-
self.linker_arg("--start-group");
736-
}
737-
}
738-
739-
fn group_end(&mut self) {
740-
if self.takes_hints() {
741-
self.linker_arg("--end-group");
742-
}
743-
}
744-
745731
fn linker_plugin_lto(&mut self) {
746732
match self.sess.opts.cg.linker_plugin_lto {
747733
LinkerPluginLto::Disabled => {
@@ -1019,10 +1005,6 @@ impl<'a> Linker for MsvcLinker<'a> {
10191005
}
10201006
}
10211007

1022-
// MSVC doesn't need group indicators
1023-
fn group_start(&mut self) {}
1024-
fn group_end(&mut self) {}
1025-
10261008
fn linker_plugin_lto(&mut self) {
10271009
// Do nothing
10281010
}
@@ -1165,10 +1147,6 @@ impl<'a> Linker for EmLinker<'a> {
11651147
// noop
11661148
}
11671149

1168-
// Appears not necessary on Emscripten
1169-
fn group_start(&mut self) {}
1170-
fn group_end(&mut self) {}
1171-
11721150
fn linker_plugin_lto(&mut self) {
11731151
// Do nothing
11741152
}
@@ -1344,10 +1322,6 @@ impl<'a> Linker for WasmLd<'a> {
13441322

13451323
fn subsystem(&mut self, _subsystem: &str) {}
13461324

1347-
// Not needed for now with LLD
1348-
fn group_start(&mut self) {}
1349-
fn group_end(&mut self) {}
1350-
13511325
fn linker_plugin_lto(&mut self) {
13521326
// Do nothing for now
13531327
}
@@ -1476,14 +1450,6 @@ impl<'a> Linker for L4Bender<'a> {
14761450
self.hint_static(); // Reset to default before returning the composed command line.
14771451
}
14781452

1479-
fn group_start(&mut self) {
1480-
self.cmd.arg("--start-group");
1481-
}
1482-
1483-
fn group_end(&mut self) {
1484-
self.cmd.arg("--end-group");
1485-
}
1486-
14871453
fn linker_plugin_lto(&mut self) {}
14881454

14891455
fn control_flow_guard(&mut self) {}
@@ -1664,10 +1630,6 @@ impl<'a> Linker for PtxLinker<'a> {
16641630

16651631
fn subsystem(&mut self, _subsystem: &str) {}
16661632

1667-
fn group_start(&mut self) {}
1668-
1669-
fn group_end(&mut self) {}
1670-
16711633
fn linker_plugin_lto(&mut self) {}
16721634
}
16731635

@@ -1777,9 +1739,5 @@ impl<'a> Linker for BpfLinker<'a> {
17771739

17781740
fn subsystem(&mut self, _subsystem: &str) {}
17791741

1780-
fn group_start(&mut self) {}
1781-
1782-
fn group_end(&mut self) {}
1783-
17841742
fn linker_plugin_lto(&mut self) {}
17851743
}

compiler/rustc_codegen_ssa/src/base.rs

+35-17
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::traits::*;
1212
use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
1313

1414
use rustc_attr as attr;
15-
use rustc_data_structures::fx::FxHashMap;
15+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1616
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
1717

1818
use rustc_data_structures::sync::par_iter;
@@ -21,10 +21,12 @@ use rustc_data_structures::sync::ParallelIterator;
2121
use rustc_hir as hir;
2222
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
2323
use rustc_hir::lang_items::LangItem;
24+
use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS;
2425
use rustc_index::vec::Idx;
2526
use rustc_metadata::EncodedMetadata;
2627
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
2728
use rustc_middle::middle::exported_symbols;
29+
use rustc_middle::middle::exported_symbols::SymbolExportKind;
2830
use rustc_middle::middle::lang_items;
2931
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
3032
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
@@ -34,6 +36,7 @@ use rustc_session::cgu_reuse_tracker::CguReuse;
3436
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
3537
use rustc_session::Session;
3638
use rustc_span::symbol::sym;
39+
use rustc_span::Symbol;
3740
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
3841
use rustc_target::abi::{Align, VariantIdx};
3942

@@ -815,21 +818,16 @@ impl CrateInfo {
815818
crate_name: Default::default(),
816819
used_crates,
817820
used_crate_source: Default::default(),
818-
lang_item_to_crate: Default::default(),
819-
missing_lang_items: Default::default(),
820821
dependency_formats: tcx.dependency_formats(()).clone(),
821822
windows_subsystem,
822823
natvis_debugger_visualizers: Default::default(),
823824
};
824-
let lang_items = tcx.lang_items();
825-
826825
let crates = tcx.crates(());
827826

828827
let n_crates = crates.len();
829828
info.native_libraries.reserve(n_crates);
830829
info.crate_name.reserve(n_crates);
831830
info.used_crate_source.reserve(n_crates);
832-
info.missing_lang_items.reserve(n_crates);
833831

834832
for &cnum in crates.iter() {
835833
info.native_libraries
@@ -847,17 +845,37 @@ impl CrateInfo {
847845
if tcx.is_no_builtins(cnum) {
848846
info.is_no_builtins.insert(cnum);
849847
}
850-
let missing = tcx.missing_lang_items(cnum);
851-
for &item in missing.iter() {
852-
if let Ok(id) = lang_items.require(item) {
853-
info.lang_item_to_crate.insert(item, id.krate);
854-
}
855-
}
848+
}
856849

857-
// No need to look for lang items that don't actually need to exist.
858-
let missing =
859-
missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
860-
info.missing_lang_items.insert(cnum, missing);
850+
// Handle circular dependencies in the standard library.
851+
// See comment before `add_linked_symbol_object` function for the details.
852+
// With msvc-like linkers it's both unnecessary (they support circular dependencies),
853+
// and causes linking issues (when weak lang item symbols are "privatized" by LTO).
854+
let target = &tcx.sess.target;
855+
if !target.is_like_msvc {
856+
let missing_weak_lang_items: FxHashSet<&Symbol> = info
857+
.used_crates
858+
.iter()
859+
.flat_map(|cnum| {
860+
tcx.missing_lang_items(*cnum)
861+
.iter()
862+
.filter(|l| lang_items::required(tcx, **l))
863+
.filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item))
864+
})
865+
.collect();
866+
let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
867+
info.linked_symbols
868+
.iter_mut()
869+
.filter(|(crate_type, _)| {
870+
!matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
871+
})
872+
.for_each(|(_, linked_symbols)| {
873+
linked_symbols.extend(
874+
missing_weak_lang_items
875+
.iter()
876+
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
877+
)
878+
});
861879
}
862880

863881
let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
@@ -878,7 +896,7 @@ impl CrateInfo {
878896
}
879897
});
880898

881-
if tcx.sess.target.is_like_msvc && embed_visualizers {
899+
if target.is_like_msvc && embed_visualizers {
882900
info.natvis_debugger_visualizers =
883901
collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
884902
}

compiler/rustc_codegen_ssa/src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use rustc_ast as ast;
2525
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2626
use rustc_data_structures::sync::Lrc;
2727
use rustc_hir::def_id::CrateNum;
28-
use rustc_hir::LangItem;
2928
use rustc_middle::dep_graph::WorkProduct;
3029
use rustc_middle::middle::dependency_format::Dependencies;
3130
use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -152,8 +151,6 @@ pub struct CrateInfo {
152151
pub used_libraries: Vec<NativeLib>,
153152
pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
154153
pub used_crates: Vec<CrateNum>,
155-
pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
156-
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
157154
pub dependency_formats: Lrc<Dependencies>,
158155
pub windows_subsystem: Option<String>,
159156
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,

compiler/rustc_hir/src/weak_lang_items.rs

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::n
1818
map
1919
});
2020

21+
pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| {
22+
let mut map = FxIndexMap::default();
23+
$(map.insert(LangItem::$item, sym::$sym);)*
24+
map
25+
});
26+
2127
pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
2228
{
2329
lang_items::extract(attrs).and_then(|(name, _)| {

0 commit comments

Comments
 (0)