From 0487292ad902483d38e4335f6d6054be98e32036 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 Jan 2016 19:45:59 -0800 Subject: [PATCH] std: Move pc-windows-gnu to SEH-based unwinding This commit moves the `*-pc-windows-gnu` targets (e.g. the MinGW targets) to use SEH-based unwinding instead of libunwind-based unwinding. There are a number of ramifications on these targets as a result: * Binary distributions of the standard library are no longer tied to a particular compiler toolchain. The MinGW toolchains typically ship with either SEH, Dwarf, or SjLj based unwinding and are binary-incompatible, but with SEH unwinding we'll be able to link with any of the toolchains. * The GNU implementation is now much closer to the MSVC implementation, reducing the amount of duplicated code we'll have to maintain (yay!). * Due to the loss of the libunwind stack unwinder the libbacktrace library is no longer used on Windows. The same unwinding code for MSVC is now used for GNU as well, and unfortunately this has empirically led to worse stack traces in the past. In theory, though, this should be fixed for both MSVC and GNU at the same time! * Due to the lack of a need for frame unwind info registration, the `rsend.o` and `rsbegin.o` startup object files are no longer built. Additionally the `crt2.o` and `dllcrt2.o` files are no longer distributed. It's assumed that the linker in use will inject these as usual. The `-nostdlib` flag is no longer passed to the linker to indicate this. This change also opened up the possibility to reorganize a few modules, so the following changes were also made: * The `custom_unwind_resume` option and all support code was removed from trans as this is no longer necessary. * The `sys_common::unwind` module was refactored to have the platform-specific portions live in `sys::unwind`. * A similar refactoring was applied to backtrace writing (just shuffling some files around). * Documentation was updated in shuffled modules to reflect the current state of affairs. --- mk/cfg/i686-pc-windows-gnu.mk | 5 +- mk/cfg/x86_64-pc-windows-gnu.mk | 5 +- mk/dist.mk | 1 - mk/rt.mk | 12 +- mk/target.mk | 64 +++---- src/doc/book/custom-allocators.md | 3 - src/doc/book/lang-items.md | 3 - src/doc/book/no-stdlib.md | 6 - src/librustc/middle/lang_items.rs | 1 - src/librustc/middle/weak_lang_items.rs | 5 - src/librustc_back/target/mod.rs | 7 - src/librustc_back/target/windows_base.rs | 25 +-- src/librustc_llvm/lib.rs | 14 ++ src/librustc_trans/trans/base.rs | 23 +-- src/librustc_trans/trans/cleanup.rs | 2 +- src/librustc_trans/trans/common.rs | 29 ---- src/librustc_trans/trans/context.rs | 6 - src/librustc_trans/trans/mir/block.rs | 2 +- src/libstd/rt.rs | 5 - src/libstd/sys/common/dwarf/eh.rs | 159 ------------------ src/libstd/sys/common/dwarf/mod.rs | 107 ------------ src/libstd/sys/common/gnu/mod.rs | 15 -- src/libstd/sys/common/mod.rs | 6 - .../sys/common/{unwind/mod.rs => unwind.rs} | 101 ++--------- src/libstd/sys/common/unwind/seh64_gnu.rs | 146 ---------------- src/libstd/sys/unix/backtrace/printing/gnu.rs | 11 -- .../backtrace/printing}/libbacktrace.rs | 0 src/libstd/sys/unix/backtrace/printing/mod.rs | 2 +- src/libstd/sys/{common => unix}/libunwind.rs | 4 +- src/libstd/sys/unix/mod.rs | 4 +- .../{common/unwind/gcc.rs => unix/unwind.rs} | 154 ++++++++++------- src/libstd/sys/windows/backtrace.rs | 72 ++++++-- src/libstd/sys/windows/mod.rs | 3 +- src/libstd/sys/windows/printing/gnu.rs | 25 --- src/libstd/sys/windows/printing/msvc.rs | 61 ------- .../unwind/seh.rs => windows/unwind.rs} | 14 +- src/rtstartup/rsbegin.rs | 78 --------- src/rtstartup/rsend.rs | 24 --- src/test/auxiliary/lang-item-public.rs | 3 - .../compile-fail/no_owned_box_lang_item.rs | 1 - .../mir_trans_calls_converging_drops.rs | 2 +- .../mir_trans_calls_converging_drops_2.rs | 2 +- .../mir_trans_calls_diverging_drops.rs | 2 +- src/test/run-make/no-duplicate-libs/bar.rs | 3 - src/test/run-make/no-duplicate-libs/foo.rs | 3 - src/test/run-pass/backtrace.rs | 2 +- src/test/run-pass/smallest-hello-world.rs | 3 - 47 files changed, 238 insertions(+), 987 deletions(-) delete mode 100644 src/libstd/sys/common/dwarf/eh.rs delete mode 100644 src/libstd/sys/common/dwarf/mod.rs delete mode 100644 src/libstd/sys/common/gnu/mod.rs rename src/libstd/sys/common/{unwind/mod.rs => unwind.rs} (61%) delete mode 100644 src/libstd/sys/common/unwind/seh64_gnu.rs delete mode 100644 src/libstd/sys/unix/backtrace/printing/gnu.rs rename src/libstd/sys/{common/gnu => unix/backtrace/printing}/libbacktrace.rs (100%) rename src/libstd/sys/{common => unix}/libunwind.rs (97%) rename src/libstd/sys/{common/unwind/gcc.rs => unix/unwind.rs} (60%) delete mode 100644 src/libstd/sys/windows/printing/gnu.rs delete mode 100644 src/libstd/sys/windows/printing/msvc.rs rename src/libstd/sys/{common/unwind/seh.rs => windows/unwind.rs} (96%) delete mode 100644 src/rtstartup/rsbegin.rs delete mode 100644 src/rtstartup/rsend.rs diff --git a/mk/cfg/i686-pc-windows-gnu.mk b/mk/cfg/i686-pc-windows-gnu.mk index 3426b30aeeb85..9c55fdbb05fa4 100644 --- a/mk/cfg/i686-pc-windows-gnu.mk +++ b/mk/cfg/i686-pc-windows-gnu.mk @@ -22,6 +22,5 @@ CFG_LDPATH_i686-pc-windows-gnu := CFG_RUN_i686-pc-windows-gnu=$(2) CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2)) CFG_GNU_TRIPLE_i686-pc-windows-gnu := i686-w64-mingw32 -CFG_THIRD_PARTY_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o -CFG_INSTALLED_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o -CFG_RUSTRT_HAS_STARTUP_OBJS_i686-pc-windows-gnu := 1 +CFG_THIRD_PARTY_OBJECTS_i686-pc-windows-gnu := +CFG_INSTALLED_OBJECTS_i686-pc-windows-gnu := diff --git a/mk/cfg/x86_64-pc-windows-gnu.mk b/mk/cfg/x86_64-pc-windows-gnu.mk index f0732d08c71ea..b69c84cd4ff72 100644 --- a/mk/cfg/x86_64-pc-windows-gnu.mk +++ b/mk/cfg/x86_64-pc-windows-gnu.mk @@ -22,6 +22,5 @@ CFG_LDPATH_x86_64-pc-windows-gnu := CFG_RUN_x86_64-pc-windows-gnu=$(2) CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2)) CFG_GNU_TRIPLE_x86_64-pc-windows-gnu := x86_64-w64-mingw32 -CFG_THIRD_PARTY_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o -CFG_INSTALLED_OBJECTS_x86_64-pc-windows-gnu := crt2.o dllcrt2.o rsbegin.o rsend.o -CFG_RUSTRT_HAS_STARTUP_OBJS_x86_64-pc-windows-gnu := 1 +CFG_THIRD_PARTY_OBJECTS_x86_64-pc-windows-gnu := +CFG_INSTALLED_OBJECTS_x86_64-pc-windows-gnu := diff --git a/mk/dist.mk b/mk/dist.mk index 685fb2b5b4679..929b6c39952e9 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -58,7 +58,6 @@ PKG_FILES := \ libcoretest \ libbacktrace \ rt \ - rtstartup \ rustllvm \ snapshots.txt \ rust-installer \ diff --git a/mk/rt.mk b/mk/rt.mk index cfb210952bcfb..798913fe8a5ad 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -291,10 +291,8 @@ BACKTRACE_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),backtrace) BACKTRACE_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(BACKTRACE_NAME_$(1)) BACKTRACE_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/libbacktrace -# We don't use this on platforms that aren't linux-based (with the exception of -# msys2/mingw builds on windows, which use it to read the dwarf debug -# information) so just make the file available, the compilation of libstd won't -# actually build it. +# We don't use this on platforms that aren't linux-based so just make the file +# available, the compilation of libstd won't actually build it. ifeq ($$(findstring darwin,$$(OSTYPE_$(1))),darwin) # See comment above $$(BACKTRACE_LIB_$(1)): @@ -307,7 +305,7 @@ $$(BACKTRACE_LIB_$(1)): touch $$@ else -ifeq ($$(findstring msvc,$(1)),msvc) +ifeq ($$(findstring windows,$(1)),windows) # See comment above $$(BACKTRACE_LIB_$(1)): touch $$@ @@ -382,10 +380,6 @@ endif # endif for darwin ifeq ($$(findstring musl,$(1)),musl) $$(RT_OUTPUT_DIR_$(1))/%: $$(CFG_MUSL_ROOT)/lib/% cp $$^ $$@ -else -# Ask gcc where it is -$$(RT_OUTPUT_DIR_$(1))/%: - cp $$(shell $$(CC_$(1)) -print-file-name=$$(@F)) $$@ endif endef diff --git a/mk/target.mk b/mk/target.mk index 32a3eb5c20d28..62114dbc7d172 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -126,34 +126,6 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ endef -# Macro for building runtime startup/shutdown object files; -# these are Rust's equivalent of crti.o, crtn.o -# -# $(1) - stage -# $(2) - target triple -# $(3) - host triple -# $(4) - object basename -define TARGET_RUSTRT_STARTUP_OBJ - -$$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o: \ - $(S)src/rtstartup/$(4).rs \ - $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \ - $$(HSREQ$(1)_T_$(2)_H_$(3)) \ - | $$(TBIN$(1)_T_$(2)_H_$(3))/ - @$$(call E, rustc: $$@) - $$(STAGE$(1)_T_$(2)_H_$(3)) --emit=obj -o $$@ $$< - -ifeq ($$(CFG_RUSTRT_HAS_STARTUP_OBJS_$(2)), 1) -# Add dependencies on Rust startup objects to all crates that depend on core. -# This ensures that they are built after core (since they depend on it), -# but before everything else (since they are needed for linking dylib crates). -$$(foreach crate, $$(TARGET_CRATES), \ - $$(if $$(findstring core,$$(DEPS_$$(crate))), \ - $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate))) : $$(TLIB$(1)_T_$(2)_H_$(3))/$(4).o -endif - -endef - # Every recipe in RUST_TARGET_STAGE_N outputs to $$(TLIB$(1)_T_$(2)_H_$(3), # a directory that can be cleaned out during the middle of a run of # the get-snapshot.py script. Therefore, every recipe needs to have @@ -166,7 +138,10 @@ SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD)) define TARGET_HOST_RULES -$$(TLIB$(1)_T_$(2)_H_$(3))/: +$$(TLIB$(1)_T_$(2)_H_$(3))/: | $$(SNAPSHOT_RUSTC_POST_CLEANUP) + mkdir -p $$@ + +$$(TBIN$(1)_T_$(2)_H_$(3))/: | $$(SNAPSHOT_RUSTC_POST_CLEANUP) mkdir -p $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \ @@ -197,8 +172,33 @@ $(foreach host,$(CFG_HOST), \ $(foreach tool,$(TOOLS), \ $(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool))))))) +# FIXME(stage0) - remove everything here after a snapshot +# +# The stage0 compiler requires the rsend.o, rsbegin.o, crt2.o, and dllcrt2.o +# startup objects on the pc-windows-gnu targets, but that's no longer the case. +# Hack in support to the makefiles to ensure that these objects all exist. +# +# Note that the rs*.o files can just be blank object files. +define STARTUP_OBJS_COMPAT +ifeq ($$(findstring pc-windows-gnu,$(2)),pc-windows-gnu) +DUMMY_DEPS_$(2)_H_$(3) := \ + $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core \ + $$(HSREQ$(1)_T_$(2)_H_$(3))/stamp.core +$$(TLIB$(1)_T_$(2)_H_$(3))/rsend.o $$(TLIB$(1)_T_$(2)_H_$(3))/rsbegin.o: \ + $$(DUMMY_DEPS_$(2)_H_$(3) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP) + $$(CC_$(2)) $$(CFG_GCCISH_CFLAGS_$(2)) -c -x c - -o $$@ < /dev/null +$$(TLIB$(1)_T_$(2)_H_$(3))/dllcrt2.o $$(TLIB$(1)_T_$(2)_H_$(3))/crt2.o: \ + $$(DUMMY_DEPS_$(2)_H_$(3) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP) + cp $$(shell $$(CC_$(2)) -print-file-name=$$(@F)) $$@ +$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.std: \ + $$(TLIB$(1)_T_$(2)_H_$(3))/rsend.o \ + $$(TLIB$(1)_T_$(2)_H_$(3))/rsbegin.o \ + $$(TLIB$(1)_T_$(2)_H_$(3))/dllcrt2.o \ + $$(TLIB$(1)_T_$(2)_H_$(3))/crt2.o +endif +endef $(foreach host,$(CFG_HOST), \ $(foreach target,$(CFG_TARGET), \ - $(foreach stage,$(STAGES), \ - $(foreach obj,rsbegin rsend, \ - $(eval $(call TARGET_RUSTRT_STARTUP_OBJ,$(stage),$(target),$(host),$(obj))))))) + $(eval $(call STARTUP_OBJS_COMPAT,0,$(target),$(host))))) diff --git a/src/doc/book/custom-allocators.md b/src/doc/book/custom-allocators.md index d69ef6cf7e83a..7b43aeb4de2ab 100644 --- a/src/doc/book/custom-allocators.md +++ b/src/doc/book/custom-allocators.md @@ -138,9 +138,6 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { # fn main() {} # #[lang = "panic_fmt"] fn panic_fmt() {} # #[lang = "eh_personality"] fn eh_personality() {} -# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} ``` After we compile this crate, it can be used as follows: diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index b948567ac5b74..78f84a50b4124 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -59,9 +59,6 @@ fn main(argc: isize, argv: *const *const u8) -> isize { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to diff --git a/src/doc/book/no-stdlib.md b/src/doc/book/no-stdlib.md index 610940cde95e6..7f21761ef4e6a 100644 --- a/src/doc/book/no-stdlib.md +++ b/src/doc/book/no-stdlib.md @@ -39,9 +39,6 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { // provided by libstd. #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} # // fn main() {} tricked you, rustdoc! ``` @@ -66,9 +63,6 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} # // fn main() {} tricked you, rustdoc! ``` diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a22ad7a0707c2..d472d469024f7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -340,7 +340,6 @@ lets_do_this! { EhPersonalityLangItem, "eh_personality", eh_personality; EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch; - EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume; MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; OwnedBoxLangItem, "owned_box", owned_box; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 6059d7ee74e39..391b6664faa52 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -43,10 +43,6 @@ pub fn check_crate(krate: &hir::Crate, if items.eh_personality().is_none() { items.missing.push(lang_items::EhPersonalityLangItem); } - if sess.target.target.options.custom_unwind_resume & - items.eh_unwind_resume().is_none() { - items.missing.push(lang_items::EhUnwindResumeLangItem); - } { let mut cx = Context { sess: sess, items: items }; @@ -123,5 +119,4 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { weak_lang_items! { panic_fmt, PanicFmtLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; - eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index c61ae547a2254..2e0cca0e8dc1e 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -191,11 +191,6 @@ pub struct TargetOptions { pub archive_format: String, /// Is asm!() allowed? Defaults to true. pub allow_asm: bool, - /// Whether the target uses a custom unwind resumption routine. - /// By default LLVM lowers `resume` instructions into calls to `_Unwind_Resume` - /// defined in libgcc. If this option is enabled, the target must provide - /// `eh_unwind_resume` lang item. - pub custom_unwind_resume: bool, /// Default crate for allocation symbols to link against pub lib_allocation_crate: String, @@ -250,7 +245,6 @@ impl Default for TargetOptions { post_link_objects: Vec::new(), late_link_args: Vec::new(), archive_format: String::new(), - custom_unwind_resume: false, lib_allocation_crate: "alloc_system".to_string(), exe_allocation_crate: "alloc_system".to_string(), allow_asm: true, @@ -365,7 +359,6 @@ impl Target { key!(post_link_args, list); key!(archive_format); key!(allow_asm, bool); - key!(custom_unwind_resume, bool); base } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index 4eacea3fcd9a9..1c1c2355e13c2 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -23,7 +23,7 @@ pub fn opts() -> TargetOptions { exe_suffix: ".exe".to_string(), staticlib_prefix: "".to_string(), staticlib_suffix: ".lib".to_string(), - no_default_libraries: true, + no_default_libraries: false, is_like_windows: true, archive_format: "gnu".to_string(), pre_link_args: vec!( @@ -60,30 +60,7 @@ pub fn opts() -> TargetOptions { // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), - - // Do not use the standard system startup files or libraries when linking - "-nostdlib".to_string(), - ), - pre_link_objects_exe: vec!( - "crt2.o".to_string(), // mingw C runtime initialization for executables - "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs - ), - pre_link_objects_dll: vec!( - "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls - "rsbegin.o".to_string(), - ), - late_link_args: vec!( - "-lmingwex".to_string(), - "-lmingw32".to_string(), - "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc - "-lmsvcrt".to_string(), - "-luser32".to_string(), - "-lkernel32".to_string(), - ), - post_link_objects: vec!( - "rsend.o".to_string() ), - custom_unwind_resume: true, .. Default::default() } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 2ddc803fe493f..83b0a582eea52 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -2490,3 +2490,17 @@ impl Drop for OperandBundleDef { mod llvmdeps { include! { env!("CFG_LLVM_LINKAGE_FILE") } } + +// Currenty when compiling LLVM for i686-pc-windows-gnu it will think that it's +// got "ehtable support", and these two symbols here will be referenced from +// RTDyldMemoryManager. This class is, however, only really used from jits, so +// we don't really need it to work. For now just define two dummy symbols, but +// ideally we'd upstream some patch or configure LLVM in such a way that it +// doesn't even need these symbols defined. +#[cfg(all(windows, target_env = "gnu", target_arch = "x86"))] +pub mod __dummy_llvm_required_symbols { + #[no_mangle] + pub extern fn __register_frame(_ptr: *mut u8) {} + #[no_mangle] + pub extern fn __deregister_frame(_ptr: *mut u8) {} +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 2fc585c7c795e..5710ef9017b8d 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -980,11 +980,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Returns whether this session's target will use SEH-based unwinding. /// -/// This is only true for MSVC targets, and even then the 64-bit MSVC target -/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as -/// 64-bit MinGW) instead of "full SEH". +/// This is currentlyt true for all Windows targets. pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.target.options.is_like_msvc + sess.target.target.options.is_like_windows } pub fn avoid_invoke(bcx: Block) -> bool { @@ -1220,19 +1218,6 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) { }) } -// Generates code for resumption of unwind at the end of a landing pad. -pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) { - if !bcx.sess().target.target.options.custom_unwind_resume { - Resume(bcx, lpval); - } else { - let exc_ptr = ExtractValue(bcx, lpval, 0); - let llunwresume = bcx.fcx.eh_unwind_resume(); - Call(bcx, llunwresume, &[exc_ptr], None, DebugLoc::None); - Unreachable(bcx); - } -} - - pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) { let _icx = push_ctxt("call_memcpy"); let ccx = cx.ccx(); @@ -1981,7 +1966,9 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, record_translation_item_as_generated(ccx, fn_ast_id, param_substs); let _icx = push_ctxt("trans_closure"); - attributes::emit_uwtable(llfndecl, true); + if !wants_msvc_seh(ccx.sess()) { + attributes::emit_uwtable(llfndecl, true); + } debug!("trans_closure(..., param_substs={:?})", param_substs); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 7c98868dfe7c6..0d262fbd033d0 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -747,7 +747,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx .unwrap(); let lp = build::Load(bcx, addr); base::call_lifetime_end(bcx, addr); - base::trans_unwind_resume(bcx, lp); + build::Resume(bcx, lp); } UnwindKind::CleanupPad(_) => { let pad = build::CleanupPad(bcx, None, &[]); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 303fc17ce81b4..86ca9d46cc45f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -534,35 +534,6 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } } } - - // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined, - // otherwise declares it as an external funtion. - pub fn eh_unwind_resume(&self) -> ValueRef { - use trans::attributes; - assert!(self.ccx.sess().target.target.options.custom_unwind_resume); - match self.ccx.tcx().lang_items.eh_unwind_resume() { - Some(def_id) => { - callee::trans_fn_ref(self.ccx, def_id, ExprId(0), - self.param_substs).val - } - None => { - let mut unwresume = self.ccx.eh_unwind_resume().borrow_mut(); - match *unwresume { - Some(llfn) => llfn, - None => { - let fty = Type::func(&[Type::i8p(self.ccx)], &Type::void(self.ccx)); - let llfn = declare::declare_fn(self.ccx, - "rust_eh_unwind_resume", - llvm::CCallConv, - fty, ty::FnDiverging); - attributes::unwind(llfn, true); - *unwresume = Some(llfn); - llfn - } - } - } - } - } } // Basic block context. We create a block context for each basic block diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 38459c1ec3cb7..65b100476b2dc 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -153,7 +153,6 @@ pub struct LocalCrateContext<'tcx> { dbg_cx: Option>, eh_personality: RefCell>, - eh_unwind_resume: RefCell>, rust_try_fn: RefCell>, intrinsics: RefCell>, @@ -493,7 +492,6 @@ impl<'tcx> LocalCrateContext<'tcx> { closure_vals: RefCell::new(FnvHashMap()), dbg_cx: dbg_cx, eh_personality: RefCell::new(None), - eh_unwind_resume: RefCell::new(None), rust_try_fn: RefCell::new(None), intrinsics: RefCell::new(FnvHashMap()), n_llvm_insns: Cell::new(0), @@ -758,10 +756,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.eh_personality } - pub fn eh_unwind_resume<'a>(&'a self) -> &'a RefCell> { - &self.local.eh_unwind_resume - } - pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell> { &self.local.rust_try_fn } diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 5be585c4189e1..c7961e723ffaf 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -87,7 +87,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let ps = self.get_personality_slot(bcx); let lp = build::Load(bcx, ps); base::call_lifetime_end(bcx, ps); - base::trans_unwind_resume(bcx, lp); + build::Resume(bcx, lp); } mir::Terminator::Return => { diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index fcd827e2a8b72..3a362cd766469 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -27,11 +27,6 @@ // Reexport some of our utilities which are expected by other crates. pub use sys_common::unwind::{begin_unwind, begin_unwind_fmt}; -// Rust runtime's startup objects depend on these symbols, so they must be public. -// Since sys_common isn't public, we have to re-export them here. -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub use sys_common::unwind::imp::eh_frame_registry::*; - #[cfg(not(test))] #[lang = "start"] fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { diff --git a/src/libstd/sys/common/dwarf/eh.rs b/src/libstd/sys/common/dwarf/eh.rs deleted file mode 100644 index 319be245bde98..0000000000000 --- a/src/libstd/sys/common/dwarf/eh.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Parsing of GCC-style Language-Specific Data Area (LSDA) -//! For details see: -//! http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html -//! http://mentorembedded.github.io/cxx-abi/exceptions.pdf -//! http://www.airs.com/blog/archives/460 -//! http://www.airs.com/blog/archives/464 -//! -//! A reference implementation may be found in the GCC source tree -//! (/libgcc/unwind-c.c as of this writing) - -#![allow(non_upper_case_globals)] -#![allow(unused)] - -use prelude::v1::*; -use sys_common::dwarf::DwarfReader; -use core::mem; - -pub const DW_EH_PE_omit : u8 = 0xFF; -pub const DW_EH_PE_absptr : u8 = 0x00; - -pub const DW_EH_PE_uleb128 : u8 = 0x01; -pub const DW_EH_PE_udata2 : u8 = 0x02; -pub const DW_EH_PE_udata4 : u8 = 0x03; -pub const DW_EH_PE_udata8 : u8 = 0x04; -pub const DW_EH_PE_sleb128 : u8 = 0x09; -pub const DW_EH_PE_sdata2 : u8 = 0x0A; -pub const DW_EH_PE_sdata4 : u8 = 0x0B; -pub const DW_EH_PE_sdata8 : u8 = 0x0C; - -pub const DW_EH_PE_pcrel : u8 = 0x10; -pub const DW_EH_PE_textrel : u8 = 0x20; -pub const DW_EH_PE_datarel : u8 = 0x30; -pub const DW_EH_PE_funcrel : u8 = 0x40; -pub const DW_EH_PE_aligned : u8 = 0x50; - -pub const DW_EH_PE_indirect : u8 = 0x80; - -#[derive(Copy, Clone)] -pub struct EHContext { - pub ip: usize, // Current instruction pointer - pub func_start: usize, // Address of the current function - pub text_start: usize, // Address of the code section - pub data_start: usize, // Address of the data section -} - -pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) - -> Option { - if lsda.is_null() { - return None; - } - - let func_start = context.func_start; - let mut reader = DwarfReader::new(lsda); - - let start_encoding = reader.read::(); - // base address for landing pad offsets - let lpad_base = if start_encoding != DW_EH_PE_omit { - read_encoded_pointer(&mut reader, context, start_encoding) - } else { - func_start - }; - - let ttype_encoding = reader.read::(); - if ttype_encoding != DW_EH_PE_omit { - // Rust doesn't analyze exception types, so we don't care about the type table - reader.read_uleb128(); - } - - let call_site_encoding = reader.read::(); - let call_site_table_length = reader.read_uleb128(); - let action_table = reader.ptr.offset(call_site_table_length as isize); - // Return addresses point 1 byte past the call instruction, which could - // be in the next IP range. - let ip = context.ip-1; - - while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_action = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start + cs_start { - break - } - if ip < func_start + cs_start + cs_len { - if cs_lpad != 0 { - return Some(lpad_base + cs_lpad); - } else { - return None; - } - } - } - // IP range not found: gcc's C++ personality calls terminate() here, - // however the rest of the languages treat this the same as cs_lpad == 0. - // We follow this suit. - None -} - -#[inline] -fn round_up(unrounded: usize, align: usize) -> usize { - assert!(align.is_power_of_two()); - (unrounded + align - 1) & !(align - 1) -} - -unsafe fn read_encoded_pointer(reader: &mut DwarfReader, - context: &EHContext, - encoding: u8) -> usize { - assert!(encoding != DW_EH_PE_omit); - - // DW_EH_PE_aligned implies it's an absolute pointer value - if encoding == DW_EH_PE_aligned { - reader.ptr = round_up(reader.ptr as usize, - mem::size_of::()) as *const u8; - return reader.read::(); - } - - let mut result = match encoding & 0x0F { - DW_EH_PE_absptr => reader.read::(), - DW_EH_PE_uleb128 => reader.read_uleb128() as usize, - DW_EH_PE_udata2 => reader.read::() as usize, - DW_EH_PE_udata4 => reader.read::() as usize, - DW_EH_PE_udata8 => reader.read::() as usize, - DW_EH_PE_sleb128 => reader.read_sleb128() as usize, - DW_EH_PE_sdata2 => reader.read::() as usize, - DW_EH_PE_sdata4 => reader.read::() as usize, - DW_EH_PE_sdata8 => reader.read::() as usize, - _ => panic!() - }; - - result += match encoding & 0x70 { - DW_EH_PE_absptr => 0, - // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => reader.ptr as usize, - DW_EH_PE_textrel => { assert!(context.text_start != 0); - context.text_start }, - DW_EH_PE_datarel => { assert!(context.data_start != 0); - context.data_start }, - DW_EH_PE_funcrel => { assert!(context.func_start != 0); - context.func_start }, - _ => panic!() - }; - - if encoding & DW_EH_PE_indirect != 0 { - result = *(result as *const usize); - } - - result -} diff --git a/src/libstd/sys/common/dwarf/mod.rs b/src/libstd/sys/common/dwarf/mod.rs deleted file mode 100644 index 822826bcc837f..0000000000000 --- a/src/libstd/sys/common/dwarf/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for parsing DWARF-encoded data streams. -//! See http://www.dwarfstd.org, -//! DWARF-4 standard, Section 7 - "Data Representation" - -// This module is used only by x86_64-pc-windows-gnu for now, but we -// are compiling it everywhere to avoid regressions. -#![allow(unused)] - -pub mod eh; - -use prelude::v1::*; -use core::mem; - -pub struct DwarfReader { - pub ptr : *const u8 -} - -#[repr(C,packed)] -struct Unaligned(T); - -impl DwarfReader { - - pub fn new(ptr : *const u8) -> DwarfReader { - DwarfReader { - ptr : ptr - } - } - - // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. - pub unsafe fn read(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned); - self.ptr = self.ptr.offset(mem::size_of::() as isize); - result - } - - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". - pub unsafe fn read_uleb128(&mut self) -> u64 { - let mut shift : usize = 0; - let mut result : u64 = 0; - let mut byte : u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - result - } - - pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift : usize = 0; - let mut result : u64 = 0; - let mut byte : u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { - result |= (!0 as u64) << shift; - } - result as i64 - } -} - -#[test] -fn dwarf_reader() { - let encoded: &[u8] = &[1, - 2, 3, - 4, 5, 6, 7, - 0xE5, 0x8E, 0x26, - 0x9B, 0xF1, 0x59, - 0xFF, 0xFF]; - - let mut reader = DwarfReader::new(encoded.as_ptr()); - - unsafe { - assert!(reader.read::() == u8::to_be(1u8)); - assert!(reader.read::() == u16::to_be(0x0203)); - assert!(reader.read::() == u32::to_be(0x04050607)); - - assert!(reader.read_uleb128() == 624485); - assert!(reader.read_sleb128() == -624485); - - assert!(reader.read::() == i8::to_be(-1)); - } -} diff --git a/src/libstd/sys/common/gnu/mod.rs b/src/libstd/sys/common/gnu/mod.rs deleted file mode 100644 index 3a8cf2d842591..0000000000000 --- a/src/libstd/sys/common/gnu/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -pub mod libbacktrace; diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 56628a4c7545e..0195ab2004b43 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -30,9 +30,7 @@ pub mod args; pub mod at_exit_imp; pub mod backtrace; pub mod condvar; -pub mod dwarf; pub mod io; -pub mod libunwind; pub mod mutex; pub mod net; pub mod poison; @@ -45,10 +43,6 @@ pub mod unwind; pub mod util; pub mod wtf8; -#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))), - all(windows, target_env = "gnu")))] -pub mod gnu; - // common error constructors /// A trait for viewing representations from std types diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind.rs similarity index 61% rename from src/libstd/sys/common/unwind/mod.rs rename to src/libstd/sys/common/unwind.rs index d9641e63760e5..7ff898b7b1d89 100644 --- a/src/libstd/sys/common/unwind/mod.rs +++ b/src/libstd/sys/common/unwind.rs @@ -8,95 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Implementation of Rust stack unwinding +//! Common unwinding support to all platforms. //! -//! For background on exception handling and stack unwinding please see -//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and -//! documents linked from it. -//! These are also good reads: -//! http://mentorembedded.github.io/cxx-abi/abi-eh.html -//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/ -//! http://www.airs.com/blog/index.php?s=exception+frames +//! This module does not contain the lowest-level implementation of unwinding +//! itself, but rather contains some of the Rust APIs used as entry points to +//! unwinding itself. For example this is the location of the lang item +//! `panic_fmt` which is the entry point of all panics from libcore. //! -//! ## A brief summary -//! -//! Exception handling happens in two phases: a search phase and a cleanup phase. -//! -//! In both phases the unwinder walks stack frames from top to bottom using -//! information from the stack frame unwind sections of the current process's -//! modules ("module" here refers to an OS module, i.e. an executable or a -//! dynamic library). -//! -//! For each stack frame, it invokes the associated "personality routine", whose -//! address is also stored in the unwind info section. -//! -//! In the search phase, the job of a personality routine is to examine exception -//! object being thrown, and to decide whether it should be caught at that stack -//! frame. Once the handler frame has been identified, cleanup phase begins. -//! -//! In the cleanup phase, the unwinder invokes each personality routine again. -//! This time it decides which (if any) cleanup code needs to be run for -//! the current stack frame. If so, the control is transferred to a special branch -//! in the function body, the "landing pad", which invokes destructors, frees memory, -//! etc. At the end of the landing pad, control is transferred back to the unwinder -//! and unwinding resumes. -//! -//! Once stack has been unwound down to the handler frame level, unwinding stops -//! and the last personality routine transfers control to the catch block. -//! -//! ## `eh_personality` and `eh_unwind_resume` -//! -//! These language items are used by the compiler when generating unwind info. -//! The first one is the personality routine described above. The second one -//! allows compilation target to customize the process of resuming unwind at the -//! end of the landing pads. `eh_unwind_resume` is used only if `custom_unwind_resume` -//! flag in the target options is set. -//! -//! ## Frame unwind info registration -//! -//! Each module's image contains a frame unwind info section (usually ".eh_frame"). -//! When a module is loaded/unloaded into the process, the unwinder must be informed -//! about the location of this section in memory. The methods of achieving that vary -//! by the platform. -//! On some (e.g. Linux), the unwinder can discover unwind info sections on its own -//! (by dynamically enumerating currently loaded modules via the dl_iterate_phdr() API -//! and finding their ".eh_frame" sections); -//! Others, like Windows, require modules to actively register their unwind info -//! sections via unwinder API (see `rust_eh_register_frames`/`rust_eh_unregister_frames`). - -#![allow(dead_code)] -#![allow(unused_imports)] +//! For details on how each platform implements unwinding, see the +//! platform-specific `sys::unwind` module. use prelude::v1::*; use any::Any; -use boxed; -use cmp; use panicking::{self,PANIC_COUNT}; use fmt; use intrinsics; -use mem; -use sync::atomic::{self, Ordering}; -use sys_common::mutex::Mutex; - -// The actual unwinding implementation is cfg'd here, and we've got two current -// implementations. One goes through SEH on Windows and the other goes through -// libgcc via the libunwind-like API. - -// *-pc-windows-msvc -#[cfg(target_env = "msvc")] -#[path = "seh.rs"] #[doc(hidden)] -pub mod imp; - -// x86_64-pc-windows-gnu -#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] -#[path = "seh64_gnu.rs"] #[doc(hidden)] -pub mod imp; - -// i686-pc-windows-gnu and all others -#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))] -#[path = "gcc.rs"] #[doc(hidden)] -pub mod imp; +use sys::unwind; /// Invoke a closure, capturing the cause of panic if one occurs. /// @@ -140,18 +68,19 @@ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) // the point-of-throw back to this location. // // A pointer to this data is passed to the `try` intrinsic itself, - // allowing this function, the `try` intrinsic, imp::payload(), and - // imp::cleanup() to all work in concert to transmit this information. + // allowing this function, the `try` intrinsic, unwind::payload(), and + // unwind::cleanup() to all work in concert to transmit this + // information. // // More information about what this pointer actually is can be found in // each implementation as well as browsing the compiler source itself. - let mut payload = imp::payload(); + let mut payload = unwind::payload(); let r = intrinsics::try(f, data, &mut payload as *mut _ as *mut _); s.set(prev); if r == 0 { Ok(()) } else { - Err(imp::cleanup(payload)) + Err(unwind::cleanup(payload)) } }) } @@ -167,7 +96,7 @@ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) if ep.is_null() { Ok(()) } else { - Err(imp::cleanup(ep)) + Err(unwind::cleanup(ep)) } }) } @@ -183,7 +112,7 @@ pub fn panicking() -> bool { #[allow(private_no_mangle_fns)] pub fn rust_panic(cause: Box) -> ! { unsafe { - imp::panic(cause) + unwind::panic(cause) } } diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs deleted file mode 100644 index 8afef081673d0..0000000000000 --- a/src/libstd/sys/common/unwind/seh64_gnu.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unwinding implementation of top of native Win64 SEH, -//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding. - -#![allow(bad_style)] -#![allow(private_no_mangle_fns)] - -use prelude::v1::*; - -use any::Any; -use sys_common::dwarf::eh; -use core::mem; -use core::ptr; -use sys::c; - -// Define our exception codes: -// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx, -// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success) -// [29] = 1 (user-defined) -// [28] = 0 (reserved) -// we define bits: -// [24:27] = type -// [0:23] = magic -const ETYPE: c::DWORD = 0b1110_u32 << 28; -const MAGIC: c::DWORD = 0x525354; // "RST" - -const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC; - -#[repr(C)] -struct PanicData { - data: Box -} - -pub unsafe fn panic(data: Box) -> ! { - let panic_ctx = Box::new(PanicData { data: data }); - let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR]; - c::RaiseException(RUST_PANIC, - c::EXCEPTION_NONCONTINUABLE, - params.len() as c::DWORD, - ¶ms as *const c::ULONG_PTR); - rtabort!("could not unwind stack"); -} - -#[cfg(not(stage0))] -pub fn payload() -> *mut u8 { - 0 as *mut u8 -} - -pub unsafe fn cleanup(ptr: *mut u8) -> Box { - let panic_ctx = Box::from_raw(ptr as *mut PanicData); - return panic_ctx.data; -} - -// SEH doesn't support resuming unwinds after calling a landing pad like -// libunwind does. For this reason, MSVC compiler outlines landing pads into -// separate functions that can be called directly from the personality function -// but are nevertheless able to find and modify stack frame of the "parent" -// function. -// -// Since this cannot be done with libdwarf-style landing pads, -// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then -// reraises the exception. -// -// Note that it makes certain assumptions about the exception: -// -// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to -// resume execution. -// 2. That the first parameter of the exception is a pointer to an extra data -// area (PanicData). -// Since these assumptions do not generally hold true for foreign exceptions -// (system faults, C++ exceptions, etc), we make no attempt to invoke our -// landing pads (and, thus, destructors!) for anything other than RUST_PANICs. -// This is considered acceptable, because the behavior of throwing exceptions -// through a C ABI boundary is undefined. - -#[lang = "eh_personality_catch"] -#[cfg(not(test))] -unsafe extern fn rust_eh_personality_catch( - exceptionRecord: *mut c::EXCEPTION_RECORD, - establisherFrame: c::LPVOID, - contextRecord: *mut c::CONTEXT, - dispatcherContext: *mut c::DISPATCHER_CONTEXT -) -> c::EXCEPTION_DISPOSITION -{ - rust_eh_personality(exceptionRecord, establisherFrame, - contextRecord, dispatcherContext) -} - -#[lang = "eh_personality"] -#[cfg(not(test))] -unsafe extern fn rust_eh_personality( - exceptionRecord: *mut c::EXCEPTION_RECORD, - establisherFrame: c::LPVOID, - contextRecord: *mut c::CONTEXT, - dispatcherContext: *mut c::DISPATCHER_CONTEXT -) -> c::EXCEPTION_DISPOSITION -{ - let er = &*exceptionRecord; - let dc = &*dispatcherContext; - - if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 { // we are in the dispatch phase - if er.ExceptionCode == RUST_PANIC { - if let Some(lpad) = find_landing_pad(dc) { - c::RtlUnwindEx(establisherFrame, - lpad as c::LPVOID, - exceptionRecord, - er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData - contextRecord, - dc.HistoryTable); - rtabort!("could not unwind"); - } - } - } - c::ExceptionContinueSearch -} - -#[cfg(not(test))] -#[lang = "eh_unwind_resume"] -#[unwind] -unsafe extern fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { - let params = [panic_ctx as c::ULONG_PTR]; - c::RaiseException(RUST_PANIC, - c::EXCEPTION_NONCONTINUABLE, - params.len() as c::DWORD, - ¶ms as *const c::ULONG_PTR); - rtabort!("could not resume unwind"); -} - -unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { - let eh_ctx = eh::EHContext { - ip: dc.ControlPc as usize, - func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize, - text_start: dc.ImageBase as usize, - data_start: 0 - }; - eh::find_landing_pad(dc.HandlerData, &eh_ctx) -} diff --git a/src/libstd/sys/unix/backtrace/printing/gnu.rs b/src/libstd/sys/unix/backtrace/printing/gnu.rs deleted file mode 100644 index fb06fbedaf57b..0000000000000 --- a/src/libstd/sys/unix/backtrace/printing/gnu.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use sys_common::gnu::libbacktrace::print; diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys/unix/backtrace/printing/libbacktrace.rs similarity index 100% rename from src/libstd/sys/common/gnu/libbacktrace.rs rename to src/libstd/sys/unix/backtrace/printing/libbacktrace.rs diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs index 02e53854727f7..7c9fb9cf71c68 100644 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ b/src/libstd/sys/unix/backtrace/printing/mod.rs @@ -17,5 +17,5 @@ mod imp; #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] -#[path = "gnu.rs"] +#[path = "libbacktrace.rs"] mod imp; diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/unix/libunwind.rs similarity index 97% rename from src/libstd/sys/common/libunwind.rs rename to src/libstd/sys/unix/libunwind.rs index 3f70afe6ad76e..13c8622a2622f 100644 --- a/src/libstd/sys/common/libunwind.rs +++ b/src/libstd/sys/unix/libunwind.rs @@ -120,9 +120,7 @@ pub type _Unwind_Exception_Cleanup_Fn = link(name = "gcc_pic"))] #[cfg_attr(target_os = "bitrig", link(name = "c++abi"))] -#[cfg_attr(all(target_os = "windows", target_env="gnu"), - link(name = "gcc_eh"))] -extern "C" { +extern { // iOS on armv7 uses SjLj exceptions and requires to link // against corresponding routine (..._SjLj_...) #[cfg(not(all(target_os = "ios", target_arch = "arm")))] diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9cae36fb7260b..7429fb33cf433 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -36,6 +36,7 @@ pub mod condvar; pub mod ext; pub mod fd; pub mod fs; +pub mod libunwind; pub mod mutex; pub mod net; pub mod os; @@ -44,10 +45,11 @@ pub mod pipe; pub mod process; pub mod rwlock; pub mod stack_overflow; +pub mod stdio; pub mod thread; pub mod thread_local; pub mod time; -pub mod stdio; +pub mod unwind; #[cfg(not(test))] pub fn init() { diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/unix/unwind.rs similarity index 60% rename from src/libstd/sys/common/unwind/gcc.rs rename to src/libstd/sys/unix/unwind.rs index 12cd07a4f4f18..61169499dd2a6 100644 --- a/src/libstd/sys/common/unwind/gcc.rs +++ b/src/libstd/sys/unix/unwind.rs @@ -8,21 +8,105 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! # Implementation of Rust stack unwinding +//! +//! Also might be known as itanium exceptions, libunwind-based unwinding, +//! libgcc unwinding, etc. Unwinding on Unix currently always happens through +//! the libunwind support library, although we don't always link to libunwind +//! directly as it's often bundled directly into libgcc (or libgcc_s). +//! +//! For background on exception handling and stack unwinding please see +//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and +//! documents linked from it. +//! +//! These are also good reads: +//! +//! * http://mentorembedded.github.io/cxx-abi/abi-eh.html +//! * http://monoinfinito.wordpress.com/series/exception-handling-in-c/ +//! * http://www.airs.com/blog/index.php?s=exception+frames +//! +//! The basic premise here is that we're going to literally throw an exception, +//! only with library support rather than language support. This interacts with +//! LLVM by using the `invoke` instruction all over the place instead of a +//! typical `call` instruction. As a reminder, when LLVM translates an `invoke` +//! instruction it requires that the surrounding function is attached with a +//! **personality** function. The major purpose of this module is to define +//! these personality functions. +//! +//! First, though, let's take a look at how unwinding works: +//! +//! ## A brief summary +//! +//! Exception handling happens in two phases: a search phase and a cleanup +//! phase. +//! +//! In both phases the unwinder walks stack frames from top to bottom using +//! information from the stack frame unwind sections of the current process's +//! modules ("module" here refers to an OS module, i.e. an executable or a +//! dynamic library). +//! +//! For each stack frame, it invokes the associated "personality routine", whose +//! address is also stored in the unwind info section. +//! +//! In the search phase, the job of a personality routine is to examine +//! exception object being thrown, and to decide whether it should be caught at +//! that stack frame. Once the handler frame has been identified, cleanup phase +//! begins. +//! +//! In the cleanup phase, the unwinder invokes each personality routine again. +//! This time it decides which (if any) cleanup code needs to be run for +//! the current stack frame. If so, the control is transferred to a special +//! branch in the function body, the "landing pad", which invokes destructors, +//! frees memory, etc. At the end of the landing pad, control is transferred +//! back to the unwinder and unwinding resumes. +//! +//! Once stack has been unwound down to the handler frame level, unwinding stops +//! and the last personality routine transfers control to the catch block. +//! +//! ## `eh_personality` and `eh_personality_catch` +//! +//! The main personality function, `eh_personality`, is used by almost all Rust +//! functions that are translated. This personality indicates that no exceptions +//! should be caught, but cleanups should always be run. The second personality +//! function, `eh_personality_catch`, is distinct in that it indicates that +//! exceptions should be caught (no cleanups are run). The compiler will +//! annotate all generated functions with these two personalities, and then +//! we're just left to implement them over here! +//! +//! We could implement our personality routine in pure Rust, however exception +//! info decoding is tedious. More importantly, personality routines have to +//! handle various platform quirks, which are not fun to maintain. For this +//! reason, we attempt to reuse personality routine of the C language. This +//! comes under a number of names and ABIs, including `__gcc_personality_v0` and +//! `__gcc_personality_sj0`. +//! +//! Since C does not support exception catching, this personality function +//! simply always returns `_URC_CONTINUE_UNWIND` in search phase, and always +//! returns `_URC_INSTALL_CONTEXT` (i.e. "invoke cleanup code") in cleanup +//! phase. +//! +//! To implement the `eh_personality_catch` function, however, we detect when +//! the search phase is occurring and return `_URC_HANDLER_FOUND` to indicate +//! that we want to catch the exception. +//! +//! See also: `rustc_trans::trans::intrinsic::trans_gnu_try` + #![allow(private_no_mangle_fns)] use prelude::v1::*; use any::Any; -use sys_common::libunwind as uw; +use sys::libunwind as uw; +#[repr(C)] struct Exception { - uwe: uw::_Unwind_Exception, + _uwe: uw::_Unwind_Exception, cause: Option>, } pub unsafe fn panic(data: Box) -> ! { let exception: Box<_> = box Exception { - uwe: uw::_Unwind_Exception { + _uwe: uw::_Unwind_Exception { exception_class: rust_exception_class(), exception_cleanup: exception_cleanup, private: [0; uw::unwinder_private_data_size], @@ -60,30 +144,9 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { 0x4d4f5a_00_52555354 } -// We could implement our personality routine in pure Rust, however exception -// info decoding is tedious. More importantly, personality routines have to -// handle various platform quirks, which are not fun to maintain. For this -// reason, we attempt to reuse personality routine of the C language: -// __gcc_personality_v0. -// -// Since C does not support exception catching, __gcc_personality_v0 simply -// always returns _URC_CONTINUE_UNWIND in search phase, and always returns -// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase. -// -// This is pretty close to Rust's exception handling approach, except that Rust -// does have a single "catch-all" handler at the bottom of each thread's stack. -// So we have two versions of the personality routine: -// - rust_eh_personality, used by all cleanup landing pads, which never catches, -// so the behavior of __gcc_personality_v0 is perfectly adequate there, and -// - rust_eh_personality_catch, used only by rust_try(), which always catches. -// -// See also: rustc_trans::trans::intrinsic::trans_gnu_try - -#[cfg(all(not(target_arch = "arm"), - not(all(windows, target_arch = "x86_64")), - not(test)))] +#[cfg(all(not(target_arch = "arm"), not(test)))] pub mod eabi { - use sys_common::libunwind as uw; + use sys::libunwind as uw; use libc::c_int; extern { @@ -139,7 +202,7 @@ pub mod eabi { #[cfg(all(target_os = "ios", target_arch = "arm", not(test)))] pub mod eabi { - use sys_common::libunwind as uw; + use sys::libunwind as uw; use libc::c_int; extern { @@ -194,7 +257,7 @@ pub mod eabi { // but otherwise works the same. #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))] pub mod eabi { - use sys_common::libunwind as uw; + use sys::libunwind as uw; use libc::c_int; extern { @@ -236,38 +299,3 @@ pub mod eabi { } } } - -// See docs in the `unwind` module. -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu", not(test)))] -#[lang = "eh_unwind_resume"] -#[unwind] -unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { - uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); -} - -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub mod eh_frame_registry { - // The implementation of stack unwinding is (for now) deferred to libgcc_eh, however Rust - // crates use these Rust-specific entry points to avoid potential clashes with GCC runtime. - // See also: rtbegin.rs, `unwind` module. - - #[link(name = "gcc_eh")] - extern { - fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8); - fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8); - } - #[cfg(not(test))] - #[no_mangle] - #[unstable(feature = "libstd_sys_internals", issue = "0")] - pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8, - object: *mut u8) { - __register_frame_info(eh_frame_begin, object); - } - #[cfg(not(test))] - #[no_mangle] - #[unstable(feature = "libstd_sys_internals", issue = "0")] - pub unsafe extern fn rust_eh_unregister_frames(eh_frame_begin: *const u8, - object: *mut u8) { - __deregister_frame_info(eh_frame_begin, object); - } -} diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index d106bc3285cb1..0b6aa66b3accb 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -27,29 +27,25 @@ use io::prelude::*; use dynamic_lib::DynamicLibrary; +use ffi::CStr; use io; -use libc::c_void; +use libc::{c_ulong, c_int, c_char, c_void}; use mem; use path::Path; use ptr; use sync::StaticMutex; use sys::c; - -macro_rules! sym{ ($lib:expr, $e:expr, $t:ident) => (unsafe { - let lib = $lib; - match lib.symbol($e) { - Ok(f) => $crate::mem::transmute::<*mut u8, $t>(f), - Err(..) => return Ok(()) - } -}) } - -#[cfg(target_env = "msvc")] -#[path = "printing/msvc.rs"] -mod printing; - -#[cfg(target_env = "gnu")] -#[path = "printing/gnu.rs"] -mod printing; +use sys_common::backtrace::{output, output_fileline}; + +macro_rules! sym { + ($lib:expr, $e:expr, $t:ident) => (unsafe { + let lib = $lib; + match lib.symbol($e) { + Ok(f) => $crate::mem::transmute::<*mut u8, $t>(f), + Err(..) => return Ok(()) + } + }) +} type SymFromAddrFn = extern "system" fn(c::HANDLE, u64, *mut u64, @@ -151,9 +147,49 @@ pub fn write(w: &mut Write) -> io::Result<()> { i += 1; if i >= 0 { - try!(printing::print(w, i, addr-1, &dbghelp, process)); + try!(print(w, i, addr-1, &dbghelp, process)); } } Ok(()) } + +fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary, + process: c::HANDLE) -> io::Result<()> { + let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn); + let SymGetLineFromAddr64 = sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn); + + let mut info: c::SYMBOL_INFO = unsafe { mem::zeroed() }; + info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; + + let mut displacement = 0u64; + let ret = SymFromAddr(process, addr, &mut displacement, &mut info); + + let name = if ret == c::TRUE { + let ptr = info.Name.as_ptr() as *const c_char; + Some(unsafe { CStr::from_ptr(ptr).to_bytes() }) + } else { + None + }; + + try!(output(w, i, addr as usize as *mut c_void, name)); + + // Now find out the filename and line number + let mut line: c::IMAGEHLP_LINE64 = unsafe { mem::zeroed() }; + line.SizeOfStruct = ::mem::size_of::() as u32; + + let mut displacement = 0u32; + let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line); + if ret == c::TRUE { + output_fileline(w, + unsafe { CStr::from_ptr(line.Filename).to_bytes() }, + line.LineNumber as c_int, + false) + } else { + Ok(()) + } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9ecef5ee92c71..684ad9bd6c045 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -35,10 +35,11 @@ pub mod pipe; pub mod process; pub mod rwlock; pub mod stack_overflow; +pub mod stdio; pub mod thread; pub mod thread_local; pub mod time; -pub mod stdio; +pub mod unwind; #[cfg(not(test))] pub fn init() { diff --git a/src/libstd/sys/windows/printing/gnu.rs b/src/libstd/sys/windows/printing/gnu.rs deleted file mode 100644 index c1367d5381da1..0000000000000 --- a/src/libstd/sys/windows/printing/gnu.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] - -use dynamic_lib::DynamicLibrary; -use io::prelude::*; -use io; -use sys::c; -use libc::c_void; - -use sys_common::gnu::libbacktrace; - -pub fn print(w: &mut Write, i: isize, addr: u64, _: &DynamicLibrary, _: c::HANDLE) - -> io::Result<()> { - let addr = addr as usize as *mut c_void; - libbacktrace::print(w, i, addr, addr) -} diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs deleted file mode 100644 index d04691a6a4783..0000000000000 --- a/src/libstd/sys/windows/printing/msvc.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] - -use dynamic_lib::DynamicLibrary; -use ffi::CStr; -use io::prelude::*; -use io; -use libc::{c_ulong, c_int, c_char, c_void}; -use mem; -use super::{SymFromAddrFn, SymGetLineFromAddr64Fn}; -use sys::c; -use sys_common::backtrace::{output, output_fileline}; - -pub fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary, - process: c::HANDLE) -> io::Result<()> { - let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn); - let SymGetLineFromAddr64 = sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn); - - let mut info: c::SYMBOL_INFO = unsafe { mem::zeroed() }; - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - let mut displacement = 0u64; - let ret = SymFromAddr(process, addr, &mut displacement, &mut info); - - let name = if ret == c::TRUE { - let ptr = info.Name.as_ptr() as *const c_char; - Some(unsafe { CStr::from_ptr(ptr).to_bytes() }) - } else { - None - }; - - try!(output(w, i, addr as usize as *mut c_void, name)); - - // Now find out the filename and line number - let mut line: c::IMAGEHLP_LINE64 = unsafe { mem::zeroed() }; - line.SizeOfStruct = ::mem::size_of::() as u32; - - let mut displacement = 0u32; - let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line); - if ret == c::TRUE { - output_fileline(w, - unsafe { CStr::from_ptr(line.Filename).to_bytes() }, - line.LineNumber as c_int, - false) - } else { - Ok(()) - } -} diff --git a/src/libstd/sys/common/unwind/seh.rs b/src/libstd/sys/windows/unwind.rs similarity index 96% rename from src/libstd/sys/common/unwind/seh.rs rename to src/libstd/sys/windows/unwind.rs index f8d3a92b3b65b..96fc5d69d2ab6 100644 --- a/src/libstd/sys/common/unwind/seh.rs +++ b/src/libstd/sys/windows/unwind.rs @@ -56,13 +56,6 @@ //! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx //! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions -use sys::c; - -// A code which indicates panics that originate from Rust. Note that some of the -// upper bits are used by the system so we just set them to 0 and ignore them. -// 0x 0 R S T -const RUST_PANIC: c::DWORD = 0x00525354; - pub use self::imp::*; #[cfg(stage0)] @@ -100,9 +93,14 @@ mod imp { use any::Any; use mem; use raw; - use super::RUST_PANIC; use sys::c; + // A code which indicates panics that originate from Rust. Note that some of + // the upper bits are used by the system so we just set them to 0 and ignore + // them. + // 0x 0 R S T + const RUST_PANIC: c::DWORD = 0x00525354; + pub unsafe fn panic(data: Box) -> ! { // As mentioned above, the call stack here is preserved while the filter // functions are running, so it's ok to pass stack-local arrays into diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs deleted file mode 100644 index d1b6fe6655ac6..0000000000000 --- a/src/rtstartup/rsbegin.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// rsbegin.o and rsend.o are the so called "compiler runtime startup objects". -// They contain code needed to correctly initialize the compiler runtime. -// -// When an executable or dylib image is linked, all user code and libraries are -// "sandwiched" between these two object files, so code or data from rsbegin.o -// become first in the respective sections of the image, whereas code and data -// from rsend.o become the last ones. This effect can be used to place symbols -// at the beginning or at the end of a section, as well as to insert any required -// headers or footers. -// -// Note that the actual module entry point is located in the C runtime startup -// object (usually called `crtX.o), which then invokes initialization callbacks -// of other runtime components (registered via yet another special image section). - -#![crate_type="rlib"] -#![no_std] -#![allow(non_camel_case_types)] - -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub mod eh_frames -{ - #[no_mangle] - #[link_section = ".eh_frame"] - // Marks beginning of the stack frame unwind info section - pub static __EH_FRAME_BEGIN__: [u8; 0] = []; - - // Scratch space for unwinder's internal book-keeping. - // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h. - static mut obj: [isize; 6] = [0; 6]; - - // Unwind info registration/deregistration routines. - // See the docs of `unwind` module in libstd. - extern { - fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8); - fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8); - } - - unsafe fn init() { - // register unwind info on module startup - rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut obj as *mut _ as *mut u8); - } - - unsafe fn uninit() { - // unregister on shutdown - rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut obj as *mut _ as *mut u8); - } - - // MSVC-specific init/uninit routine registration - pub mod ms_init - { - // .CRT$X?? sections are roughly analogous to ELF's .init_array and .fini_array, - // except that they exploit the fact that linker will sort them alphabitically, - // so e.g. sections with names between .CRT$XIA and .CRT$XIZ are guaranteed to be - // placed between those two, without requiring any ordering of objects on the linker - // command line. - // Note that ordering of same-named sections from different objects is not guaranteed. - // Since .CRT$XIA contains init array's header symbol, which must always come first, - // we place our initialization callback into .CRT$XIB. - - #[link_section = ".CRT$XIB"] // .CRT$XI? : C initialization callbacks - pub static P_INIT: unsafe fn() = super::init; - - #[link_section = ".CRT$XTY"] // .CRT$XT? : C termination callbacks - pub static P_UNINIT: unsafe fn() = super::uninit; - } -} diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs deleted file mode 100644 index 5e4e13ebd05e4..0000000000000 --- a/src/rtstartup/rsend.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// See rsbegin.rs for details. - -#![crate_type="rlib"] -#![no_std] - -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub mod eh_frames -{ - // Terminate the frame unwind info section with a 0 as a sentinel; - // this would be the 'length' field in a real FDE. - #[no_mangle] - #[link_section = ".eh_frame"] - pub static __EH_FRAME_END__: u32 = 0; -} diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index 41ceb924ab306..5c9d2e53a6468 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -18,9 +18,6 @@ extern crate libc; #[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "eh_unwind_resume"] -extern fn eh_unwind_resume() {} - #[lang = "panic_fmt"] extern fn rust_begin_unwind(msg: core::fmt::Arguments, file: &'static str, line: u32) -> ! { diff --git a/src/test/compile-fail/no_owned_box_lang_item.rs b/src/test/compile-fail/no_owned_box_lang_item.rs index 72eb687adc602..1f42245765d0c 100644 --- a/src/test/compile-fail/no_owned_box_lang_item.rs +++ b/src/test/compile-fail/no_owned_box_lang_item.rs @@ -20,5 +20,4 @@ fn main() { } #[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs index eb399e07d859d..7f595f2c4655d 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs @@ -10,7 +10,7 @@ #![feature(rustc_attrs)] -// ignore-msvc: FIXME(#30941) +// ignore-windows: FIXME(#30941) // error-pattern:converging_fn called // error-pattern:0 dropped // error-pattern:exit diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs index df4ead387b91f..97c47cc43fccc 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs @@ -10,7 +10,7 @@ #![feature(rustc_attrs)] -// ignore-msvc: FIXME(#30941) +// ignore-windows: FIXME(#30941) // error-pattern:complex called // error-pattern:dropped // error-pattern:exit diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs index cbe8793cceb22..c4ff228c1ac4a 100644 --- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs @@ -10,7 +10,7 @@ #![feature(rustc_attrs)] -// ignore-msvc: FIXME(#30941) +// ignore-windows: FIXME(#30941) // error-pattern:diverging_fn called // error-pattern:0 dropped diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs index 8a15afb328a92..65d9fddb9c8c0 100644 --- a/src/test/run-make/no-duplicate-libs/bar.rs +++ b/src/test/run-make/no-duplicate-libs/bar.rs @@ -18,7 +18,4 @@ extern crate libc; pub extern fn bar() {} #[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs index ab8d2eca9363f..729153a471a90 100644 --- a/src/test/run-make/no-duplicate-libs/foo.rs +++ b/src/test/run-make/no-duplicate-libs/foo.rs @@ -18,7 +18,4 @@ extern crate libc; pub extern fn foo() {} #[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 3fb52f8c8b4dc..effc3bcf802cf 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -89,7 +89,7 @@ fn runtest(me: &str) { } fn main() { - if cfg!(windows) && cfg!(target_arch = "x86") && cfg!(target_env = "gnu") { + if cfg!(windows) && cfg!(target_env = "gnu") { return } diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index b11970560d59a..4298cb3be1897 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -21,10 +21,7 @@ extern { fn puts(s: *const u8); } extern "rust-intrinsic" { fn transmute(t: T) -> U; } #[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} #[start] fn main(_: isize, _: *const *const u8) -> isize {