Skip to content

Commit b906b7d

Browse files
committed
Add emulated TLS support
1 parent 8b6a4a9 commit b906b7d

File tree

16 files changed

+69
-27
lines changed

16 files changed

+69
-27
lines changed

compiler/rustc_codegen_gcc/src/context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -569,5 +569,6 @@ fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
569569
TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
570570
TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
571571
TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
572+
TlsModel::Emulated => gccjit::TlsModel::GlobalDynamic,
572573
}
573574
}

compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl OwnedTargetMachine {
3939
split_dwarf_file: &CStr,
4040
output_obj_file: &CStr,
4141
debug_info_compression: &CStr,
42-
force_emulated_tls: bool,
42+
use_emulated_tls: bool,
4343
args_cstr_buff: &[u8],
4444
) -> Result<Self, LlvmError<'static>> {
4545
assert!(args_cstr_buff.len() > 0);
@@ -71,7 +71,7 @@ impl OwnedTargetMachine {
7171
split_dwarf_file.as_ptr(),
7272
output_obj_file.as_ptr(),
7373
debug_info_compression.as_ptr(),
74-
force_emulated_tls,
74+
use_emulated_tls,
7575
args_cstr_buff.as_ptr() as *const c_char,
7676
args_cstr_buff.len(),
7777
)

compiler/rustc_codegen_llvm/src/back/write.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, Switc
3333
use rustc_session::Session;
3434
use rustc_span::symbol::sym;
3535
use rustc_span::InnerSpan;
36-
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
36+
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
3737

3838
use crate::llvm::diagnostic::OptimizationDiagnosticKind;
3939
use libc::{c_char, c_int, c_uint, c_void, size_t};
@@ -223,7 +223,7 @@ pub fn target_machine_factory(
223223

224224
let path_mapping = sess.source_map().path_mapping().clone();
225225

226-
let force_emulated_tls = sess.target.force_emulated_tls;
226+
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
227227

228228
// copy the exe path, followed by path all into one buffer
229229
// null terminating them so we can use them as null terminated strings
@@ -297,7 +297,7 @@ pub fn target_machine_factory(
297297
&split_dwarf_file,
298298
&output_obj_file,
299299
&debuginfo_compression,
300-
force_emulated_tls,
300+
use_emulated_tls,
301301
&args_cstr_buff,
302302
)
303303
})

compiler/rustc_codegen_llvm/src/context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
120120
TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic,
121121
TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec,
122122
TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec,
123+
TlsModel::Emulated => llvm::ThreadLocalMode::GeneralDynamic,
123124
}
124125
}
125126

compiler/rustc_codegen_llvm/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ impl CodegenBackend for LlvmCodegenBackend {
306306
}
307307
PrintKind::TlsModels => {
308308
writeln!(out, "Available TLS models:");
309-
for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
309+
for name in
310+
&["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"]
311+
{
310312
writeln!(out, " {name}");
311313
}
312314
writeln!(out);

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,7 @@ extern "C" {
21592159
SplitDwarfFile: *const c_char,
21602160
OutputObjFile: *const c_char,
21612161
DebugInfoCompression: *const c_char,
2162-
ForceEmulatedTls: bool,
2162+
UseEmulatedTls: bool,
21632163
ArgsCstrBuff: *const c_char,
21642164
ArgsCstrBuffLen: usize,
21652165
) -> *mut TargetMachine;

compiler/rustc_codegen_ssa/src/back/linker.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
17481748
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
17491749
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
17501750
if info.level.is_below_threshold(export_threshold) {
1751-
symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
1751+
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1752+
tcx, symbol, cnum,
1753+
));
17521754
}
17531755
});
17541756

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
1616
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
1717
use rustc_middle::util::Providers;
1818
use rustc_session::config::{CrateType, OomStrategy};
19-
use rustc_target::spec::SanitizerSet;
19+
use rustc_target::spec::{SanitizerSet, TlsModel};
2020

2121
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
2222
crates_export_threshold(tcx.crate_types())
@@ -552,6 +552,12 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
552552

553553
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
554554

555+
// thread local will not be a function call,
556+
// so it is safe to return before windows symbol decoration check.
557+
if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) {
558+
return name;
559+
}
560+
555561
let target = &tcx.sess.target;
556562
if !target.is_like_windows {
557563
// Mach-O has a global "_" suffix and `object` crate will handle it.
@@ -612,6 +618,32 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
612618
format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
613619
}
614620

621+
pub fn exporting_symbol_name_for_instance_in_crate<'tcx>(
622+
tcx: TyCtxt<'tcx>,
623+
symbol: ExportedSymbol<'tcx>,
624+
cnum: CrateNum,
625+
) -> String {
626+
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum);
627+
maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
628+
}
629+
630+
fn maybe_emutls_symbol_name<'tcx>(
631+
tcx: TyCtxt<'tcx>,
632+
symbol: ExportedSymbol<'tcx>,
633+
undecorated: &str,
634+
) -> Option<String> {
635+
if matches!(tcx.sess.tls_model(), TlsModel::Emulated)
636+
&& let ExportedSymbol::NonGeneric(def_id) = symbol
637+
&& tcx.is_thread_local_static(def_id)
638+
{
639+
// When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols,
640+
// and exported symbol name need to match this.
641+
Some(format!("__emutls_v.{undecorated}"))
642+
} else {
643+
None
644+
}
645+
}
646+
615647
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
616648
// Build up a map from DefId to a `NativeLib` structure, where
617649
// `NativeLib` internally contains information about

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+3-7
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
410410
const char *SplitDwarfFile,
411411
const char *OutputObjFile,
412412
const char *DebugInfoCompression,
413-
bool ForceEmulatedTls,
413+
bool UseEmulatedTls,
414414
const char *ArgsCstrBuff, size_t ArgsCstrBuffLen) {
415415

416416
auto OptLevel = fromRust(RustOptLevel);
@@ -456,13 +456,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
456456
Options.UseInitArray = UseInitArray;
457457

458458
#if LLVM_VERSION_LT(17, 0)
459-
if (ForceEmulatedTls) {
460-
Options.ExplicitEmulatedTLS = true;
461-
Options.EmulatedTLS = true;
462-
}
463-
#else
464-
Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS();
459+
Options.ExplicitEmulatedTLS = true;
465460
#endif
461+
Options.EmulatedTLS = UseEmulatedTls;
466462

467463
if (TrapUnreachable) {
468464
// Tell LLVM to codegen `unreachable` into an explicit trap instruction.

compiler/rustc_session/src/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ fn default_configuration(sess: &Session) -> Cfg {
12831283
ret.insert((sym::relocation_model, Some(relocation_model)));
12841284
}
12851285
ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
1286-
if sess.target.has_thread_local {
1286+
if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) {
12871287
ret.insert((sym::target_thread_local, None));
12881288
}
12891289
let mut has_atomic = false;

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,8 @@ options! {
16241624
graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
16251625
"use the given `fontname` in graphviz output; can be overridden by setting \
16261626
environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
1627+
has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
1628+
"explicitly enable the `cfg(target_thread_local)` directive"),
16271629
hir_stats: bool = (false, parse_bool, [UNTRACKED],
16281630
"print some statistics about AST and HIR (default: no)"),
16291631
human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],

compiler/rustc_target/src/spec/base/android.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use crate::spec::{base, SanitizerSet, TargetOptions};
1+
use crate::spec::{base, SanitizerSet, TargetOptions, TlsModel};
22

33
pub fn opts() -> TargetOptions {
44
let mut base = base::linux::opts();
55
base.os = "android".into();
66
base.is_like_android = true;
77
base.default_dwarf_version = 2;
8+
base.tls_model = TlsModel::Emulated;
89
base.has_thread_local = false;
910
base.supported_sanitizers = SanitizerSet::ADDRESS;
1011
// This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867

compiler/rustc_target/src/spec/base/linux_ohos.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use crate::spec::{base, TargetOptions};
1+
use crate::spec::{base, TargetOptions, TlsModel};
22

33
pub fn opts() -> TargetOptions {
44
let mut base = base::linux::opts();
55

66
base.env = "ohos".into();
77
base.crt_static_default = false;
8-
base.force_emulated_tls = true;
8+
base.tls_model = TlsModel::Emulated;
99
base.has_thread_local = false;
1010

1111
base

compiler/rustc_target/src/spec/mod.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ pub enum TlsModel {
929929
LocalDynamic,
930930
InitialExec,
931931
LocalExec,
932+
Emulated,
932933
}
933934

934935
impl FromStr for TlsModel {
@@ -942,6 +943,7 @@ impl FromStr for TlsModel {
942943
"local-dynamic" => TlsModel::LocalDynamic,
943944
"initial-exec" => TlsModel::InitialExec,
944945
"local-exec" => TlsModel::LocalExec,
946+
"emulated" => TlsModel::Emulated,
945947
_ => return Err(()),
946948
})
947949
}
@@ -954,6 +956,7 @@ impl ToJson for TlsModel {
954956
TlsModel::LocalDynamic => "local-dynamic",
955957
TlsModel::InitialExec => "initial-exec",
956958
TlsModel::LocalExec => "local-exec",
959+
TlsModel::Emulated => "emulated",
957960
}
958961
.to_json()
959962
}
@@ -2190,9 +2193,6 @@ pub struct TargetOptions {
21902193

21912194
/// Whether the target supports XRay instrumentation.
21922195
pub supports_xray: bool,
2193-
2194-
/// Forces the use of emulated TLS (__emutls_get_address)
2195-
pub force_emulated_tls: bool,
21962196
}
21972197

21982198
/// Add arguments for the given flavor and also for its "twin" flavors
@@ -2408,7 +2408,6 @@ impl Default for TargetOptions {
24082408
entry_name: "main".into(),
24092409
entry_abi: Conv::C,
24102410
supports_xray: false,
2411-
force_emulated_tls: false,
24122411
}
24132412
}
24142413
}
@@ -3112,7 +3111,6 @@ impl Target {
31123111
key!(entry_name);
31133112
key!(entry_abi, Conv)?;
31143113
key!(supports_xray, bool);
3115-
key!(force_emulated_tls, bool);
31163114

31173115
if base.is_builtin {
31183116
// This can cause unfortunate ICEs later down the line.
@@ -3368,7 +3366,6 @@ impl ToJson for Target {
33683366
target_option_val!(entry_name);
33693367
target_option_val!(entry_abi);
33703368
target_option_val!(supports_xray);
3371-
target_option_val!(force_emulated_tls);
33723369

33733370
if let Some(abi) = self.default_adjusted_cabi {
33743371
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());

library/std/src/sys/unix/thread_local_dtor.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
// compiling from a newer linux to an older linux, so we also have a
1313
// fallback implementation to use as well.
1414
#[allow(unexpected_cfgs)]
15-
#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))]
15+
#[cfg(any(
16+
target_os = "linux",
17+
target_os = "android",
18+
target_os = "fuchsia",
19+
target_os = "redox",
20+
target_os = "hurd"
21+
))]
1622
// FIXME: The Rust compiler currently omits weakly function definitions (i.e.,
1723
// __cxa_thread_atexit_impl) and its metadata from LLVM IR.
1824
#[no_sanitize(cfi, kcfi)]

src/doc/unstable-book/src/compiler-flags/tls-model.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ loaded at program startup.
2020
The TLS data must not be in a library loaded after startup (via `dlopen`).
2121
- `local-exec` - model usable only if the TLS data is defined directly in the executable,
2222
but not in a shared library, and is accessed only from that executable.
23+
- `emulated` - Uses thread-specific data keys to implement emulated TLS.
24+
It is like using a general-dynamic TLS model for all modes.
2325

2426
`rustc` and LLVM may use a more optimized model than specified if they know that we are producing
2527
an executable rather than a library, or that the `static` item is private enough.

0 commit comments

Comments
 (0)