Skip to content

Commit 608f324

Browse files
committed
Auto merge of #117873 - quininer:android-emutls, r=Amanieu
Add emulated TLS support This is a reopen of #96317 . many android devices still only use 128 pthread keys, so using emutls can be helpful. Currently LLVM uses emutls by default for some targets (such as android, openbsd), but rust does not use it, because `has_thread_local` is false. This commit has some changes to allow users to enable emutls: 1. add `-Zhas-thread-local` flag to specify that std uses `#[thread_local]` instead of pthread key. 2. when using emutls, decorate symbol names to find thread local symbol correctly. 3. change `-Zforce-emulated-tls` to `-Ztls-model=emulated` to explicitly specify whether to generate emutls. r? `@Amanieu`
2 parents 1a3aa4a + e5b7689 commit 608f324

File tree

17 files changed

+71
-28
lines changed

17 files changed

+71
-28
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())
@@ -564,6 +564,12 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
564564

565565
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
566566

567+
// thread local will not be a function call,
568+
// so it is safe to return before windows symbol decoration check.
569+
if let Some(name) = maybe_emutls_symbol_name(tcx, symbol, &undecorated) {
570+
return name;
571+
}
572+
567573
let target = &tcx.sess.target;
568574
if !target.is_like_windows {
569575
// Mach-O has a global "_" suffix and `object` crate will handle it.
@@ -624,6 +630,32 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
624630
format!("{prefix}{undecorated}{suffix}{args_in_bytes}")
625631
}
626632

633+
pub fn exporting_symbol_name_for_instance_in_crate<'tcx>(
634+
tcx: TyCtxt<'tcx>,
635+
symbol: ExportedSymbol<'tcx>,
636+
cnum: CrateNum,
637+
) -> String {
638+
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, cnum);
639+
maybe_emutls_symbol_name(tcx, symbol, &undecorated).unwrap_or(undecorated)
640+
}
641+
642+
fn maybe_emutls_symbol_name<'tcx>(
643+
tcx: TyCtxt<'tcx>,
644+
symbol: ExportedSymbol<'tcx>,
645+
undecorated: &str,
646+
) -> Option<String> {
647+
if matches!(tcx.sess.tls_model(), TlsModel::Emulated)
648+
&& let ExportedSymbol::NonGeneric(def_id) = symbol
649+
&& tcx.is_thread_local_static(def_id)
650+
{
651+
// When using emutls, LLVM will add the `__emutls_v.` prefix to thread local symbols,
652+
// and exported symbol name need to match this.
653+
Some(format!("__emutls_v.{undecorated}"))
654+
} else {
655+
None
656+
}
657+
}
658+
627659
fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> {
628660
// Build up a map from DefId to a `NativeLib` structure, where
629661
// `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/base/openbsd.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{cvs, FramePointer, RelroLevel, TargetOptions};
1+
use crate::spec::{cvs, FramePointer, RelroLevel, TargetOptions, TlsModel};
22

33
pub fn opts() -> TargetOptions {
44
TargetOptions {
@@ -11,6 +11,7 @@ pub fn opts() -> TargetOptions {
1111
frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
1212
relro_level: RelroLevel::Full,
1313
default_dwarf_version: 2,
14+
tls_model: TlsModel::Emulated,
1415
..Default::default()
1516
}
1617
}

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
}
@@ -2191,9 +2194,6 @@ pub struct TargetOptions {
21912194

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

21992199
/// Add arguments for the given flavor and also for its "twin" flavors
@@ -2409,7 +2409,6 @@ impl Default for TargetOptions {
24092409
entry_name: "main".into(),
24102410
entry_abi: Conv::C,
24112411
supports_xray: false,
2412-
force_emulated_tls: false,
24132412
}
24142413
}
24152414
}
@@ -3113,7 +3112,6 @@ impl Target {
31133112
key!(entry_name);
31143113
key!(entry_abi, Conv)?;
31153114
key!(supports_xray, bool);
3116-
key!(force_emulated_tls, bool);
31173115

31183116
if base.is_builtin {
31193117
// This can cause unfortunate ICEs later down the line.
@@ -3369,7 +3367,6 @@ impl ToJson for Target {
33693367
target_option_val!(entry_name);
33703368
target_option_val!(entry_abi);
33713369
target_option_val!(supports_xray);
3372-
target_option_val!(force_emulated_tls);
33733370

33743371
if let Some(abi) = self.default_adjusted_cabi {
33753372
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)