Skip to content

Commit f98598c

Browse files
committed
Auto merge of rust-lang#108089 - Zoxc:windows-tls, r=bjorn3
Support TLS access into dylibs on Windows This allows access to `#[thread_local]` in upstream dylibs on Windows by introducing a MIR shim to return the address of the thread local. Accesses that go into an upstream dylib will call the MIR shim to get the address of it. `convert_tls_rvalues` is introduced in `rustc_codegen_ssa` which rewrites MIR TLS accesses to dummy calls which are replaced with calls to the MIR shims when the dummy calls are lowered to backend calls. A new `dll_tls_export` target option enables this behavior with a `false` value which is set for Windows platforms. This fixes rust-lang#84933.
2 parents 8679208 + d499bbb commit f98598c

File tree

28 files changed

+262
-95
lines changed

28 files changed

+262
-95
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,22 @@ pub(crate) fn codegen_tls_ref<'tcx>(
5454
def_id: DefId,
5555
layout: TyAndLayout<'tcx>,
5656
) -> CValue<'tcx> {
57-
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
58-
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
59-
if fx.clif_comments.enabled() {
60-
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
61-
}
62-
let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id);
57+
let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) {
58+
let instance = ty::Instance {
59+
def: ty::InstanceDef::ThreadLocalShim(def_id),
60+
substs: ty::InternalSubsts::empty(),
61+
};
62+
let func_ref = fx.get_function_ref(instance);
63+
let call = fx.bcx.ins().call(func_ref, &[]);
64+
fx.bcx.func.dfg.first_result(call)
65+
} else {
66+
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
67+
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
68+
if fx.clif_comments.enabled() {
69+
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
70+
}
71+
fx.bcx.ins().tls_value(fx.pointer_type, local_data_id)
72+
};
6373
CValue::by_val(tls_ptr, layout)
6474
}
6575

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,29 @@ fn exported_symbols_provider_local(
177177

178178
// FIXME: Sorting this is unnecessary since we are sorting later anyway.
179179
// Can we skip the later sorting?
180-
let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
181-
tcx.reachable_non_generics(LOCAL_CRATE)
182-
.to_sorted(&hcx, true)
183-
.into_iter()
184-
.map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
185-
.collect()
180+
let sorted = tcx.with_stable_hashing_context(|hcx| {
181+
tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true)
186182
});
187183

184+
let mut symbols: Vec<_> =
185+
sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect();
186+
187+
// Export TLS shims
188+
if !tcx.sess.target.dll_tls_export {
189+
symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| {
190+
tcx.needs_thread_local_shim(def_id).then(|| {
191+
(
192+
ExportedSymbol::ThreadLocalShim(def_id),
193+
SymbolExportInfo {
194+
level: info.level,
195+
kind: SymbolExportKind::Text,
196+
used: info.used,
197+
},
198+
)
199+
})
200+
}))
201+
}
202+
188203
if tcx.entry_fn(()).is_some() {
189204
let exported_symbol =
190205
ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref()));
@@ -380,7 +395,9 @@ fn upstream_monomorphizations_provider(
380395
continue;
381396
}
382397
}
383-
ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => {
398+
ExportedSymbol::NonGeneric(..)
399+
| ExportedSymbol::ThreadLocalShim(..)
400+
| ExportedSymbol::NoDefId(..) => {
384401
// These are no monomorphizations
385402
continue;
386403
}
@@ -500,6 +517,16 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
500517
instantiating_crate,
501518
)
502519
}
520+
ExportedSymbol::ThreadLocalShim(def_id) => {
521+
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
522+
tcx,
523+
ty::Instance {
524+
def: ty::InstanceDef::ThreadLocalShim(def_id),
525+
substs: ty::InternalSubsts::empty(),
526+
},
527+
instantiating_crate,
528+
)
529+
}
503530
ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate(
504531
tcx,
505532
Instance::resolve_drop_in_place(tcx, ty),
@@ -548,6 +575,8 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
548575
ExportedSymbol::DropGlue(..) => None,
549576
// NoDefId always follow the target's default symbol decoration scheme.
550577
ExportedSymbol::NoDefId(..) => None,
578+
// ThreadLocalShim always follow the target's default symbol decoration scheme.
579+
ExportedSymbol::ThreadLocalShim(..) => None,
551580
};
552581

553582
let (conv, args) = instance

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
516516

517517
mir::Rvalue::ThreadLocalRef(def_id) => {
518518
assert!(bx.cx().tcx().is_static(def_id));
519-
let static_ = bx.get_static(def_id);
520519
let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
520+
let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id)
521+
{
522+
let instance = ty::Instance {
523+
def: ty::InstanceDef::ThreadLocalShim(def_id),
524+
substs: ty::InternalSubsts::empty(),
525+
};
526+
let fn_ptr = bx.get_fn_addr(instance);
527+
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
528+
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
529+
bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None)
530+
} else {
531+
bx.get_static(def_id)
532+
};
521533
OperandRef { val: OperandValue::Immediate(static_), layout }
522534
}
523535
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),

compiler/rustc_const_eval/src/interpret/terminator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
383383
| ty::InstanceDef::DropGlue(..)
384384
| ty::InstanceDef::CloneShim(..)
385385
| ty::InstanceDef::FnPtrAddrShim(..)
386+
| ty::InstanceDef::ThreadLocalShim(..)
386387
| ty::InstanceDef::Item(_) => {
387388
// We need MIR for this fn
388389
let Some((body, instance)) =

compiler/rustc_middle/src/middle/exported_symbols.rs

+5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> {
4343
NonGeneric(DefId),
4444
Generic(DefId, SubstsRef<'tcx>),
4545
DropGlue(Ty<'tcx>),
46+
ThreadLocalShim(DefId),
4647
NoDefId(ty::SymbolName<'tcx>),
4748
}
4849

@@ -58,6 +59,10 @@ impl<'tcx> ExportedSymbol<'tcx> {
5859
ExportedSymbol::DropGlue(ty) => {
5960
tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty))
6061
}
62+
ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance {
63+
def: ty::InstanceDef::ThreadLocalShim(def_id),
64+
substs: ty::InternalSubsts::empty(),
65+
}),
6166
ExportedSymbol::NoDefId(symbol_name) => symbol_name,
6267
}
6368
}

compiler/rustc_middle/src/mir/mono.rs

+1
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ impl<'tcx> CodegenUnit<'tcx> {
382382
| InstanceDef::ClosureOnceShim { .. }
383383
| InstanceDef::DropGlue(..)
384384
| InstanceDef::CloneShim(..)
385+
| InstanceDef::ThreadLocalShim(..)
385386
| InstanceDef::FnPtrAddrShim(..) => None,
386387
}
387388
}

compiler/rustc_middle/src/mir/tcx.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,7 @@ impl<'tcx> Rvalue<'tcx> {
164164
Rvalue::Repeat(ref operand, count) => {
165165
tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count)
166166
}
167-
Rvalue::ThreadLocalRef(did) => {
168-
let static_ty = tcx.type_of(did).subst_identity();
169-
if tcx.is_mutable_static(did) {
170-
tcx.mk_mut_ptr(static_ty)
171-
} else if tcx.is_foreign_item(did) {
172-
tcx.mk_imm_ptr(static_ty)
173-
} else {
174-
// FIXME: These things don't *really* have 'static lifetime.
175-
tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
176-
}
177-
}
167+
Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
178168
Rvalue::Ref(reg, bk, ref place) => {
179169
let place_ty = place.ty(local_decls, tcx).ty;
180170
tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })

compiler/rustc_middle/src/mir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ macro_rules! make_mir_visitor {
335335
ty::InstanceDef::VTableShim(_def_id) |
336336
ty::InstanceDef::ReifyShim(_def_id) |
337337
ty::InstanceDef::Virtual(_def_id, _) |
338+
ty::InstanceDef::ThreadLocalShim(_def_id) |
338339
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
339340
ty::InstanceDef::DropGlue(_def_id, None) => {}
340341

compiler/rustc_middle/src/ty/instance.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ pub enum InstanceDef<'tcx> {
8282
/// The `DefId` is the ID of the `call_once` method in `FnOnce`.
8383
ClosureOnceShim { call_once: DefId, track_caller: bool },
8484

85+
/// Compiler-generated accessor for thread locals which returns a reference to the thread local
86+
/// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
87+
/// native support.
88+
ThreadLocalShim(DefId),
89+
8590
/// `core::ptr::drop_in_place::<T>`.
8691
///
8792
/// The `DefId` is for `core::ptr::drop_in_place`.
@@ -156,6 +161,7 @@ impl<'tcx> InstanceDef<'tcx> {
156161
| InstanceDef::FnPtrShim(def_id, _)
157162
| InstanceDef::Virtual(def_id, _)
158163
| InstanceDef::Intrinsic(def_id)
164+
| InstanceDef::ThreadLocalShim(def_id)
159165
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
160166
| InstanceDef::DropGlue(def_id, _)
161167
| InstanceDef::CloneShim(def_id, _)
@@ -167,7 +173,9 @@ impl<'tcx> InstanceDef<'tcx> {
167173
pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
168174
match self {
169175
ty::InstanceDef::Item(def) => Some(def.did),
170-
ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
176+
ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => {
177+
Some(def_id)
178+
}
171179
InstanceDef::VTableShim(..)
172180
| InstanceDef::ReifyShim(..)
173181
| InstanceDef::FnPtrShim(..)
@@ -192,6 +200,7 @@ impl<'tcx> InstanceDef<'tcx> {
192200
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
193201
| InstanceDef::DropGlue(def_id, _)
194202
| InstanceDef::CloneShim(def_id, _)
203+
| InstanceDef::ThreadLocalShim(def_id)
195204
| InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
196205
}
197206
}
@@ -215,6 +224,7 @@ impl<'tcx> InstanceDef<'tcx> {
215224
let def_id = match *self {
216225
ty::InstanceDef::Item(def) => def.did,
217226
ty::InstanceDef::DropGlue(_, Some(_)) => return false,
227+
ty::InstanceDef::ThreadLocalShim(_) => return false,
218228
_ => return true,
219229
};
220230
matches!(
@@ -255,6 +265,9 @@ impl<'tcx> InstanceDef<'tcx> {
255265
)
256266
});
257267
}
268+
if let ty::InstanceDef::ThreadLocalShim(..) = *self {
269+
return false;
270+
}
258271
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
259272
}
260273

@@ -278,6 +291,7 @@ impl<'tcx> InstanceDef<'tcx> {
278291
pub fn has_polymorphic_mir_body(&self) -> bool {
279292
match *self {
280293
InstanceDef::CloneShim(..)
294+
| InstanceDef::ThreadLocalShim(..)
281295
| InstanceDef::FnPtrAddrShim(..)
282296
| InstanceDef::FnPtrShim(..)
283297
| InstanceDef::DropGlue(_, Some(_)) => false,
@@ -310,6 +324,7 @@ fn fmt_instance(
310324
InstanceDef::Item(_) => Ok(()),
311325
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
312326
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
327+
InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
313328
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
314329
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
315330
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),

compiler/rustc_middle/src/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2386,6 +2386,7 @@ impl<'tcx> TyCtxt<'tcx> {
23862386
| ty::InstanceDef::ClosureOnceShim { .. }
23872387
| ty::InstanceDef::DropGlue(..)
23882388
| ty::InstanceDef::CloneShim(..)
2389+
| ty::InstanceDef::ThreadLocalShim(..)
23892390
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
23902391
}
23912392
}

compiler/rustc_middle/src/ty/util.rs

+22
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,28 @@ impl<'tcx> TyCtxt<'tcx> {
597597
self.static_mutability(def_id) == Some(hir::Mutability::Mut)
598598
}
599599

600+
/// Returns `true` if the item pointed to by `def_id` is a thread local which needs a
601+
/// thread local shim generated.
602+
#[inline]
603+
pub fn needs_thread_local_shim(self, def_id: DefId) -> bool {
604+
!self.sess.target.dll_tls_export
605+
&& self.is_thread_local_static(def_id)
606+
&& !self.is_foreign_item(def_id)
607+
}
608+
609+
/// Returns the type a reference to the thread local takes in MIR.
610+
pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
611+
let static_ty = self.type_of(def_id).subst_identity();
612+
if self.is_mutable_static(def_id) {
613+
self.mk_mut_ptr(static_ty)
614+
} else if self.is_foreign_item(def_id) {
615+
self.mk_imm_ptr(static_ty)
616+
} else {
617+
// FIXME: These things don't *really* have 'static lifetime.
618+
self.mk_imm_ref(self.lifetimes.re_static, static_ty)
619+
}
620+
}
621+
600622
/// Get the type of the pointer to the static that we use in MIR.
601623
pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
602624
// Make sure that any constants in the static's type are evaluated.

compiler/rustc_mir_transform/src/inline.rs

+1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ impl<'tcx> Inliner<'tcx> {
271271
| InstanceDef::ClosureOnceShim { .. }
272272
| InstanceDef::DropGlue(..)
273273
| InstanceDef::CloneShim(..)
274+
| InstanceDef::ThreadLocalShim(..)
274275
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
275276
}
276277

compiler/rustc_mir_transform/src/inline/cycle.rs

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
8383
| InstanceDef::ReifyShim(_)
8484
| InstanceDef::FnPtrShim(..)
8585
| InstanceDef::ClosureOnceShim { .. }
86+
| InstanceDef::ThreadLocalShim { .. }
8687
| InstanceDef::CloneShim(..) => {}
8788

8889
// This shim does not call any other functions, thus there can be no recursion.

compiler/rustc_mir_transform/src/shim.rs

+29
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
7676

7777
build_drop_shim(tcx, def_id, ty)
7878
}
79+
ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
7980
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
8081
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
8182
ty::InstanceDef::Virtual(..) => {
@@ -322,6 +323,34 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
322323
}
323324
}
324325

326+
fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> {
327+
let def_id = instance.def_id();
328+
329+
let span = tcx.def_span(def_id);
330+
let source_info = SourceInfo::outermost(span);
331+
332+
let mut blocks = IndexVec::with_capacity(1);
333+
blocks.push(BasicBlockData {
334+
statements: vec![Statement {
335+
source_info,
336+
kind: StatementKind::Assign(Box::new((
337+
Place::return_place(),
338+
Rvalue::ThreadLocalRef(def_id),
339+
))),
340+
}],
341+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
342+
is_cleanup: false,
343+
});
344+
345+
new_body(
346+
MirSource::from_instance(instance),
347+
blocks,
348+
IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
349+
0,
350+
span,
351+
)
352+
}
353+
325354
/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
326355
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
327356
debug!("build_clone_shim(def_id={:?})", def_id);

0 commit comments

Comments
 (0)