Skip to content

Commit

Permalink
Auto merge of #27338 - alexcrichton:remove-morestack, r=brson
Browse files Browse the repository at this point in the history
This commit removes all morestack support from the compiler which entails:

* Segmented stacks are no longer emitted in codegen.
* We no longer build or distribute libmorestack.a
* The `stack_exhausted` lang item is no longer required

The only current use of the segmented stack support in LLVM is to detect stack
overflow. This is no longer really required, however, because we already have
guard pages for all threads and registered signal handlers watching for a
segfault on those pages (to print out a stack overflow message). Additionally,
major platforms (aka Windows) already don't use morestack.

This means that Rust is by default less likely to catch stack overflows because
if a function takes up more than one page of stack space it won't hit the guard
page. This is what the purpose of morestack was (to catch this case), but it's
better served with stack probes which have more cross platform support and no
runtime support necessary. Until LLVM supports this for all platform it looks
like morestack isn't really buying us much.

cc #16012 (still need stack probes)
Closes #26458 (a drive-by fix to help diagnostics on stack overflow)

r? @brson
  • Loading branch information
bors committed Aug 10, 2015
2 parents 75383ea + 7a3fdfb commit 5aca49c
Show file tree
Hide file tree
Showing 73 changed files with 147 additions and 1,673 deletions.
1 change: 0 additions & 1 deletion mk/clean.mk
Expand Up @@ -101,7 +101,6 @@ define CLEAN_TARGET_STAGE_N
clean$(1)_T_$(2)_H_$(3): \
$$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
Expand Down
2 changes: 1 addition & 1 deletion mk/crates.mk
Expand Up @@ -65,7 +65,7 @@ DEPS_libc := core
DEPS_rustc_unicode := core
DEPS_alloc := core libc native:jemalloc
DEPS_std := core libc rand alloc collections rustc_unicode \
native:rust_builtin native:backtrace native:rustrt_native \
native:rust_builtin native:backtrace \
rustc_bitflags
DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc
Expand Down
7 changes: 6 additions & 1 deletion mk/main.mk
Expand Up @@ -163,7 +163,7 @@ endif
# that the snapshot will be generated with a statically linked rustc so we only
# have to worry about the distribution of one file (with its native dynamic
# dependencies)
RUSTFLAGS_STAGE0 += -C prefer-dynamic
RUSTFLAGS_STAGE0 += -C prefer-dynamic -C no-stack-check
RUSTFLAGS_STAGE1 += -C prefer-dynamic
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic
RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
Expand Down Expand Up @@ -400,6 +400,11 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
$$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))

ifeq ($(1),0)
TSREQ$(1)_T_$(2)_H_$(3) += \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),morestack)
endif

# Prerequisites for a working stageN compiler and libraries, for a specific
# target
SREQ$(1)_T_$(2)_H_$(3) = \
Expand Down
3 changes: 1 addition & 2 deletions mk/platform.mk
Expand Up @@ -113,8 +113,7 @@ CFG_RLIB_GLOB=lib$(1)-*.rlib
include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)

define ADD_INSTALLED_OBJECTS
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),morestack) \
$$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
endef

$(foreach target,$(CFG_TARGET), \
Expand Down
8 changes: 3 additions & 5 deletions mk/rt.mk
Expand Up @@ -35,8 +35,8 @@
# that's per-target so you're allowed to conditionally add files based on the
# target.
################################################################################
NATIVE_LIBS := rust_builtin hoedown morestack miniz \
rustrt_native rust_test_helpers
NATIVE_LIBS := rust_builtin hoedown miniz \
rust_test_helpers morestack

# $(1) is the target triple
define NATIVE_LIBRARIES
Expand All @@ -53,10 +53,8 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
NATIVE_DEPS_miniz_$(1) = miniz.c
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
rust_android_dummy.c
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S

NATIVE_DEPS_morestack_$(1) := empty.c

################################################################################
# You shouldn't find it that necessary to edit anything below this line.
Expand Down
3 changes: 1 addition & 2 deletions mk/target.mk
Expand Up @@ -56,8 +56,7 @@ $(foreach host,$(CFG_HOST), \
# 1. The immediate dependencies are the rust source files
# 2. Each rust crate dependency is listed (based on their stamp files),
# as well as all native dependencies (listed in RT_OUTPUT_DIR)
# 3. The stage (n-1) compiler is required through the TSREQ dependency, along
# with the morestack library
# 3. The stage (n-1) compiler is required through the TSREQ dependency
# 4. When actually executing the rule, the first thing we do is to clean out
# old libs and rlibs via the REMOVE_ALL_OLD_GLOB_MATCHES macro
# 5. Finally, we get around to building the actual crate. It's just one
Expand Down
1 change: 0 additions & 1 deletion src/doc/trpl/lang-items.md
Expand Up @@ -51,7 +51,6 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
0
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
Expand Down
13 changes: 2 additions & 11 deletions src/doc/trpl/no-stdlib.md
Expand Up @@ -36,7 +36,6 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
Expand All @@ -61,7 +60,6 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
0
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
Expand All @@ -73,18 +71,12 @@ The compiler currently makes a few assumptions about symbols which are available
in the executable to call. Normally these functions are provided by the standard
library, but without it you must define your own.

The first of these three functions, `stack_exhausted`, is invoked whenever stack
overflow is detected. This function has a number of restrictions about how it
can be called and what it must do, but if the stack limit register is not being
maintained then a thread always has an "infinite stack" and this function
shouldn't get triggered.

The second of these three functions, `eh_personality`, is used by the
The first of these two functions, `eh_personality`, is used by the
failure mechanisms of the compiler. This is often mapped to GCC's
personality function (see the
[libstd implementation](../std/rt/unwind/index.html) for more
information), but crates which do not trigger a panic can be assured
that this function is never called. The final function, `panic_fmt`, is
that this function is never called. The second function, `panic_fmt`, is
also used by the failure mechanisms of the compiler.

## Using libcore
Expand Down Expand Up @@ -150,7 +142,6 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
loop {}
}
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
Expand Down
2 changes: 0 additions & 2 deletions src/librustc/middle/lang_items.rs
Expand Up @@ -347,7 +347,5 @@ lets_do_this! {

NonZeroItem, "non_zero", non_zero;

StackExhaustedLangItem, "stack_exhausted", stack_exhausted;

DebugTraitLangItem, "debug_trait", debug_trait;
}
4 changes: 0 additions & 4 deletions src/librustc/middle/weak_lang_items.rs
Expand Up @@ -39,9 +39,6 @@ pub fn check_crate(krate: &ast::Crate,
// These are never called by user code, they're generated by the compiler.
// They will never implicitly be added to the `missing` array unless we do
// so here.
if items.stack_exhausted().is_none() {
items.missing.push(lang_items::StackExhaustedLangItem);
}
if items.eh_personality().is_none() {
items.missing.push(lang_items::EhPersonalityLangItem);
}
Expand Down Expand Up @@ -124,7 +121,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {

weak_lang_items! {
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
}
1 change: 0 additions & 1 deletion src/librustc_back/target/apple_base.rs
Expand Up @@ -19,7 +19,6 @@ pub fn opts() -> TargetOptions {
dynamic_linking: true,
executables: true,
is_like_osx: true,
morestack: true,
has_rpath: true,
dll_prefix: "lib".to_string(),
dll_suffix: ".dylib".to_string(),
Expand Down
8 changes: 0 additions & 8 deletions src/librustc_back/target/apple_ios_base.rs
Expand Up @@ -87,14 +87,6 @@ pub fn opts(arch: Arch) -> TargetOptions {
cpu: target_cpu(arch),
dynamic_linking: false,
executables: true,
// Although there is an experimental implementation of LLVM which
// supports SS on armv7 it wasn't approved by Apple, see:
// http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
// It looks like it might be never accepted to upstream LLVM.
//
// SS might be also enabled on Arm64 as it has builtin support in LLVM
// but I haven't tested it through yet
morestack: false,
pre_link_args: pre_link_args(arch),
.. super::apple_base::opts()
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/bitrig_base.rs
Expand Up @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: false,
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/dragonfly_base.rs
Expand Up @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: true,
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec!(
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/freebsd_base.rs
Expand Up @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: true,
has_rpath: true,
archive_format: "gnu".to_string(),

Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/i686_unknown_freebsd.rs
Expand Up @@ -14,7 +14,6 @@ pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "pentium4".to_string();
base.pre_link_args.push("-m32".to_string());
base.morestack = false;

Target {
llvm_target: "i686-unknown-freebsd".to_string(),
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/linux_base.rs
Expand Up @@ -15,7 +15,6 @@ pub fn opts() -> TargetOptions {
TargetOptions {
dynamic_linking: true,
executables: true,
morestack: true,
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_back/target/mod.rs
Expand Up @@ -118,9 +118,6 @@ pub struct TargetOptions {
/// Whether executables are available on this target. iOS, for example, only allows static
/// libraries. Defaults to false.
pub executables: bool,
/// Whether LLVM's segmented stack prelude is supported by whatever runtime is available.
/// Will emit stack checks and calls to __morestack. Defaults to false.
pub morestack: bool,
/// Relocation model to use in object file. Corresponds to `llc
/// -relocation-model=$relocation_model`. Defaults to "pic".
pub relocation_model: String,
Expand Down Expand Up @@ -192,7 +189,6 @@ impl Default for TargetOptions {
features: "".to_string(),
dynamic_linking: false,
executables: false,
morestack: false,
relocation_model: "pic".to_string(),
code_model: "default".to_string(),
disable_redzone: false,
Expand Down Expand Up @@ -298,7 +294,6 @@ impl Target {
key!(data_layout);
key!(dynamic_linking, bool);
key!(executables, bool);
key!(morestack, bool);
key!(disable_redzone, bool);
key!(eliminate_frame_pointer, bool);
key!(function_sections, bool);
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/netbsd_base.rs
Expand Up @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: false,
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec!(
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/openbsd_base.rs
Expand Up @@ -16,7 +16,6 @@ pub fn opts() -> TargetOptions {
linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: false,
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec!(
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/windows_base.rs
Expand Up @@ -23,7 +23,6 @@ pub fn opts() -> TargetOptions {
exe_suffix: ".exe".to_string(),
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
morestack: false,
is_like_windows: true,
archive_format: "gnu".to_string(),
pre_link_args: vec!(
Expand Down
1 change: 0 additions & 1 deletion src/librustc_back/target/windows_msvc_base.rs
Expand Up @@ -53,7 +53,6 @@ pub fn opts() -> TargetOptions {
exe_suffix: ".exe".to_string(),
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
morestack: false,
is_like_windows: true,
is_like_msvc: true,
pre_link_args: vec![
Expand Down
23 changes: 0 additions & 23 deletions src/librustc_trans/back/link.rs
Expand Up @@ -759,9 +759,6 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
if sess.target.target.options.is_like_osx && !ab.using_llvm() {
ab.build();
}
if sess.target.target.options.morestack {
ab.add_native_library("morestack").unwrap();
}
if !sess.target.target.options.no_compiler_rt {
ab.add_native_library("compiler-rt").unwrap();
}
Expand Down Expand Up @@ -905,26 +902,6 @@ fn link_args(cmd: &mut Linker,
}
cmd.output_filename(out_filename);

// Stack growth requires statically linking a __morestack function. Note
// that this is listed *before* all other libraries. Due to the usage of the
// --as-needed flag below, the standard library may only be useful for its
// rust_stack_exhausted function. In this case, we must ensure that the
// libmorestack.a file appears *before* the standard library (so we put it
// at the very front).
//
// Most of the time this is sufficient, except for when LLVM gets super
// clever. If, for example, we have a main function `fn main() {}`, LLVM
// will optimize out calls to `__morestack` entirely because the function
// doesn't need any stack at all!
//
// To get around this snag, we specially tell the linker to always include
// all contents of this library. This way we're guaranteed that the linker
// will include the __morestack symbol 100% of the time, always resolving
// references to it even if the object above didn't use it.
if t.options.morestack {
cmd.link_whole_staticlib("morestack", &[lib_path]);
}

// When linking a dynamic library, we put the metadata into a section of the
// executable. This metadata is in a separate object file from the main
// object file, so we link that in here.
Expand Down
17 changes: 1 addition & 16 deletions src/librustc_trans/trans/attributes.rs
Expand Up @@ -23,19 +23,6 @@ use trans::context::CrateContext;
use trans::machine;
use trans::type_of;

/// Mark LLVM function to use split stack.
#[inline]
pub fn split_stack(val: ValueRef, set: bool) {
unsafe {
let attr = "split-stack\0".as_ptr() as *const _;
if set {
llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr);
} else {
llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr);
}
}
}

/// Mark LLVM function to use provided inline heuristic.
#[inline]
pub fn inline(val: ValueRef, inline: InlineAttr) {
Expand Down Expand Up @@ -123,9 +110,7 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
}

for attr in attrs {
if attr.check_name("no_stack_check") {
split_stack(llfn, false);
} else if attr.check_name("cold") {
if attr.check_name("cold") {
unsafe {
llvm::LLVMAddFunctionAttribute(llfn,
llvm::FunctionIndex as c_uint,
Expand Down
18 changes: 2 additions & 16 deletions src/librustc_trans/trans/base.rs
Expand Up @@ -2166,17 +2166,8 @@ fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
llfn: ValueRef) {
ccx.item_symbols().borrow_mut().insert(node_id, sym);

// The stack exhaustion lang item shouldn't have a split stack because
// otherwise it would continue to be exhausted (bad), and both it and the
// eh_personality functions need to be externally linkable.
// The eh_personality function need to be externally linkable.
let def = ast_util::local_def(node_id);
if ccx.tcx().lang_items.stack_exhausted() == Some(def) {
attributes::split_stack(llfn, false);
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
if ccx.use_dll_storage_attrs() {
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
}
}
if ccx.tcx().lang_items.eh_personality() == Some(def) {
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
if ccx.use_dll_storage_attrs() {
Expand Down Expand Up @@ -2794,13 +2785,8 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
});

// Make sure that some other crucial symbols are not eliminated from the
// module. This includes the main function, the crate map (used for debug
// log settings and I/O), and finally the curious rust_stack_exhausted
// symbol. This symbol is required for use by the libmorestack library that
// we link in, so we must ensure that this symbol is not internalized (if
// defined in the crate).
// module, including the main function.
reachable.push("main".to_string());
reachable.push("rust_stack_exhausted".to_string());

// referenced from .eh_frame section on some platforms
reachable.push("rust_eh_personality".to_string());
Expand Down
5 changes: 0 additions & 5 deletions src/librustc_trans/trans/context.rs
Expand Up @@ -570,11 +570,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
}
}

pub fn is_split_stack_supported(&self) -> bool {
self.sess().target.target.options.morestack
}


pub fn llmod(&self) -> ModuleRef {
self.local.llmod
}
Expand Down

0 comments on commit 5aca49c

Please sign in to comment.