Skip to content

Commit d9403bf

Browse files
committed
Implement weak linkage for statics
1 parent bfe8c89 commit d9403bf

File tree

4 files changed

+85
-17
lines changed

4 files changed

+85
-17
lines changed

example/mini_core_hello_world.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
22

3-
#![feature(no_core, unboxed_closures, start, lang_items, box_syntax, slice_patterns)]
3+
#![feature(no_core, unboxed_closures, start, lang_items, box_syntax, slice_patterns, never_type, linkage)]
44
#![no_core]
55
#![allow(dead_code)]
66

@@ -192,4 +192,18 @@ fn main() {
192192
}
193193

194194
assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
195+
196+
extern {
197+
#[linkage = "weak"]
198+
static ABC: *const u8;
199+
}
200+
201+
{
202+
extern {
203+
#[linkage = "weak"]
204+
static ABC: *const u8;
205+
}
206+
}
207+
208+
unsafe { assert_eq!(ABC as usize, 0); }
195209
}

src/constant.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ pub fn codegen_static_ref<'a, 'tcx: 'a>(
4646
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
4747
static_: &Static<'tcx>,
4848
) -> CPlace<'tcx> {
49-
let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
49+
let linkage = crate::linkage::get_static_ref_linkage(fx.tcx, static_.def_id);
50+
let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, linkage);
5051
cplace_for_dataid(fx, static_.ty, data_id)
5152
}
5253

@@ -188,9 +189,32 @@ fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
188189
!tcx.type_of(def_id)
189190
.is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
190191
};
191-
module
192+
193+
let data_id = module
192194
.declare_data(&*symbol_name, linkage, is_mutable)
193-
.unwrap()
195+
.unwrap();
196+
197+
if linkage == Linkage::Preemptible {
198+
if let ty::RawPtr(_) = tcx.type_of(def_id).sty {
199+
} else {
200+
tcx.sess.span_fatal(tcx.def_span(def_id), "must have type `*const T` or `*mut T`")
201+
}
202+
203+
let mut data_ctx = DataContext::new();
204+
let zero_bytes = std::iter::repeat(0)
205+
.take(pointer_ty(tcx).bytes() as usize)
206+
.collect::<Vec<u8>>()
207+
.into_boxed_slice();
208+
data_ctx.define(zero_bytes);
209+
match module.define_data(data_id, &data_ctx) {
210+
// Everytime a weak static is referenced, there will be a zero pointer definition,
211+
// so duplicate definitions are expected and allowed.
212+
Err(ModuleError::DuplicateDefinition(_)) => {}
213+
res => res.unwrap(),
214+
}
215+
}
216+
217+
data_id
194218
}
195219

196220
fn cplace_for_dataid<'a, 'tcx: 'a>(
@@ -222,6 +246,11 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
222246
}
223247
TodoItem::Static(def_id) => {
224248
//println!("static {:?}", def_id);
249+
250+
if tcx.is_foreign_item(def_id) {
251+
continue;
252+
}
253+
225254
let instance = ty::Instance::mono(tcx, def_id);
226255
let cid = GlobalId {
227256
instance,
@@ -234,6 +263,7 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
234263
_ => bug!("static const eval returned {:#?}", const_),
235264
};
236265

266+
// FIXME set correct linkage
237267
let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
238268
(data_id, alloc)
239269
}
@@ -271,7 +301,8 @@ fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
271301
}
272302
AllocKind::Static(def_id) => {
273303
cx.todo.insert(TodoItem::Static(def_id));
274-
data_id_for_static(tcx, module, def_id, Linkage::Import)
304+
let linkage = crate::linkage::get_static_ref_linkage(tcx, def_id);
305+
data_id_for_static(tcx, module, def_id, linkage)
275306
}
276307
};
277308

src/lib.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use rustc_codegen_ssa::back::linker::LinkerInfo;
2929
use rustc_codegen_ssa::CrateInfo;
3030
use rustc_codegen_utils::codegen_backend::CodegenBackend;
3131
use rustc_codegen_utils::link::out_filename;
32+
use rustc_mir::monomorphize::partitioning::CodegenUnitExt;
3233

3334
use cranelift::codegen::settings;
3435
use cranelift_faerie::*;
@@ -47,6 +48,7 @@ mod debuginfo;
4748
mod intrinsics;
4849
mod link;
4950
mod link_copied;
51+
mod linkage;
5052
mod main_shim;
5153
mod metadata;
5254
mod pretty_clif;
@@ -368,7 +370,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
368370
.downcast::<CodegenResults>()
369371
.expect("Expected CraneliftCodegenBackend's CodegenResult, found Box<Any>");
370372

371-
for &crate_type in sess.opts.crate_types.iter() {
373+
for &crate_type in sess.crate_types.borrow().iter() {
372374
let output_name = out_filename(sess, crate_type, &outputs, &res.crate_name.as_str());
373375
match crate_type {
374376
CrateType::Rlib => link::link_rlib(sess, &res, output_name),
@@ -423,9 +425,8 @@ fn codegen_cgus<'a, 'tcx: 'a>(
423425
let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
424426
let mono_items = cgus
425427
.iter()
426-
.map(|cgu| cgu.items().iter())
428+
.map(|cgu| cgu.items_in_deterministic_order(tcx).into_iter())
427429
.flatten()
428-
.map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis)))
429430
.collect::<FxHashMap<_, (_, _)>>();
430431

431432
codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items);
@@ -442,16 +443,9 @@ fn codegen_mono_items<'a, 'tcx: 'a>(
442443
) {
443444
let mut cx = CodegenCx::new(tcx, module, debug_context);
444445
time("codegen mono items", move || {
445-
for (mono_item, (linkage, vis)) in mono_items {
446+
for (mono_item, (linkage, visibility)) in mono_items {
446447
unimpl::try_unimpl(tcx, log, || {
447-
let linkage = match (linkage, vis) {
448-
(RLinkage::External, Visibility::Default) => Linkage::Export,
449-
(RLinkage::Internal, Visibility::Default) => Linkage::Local,
450-
// FIXME this should get external linkage, but hidden visibility,
451-
// not internal linkage and default visibility
452-
(RLinkage::External, Visibility::Hidden) => Linkage::Export,
453-
_ => panic!("{:?} = {:?} {:?}", mono_item, linkage, vis),
454-
};
448+
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
455449
base::trans_mono_item(&mut cx, mono_item, linkage);
456450
});
457451
}

src/linkage.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use rustc::mir::mono::{MonoItem, Linkage as RLinkage, Visibility};
2+
3+
use crate::prelude::*;
4+
5+
pub fn get_clif_linkage(mono_item: MonoItem, linkage: RLinkage, visibility: Visibility) -> Linkage {
6+
match (linkage, visibility) {
7+
(RLinkage::External, Visibility::Default) => Linkage::Export,
8+
(RLinkage::Internal, Visibility::Default) => Linkage::Local,
9+
// FIXME this should get external linkage, but hidden visibility,
10+
// not internal linkage and default visibility
11+
(RLinkage::External, Visibility::Hidden) => Linkage::Export,
12+
_ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility),
13+
}
14+
}
15+
16+
pub fn get_static_ref_linkage(tcx: TyCtxt, def_id: DefId) -> Linkage {
17+
let fn_attrs = tcx.codegen_fn_attrs(def_id);
18+
19+
if let Some(linkage) = fn_attrs.linkage {
20+
match linkage {
21+
RLinkage::External => Linkage::Export,
22+
RLinkage::Internal => Linkage::Local,
23+
RLinkage::ExternalWeak | RLinkage::WeakAny => Linkage::Preemptible,
24+
_ => panic!("{:?}", linkage),
25+
}
26+
} else {
27+
Linkage::Import
28+
}
29+
}

0 commit comments

Comments
 (0)