Skip to content

Improve ELF TLS detection on OSX #30417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 22, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
rustc: Add feature-gated cfg(target_thread_local)
Currently the standard library has some pretty complicated logic to detect
whether #[thread_local] should be used or whether it's supported. This is also
unfortunately not quite true for OSX where not all versions support
the #[thread_local] attribute (only 10.7+ does). Compiling code for OSX 10.6 is
typically requested via the MACOSX_DEPLOYMENT_TARGET environment variable (e.g.
the linker recognizes this), but the standard library unfortunately does not
respect this.

This commit updates the compiler to add a `target_thread_local` cfg annotation
if the platform being targeted supports the `#[thread_local]` attribute. This is
feature gated for now, and it is only true on non-aarch64 Linux and 10.7+ OSX
(e.g. what the module already does today). Logic has also been added to parse
the deployment target environment variable.
  • Loading branch information
alexcrichton committed Dec 22, 2015
commit b67b5a8d0149096712e75336f6aa32daffcaa42d
3 changes: 3 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
"windows" | "unix" => ret.push(attr::mk_word_item(fam)),
_ => (),
}
if sess.target.target.options.has_elf_tls {
ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
}
if sess.opts.debug_assertions {
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_back/target/aarch64_unknown_linux_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
use target::Target;

pub fn target() -> Target {
let base = super::linux_base::opts();
let mut base = super::linux_base::opts();
base.has_elf_tls = false;
Target {
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
Expand Down
23 changes: 22 additions & 1 deletion src/librustc_back/target/apple_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,30 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;

use target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
// ELF TLS is only available in OSX 10.7+. If you try to compile for 10.6
// either the linker will complain if it is used or the binary will end up
// segfaulting at runtime when run on 10.6. Rust by default supports OSX
// 10.7+, but there is a standard environment variable,
// MACOSX_DEPLOYMENT_TARGET, which is used to signal targeting older
// versions of OSX. For example compiling on 10.10 with
// MACOSX_DEPLOYMENT_TARGET set to 10.6 will cause the linker to generate
// warnings about the usage of ELF TLS.
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
// TLS is flagged as enabled if it looks to be supported.
let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
let version = deployment_target.as_ref().and_then(|s| {
let mut i = s.splitn(2, ".");
i.next().and_then(|a| i.next().map(|b| (a, b)))
}).and_then(|(a, b)| {
a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok()
}).unwrap_or((10, 7));

TargetOptions {
// OSX has -dead_strip, which doesn't rely on ffunction_sections
function_sections: false,
Expand All @@ -25,6 +45,7 @@ pub fn opts() -> TargetOptions {
archive_format: "bsd".to_string(),
pre_link_args: Vec::new(),
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: version >= (10, 7),
.. Default::default()
}
}
1 change: 1 addition & 0 deletions src/librustc_back/target/apple_ios_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub fn opts(arch: Arch) -> TargetOptions {
dynamic_linking: false,
executables: true,
pre_link_args: pre_link_args(arch),
has_elf_tls: false,
.. super::apple_base::opts()
}
}
1 change: 1 addition & 0 deletions src/librustc_back/target/arm_linux_androideabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use target::Target;
pub fn target() -> Target {
let mut base = super::android_base::opts();
base.features = "+v7".to_string();
base.has_elf_tls = false;

Target {
llvm_target: "arm-linux-androideabi".to_string(),
Expand Down
1 change: 1 addition & 0 deletions src/librustc_back/target/linux_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn opts() -> TargetOptions {
position_independent_executables: true,
archive_format: "gnu".to_string(),
exe_allocation_crate: super::maybe_jemalloc(),
has_elf_tls: true,
.. Default::default()
}
}
5 changes: 5 additions & 0 deletions src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ pub struct TargetOptions {
/// Default crate for allocation symbols to link against
pub lib_allocation_crate: String,
pub exe_allocation_crate: String,

/// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
/// this target.
pub has_elf_tls: bool,
}

impl Default for TargetOptions {
Expand Down Expand Up @@ -240,6 +244,7 @@ impl Default for TargetOptions {
lib_allocation_crate: "alloc_system".to_string(),
exe_allocation_crate: "alloc_system".to_string(),
allow_asm: true,
has_elf_tls: false,
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status

// allow using type ascription in expressions
("type_ascription", "1.6.0", Some(23416), Active),

// Allows cfg(target_thread_local)
("cfg_target_thread_local", "1.7.0", Some(26581), Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)

Expand Down Expand Up @@ -414,6 +417,8 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)]
// (name in cfg, feature, function to check if the feature is enabled)
("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
("target_thread_local", "cfg_target_thread_local",
cfg_fn!(|x| x.cfg_target_thread_local)),
];

#[derive(Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -541,6 +546,7 @@ pub struct Features {
pub type_macros: bool,
pub cfg_target_feature: bool,
pub cfg_target_vendor: bool,
pub cfg_target_thread_local: bool,
pub augmented_assignments: bool,
pub braced_empty_structs: bool,
pub staged_api: bool,
Expand Down Expand Up @@ -575,6 +581,7 @@ impl Features {
type_macros: false,
cfg_target_feature: false,
cfg_target_vendor: false,
cfg_target_thread_local: false,
augmented_assignments: false,
braced_empty_structs: false,
staged_api: false,
Expand Down Expand Up @@ -1157,6 +1164,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
type_macros: cx.has_feature("type_macros"),
cfg_target_feature: cx.has_feature("cfg_target_feature"),
cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
cfg_target_thread_local: cx.has_feature("cfg_target_thread_local"),
augmented_assignments: cx.has_feature("augmented_assignments"),
braced_empty_structs: cx.has_feature("braced_empty_structs"),
staged_api: cx.has_feature("staged_api"),
Expand Down