Implement weak linkage for statics

This commit is contained in:
bjorn3 2019-03-11 20:36:29 +01:00
parent bfe8c89d41
commit d9403bf3fd
4 changed files with 85 additions and 17 deletions

View File

@ -1,6 +1,6 @@
// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
#![feature(no_core, unboxed_closures, start, lang_items, box_syntax, slice_patterns)] #![feature(no_core, unboxed_closures, start, lang_items, box_syntax, slice_patterns, never_type, linkage)]
#![no_core] #![no_core]
#![allow(dead_code)] #![allow(dead_code)]
@ -192,4 +192,18 @@ fn main() {
} }
assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
extern {
#[linkage = "weak"]
static ABC: *const u8;
}
{
extern {
#[linkage = "weak"]
static ABC: *const u8;
}
}
unsafe { assert_eq!(ABC as usize, 0); }
} }

View File

@ -46,7 +46,8 @@ pub fn codegen_static_ref<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>, fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
static_: &Static<'tcx>, static_: &Static<'tcx>,
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import); let linkage = crate::linkage::get_static_ref_linkage(fx.tcx, static_.def_id);
let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, linkage);
cplace_for_dataid(fx, static_.ty, data_id) cplace_for_dataid(fx, static_.ty, data_id)
} }
@ -188,9 +189,32 @@ fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
!tcx.type_of(def_id) !tcx.type_of(def_id)
.is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP) .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
}; };
module
let data_id = module
.declare_data(&*symbol_name, linkage, is_mutable) .declare_data(&*symbol_name, linkage, is_mutable)
.unwrap() .unwrap();
if linkage == Linkage::Preemptible {
if let ty::RawPtr(_) = tcx.type_of(def_id).sty {
} else {
tcx.sess.span_fatal(tcx.def_span(def_id), "must have type `*const T` or `*mut T`")
}
let mut data_ctx = DataContext::new();
let zero_bytes = std::iter::repeat(0)
.take(pointer_ty(tcx).bytes() as usize)
.collect::<Vec<u8>>()
.into_boxed_slice();
data_ctx.define(zero_bytes);
match module.define_data(data_id, &data_ctx) {
// Everytime a weak static is referenced, there will be a zero pointer definition,
// so duplicate definitions are expected and allowed.
Err(ModuleError::DuplicateDefinition(_)) => {}
res => res.unwrap(),
}
}
data_id
} }
fn cplace_for_dataid<'a, 'tcx: 'a>( fn cplace_for_dataid<'a, 'tcx: 'a>(
@ -222,6 +246,11 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
} }
TodoItem::Static(def_id) => { TodoItem::Static(def_id) => {
//println!("static {:?}", def_id); //println!("static {:?}", def_id);
if tcx.is_foreign_item(def_id) {
continue;
}
let instance = ty::Instance::mono(tcx, def_id); let instance = ty::Instance::mono(tcx, def_id);
let cid = GlobalId { let cid = GlobalId {
instance, instance,
@ -234,6 +263,7 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
_ => bug!("static const eval returned {:#?}", const_), _ => bug!("static const eval returned {:#?}", const_),
}; };
// FIXME set correct linkage
let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export); let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
(data_id, alloc) (data_id, alloc)
} }
@ -271,7 +301,8 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
} }
AllocKind::Static(def_id) => { AllocKind::Static(def_id) => {
cx.todo.insert(TodoItem::Static(def_id)); cx.todo.insert(TodoItem::Static(def_id));
data_id_for_static(tcx, module, def_id, Linkage::Import) let linkage = crate::linkage::get_static_ref_linkage(tcx, def_id);
data_id_for_static(tcx, module, def_id, linkage)
} }
}; };

View File

@ -29,6 +29,7 @@ use rustc_codegen_ssa::back::linker::LinkerInfo;
use rustc_codegen_ssa::CrateInfo; use rustc_codegen_ssa::CrateInfo;
use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_codegen_utils::link::out_filename; use rustc_codegen_utils::link::out_filename;
use rustc_mir::monomorphize::partitioning::CodegenUnitExt;
use cranelift::codegen::settings; use cranelift::codegen::settings;
use cranelift_faerie::*; use cranelift_faerie::*;
@ -47,6 +48,7 @@ mod debuginfo;
mod intrinsics; mod intrinsics;
mod link; mod link;
mod link_copied; mod link_copied;
mod linkage;
mod main_shim; mod main_shim;
mod metadata; mod metadata;
mod pretty_clif; mod pretty_clif;
@ -368,7 +370,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
.downcast::<CodegenResults>() .downcast::<CodegenResults>()
.expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>"); .expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");
for &crate_type in sess.opts.crate_types.iter() { for &crate_type in sess.crate_types.borrow().iter() {
let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str()); let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
match crate_type { match crate_type {
CrateType::Rlib => link::link_rlib(sess, &res, output_name), CrateType::Rlib => link::link_rlib(sess, &res, output_name),
@ -423,9 +425,8 @@ fn codegen_cgus<'a, 'tcx: 'a>(
let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
let mono_items = cgus let mono_items = cgus
.iter() .iter()
.map(|cgu| cgu.items().iter()) .map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
.flatten() .flatten()
.map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis)))
.collect::<FxHashMap<_, (_, _)>>(); .collect::<FxHashMap<_, (_, _)>>();
codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items); codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);
@ -442,16 +443,9 @@ fn codegen_mono_items<'a, 'tcx: 'a>(
) { ) {
let mut cx = CodegenCx::new(tcx, module, debug_context); let mut cx = CodegenCx::new(tcx, module, debug_context);
time("codegen mono items", move || { time("codegen mono items", move || {
for (mono_item, (linkage, vis)) in mono_items { for (mono_item, (linkage, visibility)) in mono_items {
unimpl::try_unimpl(tcx, log, || { unimpl::try_unimpl(tcx, log, || {
let linkage = match (linkage, vis) { let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
(RLinkage::External, Visibility::Default) => Linkage::Export,
(RLinkage::Internal, Visibility::Default) => Linkage::Local,
// FIXME this should get external linkage, but hidden visibility,
// not internal linkage and default visibility
(RLinkage::External, Visibility::Hidden) => Linkage::Export,
_ => panic!("{:?} = {:?} {:?}", mono_item, linkage, vis),
};
base::trans_mono_item(&mut cx, mono_item, linkage); base::trans_mono_item(&mut cx, mono_item, linkage);
}); });
} }

29
src/linkage.rs Normal file
View File

@ -0,0 +1,29 @@
use rustc::mir::mono::{MonoItem, Linkage as RLinkage, Visibility};
use crate::prelude::*;
pub fn get_clif_linkage(mono_item: MonoItem, linkage: RLinkage, visibility: Visibility) -> Linkage {
match (linkage, visibility) {
(RLinkage::External, Visibility::Default) => Linkage::Export,
(RLinkage::Internal, Visibility::Default) => Linkage::Local,
// FIXME this should get external linkage, but hidden visibility,
// not internal linkage and default visibility
(RLinkage::External, Visibility::Hidden) => Linkage::Export,
_ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility),
}
}
pub fn get_static_ref_linkage(tcx: TyCtxt, def_id: DefId) -> Linkage {
let fn_attrs = tcx.codegen_fn_attrs(def_id);
if let Some(linkage) = fn_attrs.linkage {
match linkage {
RLinkage::External => Linkage::Export,
RLinkage::Internal => Linkage::Local,
RLinkage::ExternalWeak | RLinkage::WeakAny => Linkage::Preemptible,
_ => panic!("{:?}", linkage),
}
} else {
Linkage::Import
}
}