Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 13 additions & 4 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use super::linker::{self, Linker};
use super::metadata::{MetadataPosition, create_wrapper_file};
use super::rpath::{self, RPathConfig};
use super::{apple, versioned_llvm_target};
use crate::base::needs_allocator_shim_for_linking;
use crate::{
CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file,
};
Expand Down Expand Up @@ -2080,9 +2081,17 @@ fn add_local_crate_regular_objects(cmd: &mut dyn Linker, codegen_results: &Codeg
}

/// Add object files for allocator code linked once for the whole crate tree.
fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &CodegenResults) {
if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref()) {
cmd.add_object(obj);
fn add_local_crate_allocator_objects(
cmd: &mut dyn Linker,
codegen_results: &CodegenResults,
crate_type: CrateType,
) {
if needs_allocator_shim_for_linking(&codegen_results.crate_info.dependency_formats, crate_type)
{
if let Some(obj) = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref())
{
cmd.add_object(obj);
}
}
}

Expand Down Expand Up @@ -2281,7 +2290,7 @@ fn linker_with_args(
codegen_results,
metadata,
);
add_local_crate_allocator_objects(cmd, codegen_results);
add_local_crate_allocator_objects(cmd, codegen_results, crate_type);

// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
// at the point at which they are specified on the command line.
Expand Down
17 changes: 14 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use rustc_metadata::{
};
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, SymbolExportLevel,
};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
Expand All @@ -22,6 +23,8 @@ use tracing::{debug, warn};

use super::command::Command;
use super::symbol_export;
use crate::back::symbol_export::allocator_shim_symbols;
use crate::base::needs_allocator_shim_for_linking;
use crate::errors;

#[cfg(test)]
Expand Down Expand Up @@ -1827,7 +1830,7 @@ fn exported_symbols_for_non_proc_macro(
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
// Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins
// from any cdylib. The latter doesn't work anyway as we use hidden visibility for
// from any dylib. The latter doesn't work anyway as we use hidden visibility for
// compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
symbols.push((
Expand All @@ -1838,6 +1841,14 @@ fn exported_symbols_for_non_proc_macro(
}
});

// Mark allocator shim symbols as exported only if they were generated.
if export_threshold == SymbolExportLevel::Rust
&& needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type)
&& tcx.allocator_kind(()).is_some()
{
symbols.extend(allocator_shim_symbols(tcx));
}

symbols
}

Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, Lto};
use tracing::info;

use crate::back::symbol_export::{self, symbol_name_for_instance_in_crate};
use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate};
use crate::back::write::CodegenContext;
use crate::base::allocator_kind_for_codegen;
use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
use crate::traits::*;

Expand Down Expand Up @@ -115,6 +116,11 @@ pub(super) fn exported_symbols_for_lto(
}
}

// Mark allocator shim symbols as exported only if they were generated.
if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
}

symbols_below_threshold
}

Expand Down
52 changes: 26 additions & 26 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::TlsModel;
use tracing::debug;

use crate::base::allocator_kind_for_codegen;
use crate::back::symbol_export;

fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
crates_export_threshold(tcx.crate_types())
Expand Down Expand Up @@ -217,31 +217,6 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
));
}

// Mark allocator shim symbols as exported only if they were generated.
if allocator_kind_for_codegen(tcx).is_some() {
for symbol_name in ALLOCATOR_METHODS
.iter()
.map(|method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
.chain([
mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
])
{
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));

symbols.push((
exported_symbol,
SymbolExportInfo {
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
rustc_std_internal_symbol: true,
},
));
}
}

// Sort so we get a stable incr. comp. hash.
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));

Expand Down Expand Up @@ -516,6 +491,31 @@ pub(crate) fn provide(providers: &mut Providers) {
upstream_monomorphizations_for_provider;
}

pub(crate) fn allocator_shim_symbols(
tcx: TyCtxt<'_>,
) -> impl Iterator<Item = (String, SymbolExportKind)> {
ALLOCATOR_METHODS
.iter()
.map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
.chain([
mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
])
.map(move |symbol_name| {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));

(
symbol_export::exporting_symbol_name_for_instance_in_crate(
tcx,
exported_symbol,
LOCAL_CRATE,
),
SymbolExportKind::Text,
)
})
}

fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
// We export anything that's not mangled at the "C" layer as it probably has
// to do with ABI concerns. We do not, however, apply such treatment to
Expand Down
27 changes: 22 additions & 5 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{ItemId, Target};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
use rustc_middle::middle::lang_items;
use rustc_middle::mir::BinOp;
Expand Down Expand Up @@ -630,14 +631,30 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
// If the crate doesn't have an `allocator_kind` set then there's definitely
// no shim to generate. Otherwise we also check our dependency graph for all
// our output crate types. If anything there looks like its a `Dynamic`
// linkage, then it's already got an allocator shim and we'll be using that
// one instead. If nothing exists then it's our job to generate the
// allocator!
let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
// linkage for all crate types we may link as, then it's already got an
// allocator shim and we'll be using that one instead. If nothing exists
// then it's our job to generate the allocator! If crate types disagree
// about whether an allocator shim is necessary or not, we generate one
// and let needs_allocator_shim_for_linking decide at link time whether or
// not to use it for any particular linker invocation.
let all_crate_types_any_dynamic_crate = tcx.dependency_formats(()).iter().all(|(_, list)| {
use rustc_middle::middle::dependency_format::Linkage;
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
});
if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
if all_crate_types_any_dynamic_crate { None } else { tcx.allocator_kind(()) }
}

/// Decide if this particular crate type needs an allocator shim linked in.
/// This may return true even when allocator_kind_for_codegen returns false. In
/// this case no allocator shim shall be linked.
pub(crate) fn needs_allocator_shim_for_linking(
dependency_formats: &Dependencies,
crate_type: CrateType,
) -> bool {
use rustc_middle::middle::dependency_format::Linkage;
let any_dynamic_crate =
dependency_formats[&crate_type].iter().any(|&linkage| linkage == Linkage::Dynamic);
!any_dynamic_crate
}

pub fn codegen_crate<B: ExtraBackendMethods>(
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/linking/mixed-allocator-shim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//@ build-pass
//@ compile-flags: --crate-type staticlib,dylib -Zstaticlib-prefer-dynamic
//@ no-prefer-dynamic

// Test that compiling for multiple crate types in a single compilation with
// mismatching allocator shim requirements doesn't result in the allocator shim
// missing entirely.
// In this particular test the dylib crate type will statically link libstd and
// thus need an allocator shim, while the staticlib crate type will dynamically
// link libstd and thus not need an allocator shim.
// The -Zstaticlib-prefer-dynamic flag could be avoided by doing it the other
// way around, but testing that the staticlib correctly has the allocator shim
// in that case would require a run-make test instead.

pub fn foo() {}
Loading