EII: generate aliases for implementations

This commit is contained in:
Jana Dönszelmann 2025-08-29 08:37:44 +02:00
parent a63f10a827
commit 9bd6b7ff72
No known key found for this signature in database
6 changed files with 95 additions and 5 deletions

View file

@ -2583,4 +2583,12 @@ unsafe extern "C" {
pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value);
pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
pub(crate) fn LLVMAddAlias2<'ll>(
M: &'ll Module,
ValueTy: &Type,
AddressSpace: c_uint,
Aliasee: &Value,
Name: *const c_char,
) -> &'ll Value;
}

View file

@ -6,7 +6,7 @@ use std::ptr;
use std::string::FromUtf8Error;
use libc::c_uint;
use rustc_abi::{Align, Size, WrappingRange};
use rustc_abi::{AddressSpace, Align, Size, WrappingRange};
use rustc_llvm::RustString;
pub(crate) use self::CallConv::*;
@ -452,3 +452,14 @@ pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
}
}
/// Safe wrapper for `LLVMAddAlias2`
pub(crate) fn add_alias<'ll>(
module: &'ll Module,
ty: &Type,
address_space: AddressSpace,
aliasee: &Value,
name: &CStr,
) -> &'ll Value {
unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
}

View file

@ -1,3 +1,6 @@
use std::ffi::CString;
use rustc_abi::AddressSpace;
use rustc_codegen_ssa::traits::*;
use rustc_hir::attrs::Linkage;
use rustc_hir::def::DefKind;
@ -7,6 +10,7 @@ use rustc_middle::mir::mono::Visibility;
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
use rustc_session::config::CrateType;
use rustc_span::Symbol;
use rustc_target::spec::{Arch, RelocModel};
use tracing::debug;
@ -41,6 +45,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
llvm::set_visibility(g, base::visibility_to_llvm(visibility));
self.assume_dso_local(g, false);
let attrs = self.tcx.codegen_instance_attrs(instance.def);
self.add_aliases(g, &attrs.foreign_item_symbol_aliases);
self.instances.borrow_mut().insert(instance, g);
}
@ -78,11 +85,31 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
self.assume_dso_local(lldecl, false);
self.add_aliases(lldecl, &attrs.foreign_item_symbol_aliases);
self.instances.borrow_mut().insert(instance, lldecl);
}
}
impl CodegenCx<'_, '_> {
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
let ty = self.get_type_of_global(aliasee);
for (alias, linkage, visibility) in aliases {
tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
let lldecl = llvm::add_alias(
self.llmod,
ty,
AddressSpace::ZERO,
aliasee,
&CString::new(alias.as_str()).unwrap(),
);
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
}
}
/// Whether a definition or declaration can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
/// Marks the local as DSO if so.

View file

@ -3,19 +3,22 @@ use std::str::FromStr;
use rustc_abi::{Align, ExternAbi};
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy};
use rustc_hir::attrs::{
AttributeKind, InlineAttr, InstructionSetAttr, Linkage, RtsanSetting, UsedBy,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
use rustc_middle::mir::mono::Visibility;
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::{Ident, Span, sym};
use rustc_span::{Ident, Span, Symbol, sym};
use rustc_target::spec::Os;
use crate::errors;
@ -310,6 +313,39 @@ fn process_builtin_attrs(
AttributeKind::ObjcSelector { methname, .. } => {
codegen_fn_attrs.objc_selector = Some(*methname);
}
AttributeKind::EiiImpls(impls) => {
for i in impls {
let extern_item = find_attr!(
tcx.get_all_attrs(i.eii_macro),
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
)
.expect("eii should have declaration macro with extern target attribute");
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
// this is to prevent a bug where a single crate defines both the default and explicit implementation
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
// what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent.
// However, the fact that the default one of has weak linkage isn't considered and you sometimes get that
// the default implementation is used while an explicit implementation is given.
if
// if this is a default impl
i.is_default
// iterate over all implementations *in the current crate*
// (this is ok since we generate codegen fn attrs in the local crate)
// if any of them is *not default* then don't emit the alias.
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
{
continue;
}
codegen_fn_attrs.foreign_item_symbol_aliases.push((
Symbol::intern(symbol_name.name),
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
Visibility::Default,
));
}
}
_ => {}
}
}

View file

@ -6,6 +6,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_span::Symbol;
use rustc_target::spec::SanitizerSet;
use crate::mir::mono::Visibility;
use crate::ty::{InstanceKind, TyCtxt};
impl<'tcx> TyCtxt<'tcx> {
@ -62,6 +63,12 @@ pub struct CodegenFnAttrs {
/// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
/// depending on if this is a function definition or foreign function.
pub symbol_name: Option<Symbol>,
/// Defids of foreign items somewhere that this function should "satisfy".
/// i.e., if a foreign function has some symbol foo,
/// generate this function under its real name,
/// but *also* under the same name as this foreign function so that the foreign function has an implementation.
// FIXME: make "SymbolName<'tcx>"
pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>,
/// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
/// imported function has in the dynamic library. Note that this must not
/// be set when `link_name` is set. This is for foreign items with the
@ -207,6 +214,7 @@ impl CodegenFnAttrs {
symbol_name: None,
link_ordinal: None,
target_features: vec![],
foreign_item_symbol_aliases: vec![],
safe_target_features: false,
linkage: None,
import_linkage: None,

View file

@ -374,7 +374,7 @@ pub struct MonoItemData {
/// Visibility doesn't have any effect when linkage is internal.
///
/// DSO means dynamic shared object, that is a dynamically linked executable or dylib.
#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
#[derive(Copy, Clone, PartialEq, Debug, HashStable, TyEncodable, TyDecodable)]
pub enum Visibility {
/// Export the symbol from the DSO and apply overrides of the symbol by outside DSOs to within
/// the DSO if the object file format supports this.