diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index fc1e192f1e15d..4fa57726ef5f0 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -65,11 +65,11 @@ pub fn opts() -> TargetOptions { "-nostdlib".to_string(), ), pre_link_objects_exe: vec!( - "crt2.o".to_string(), - "rsbegin.o".to_string(), + "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(), + "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls "rsbegin.o".to_string(), ), late_link_args: vec!( diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f318cde71bd66..a624b3521267a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -400,15 +400,6 @@ pub mod __rand { pub use rand::{thread_rng, ThreadRng, Rng}; } -// 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 explicitly. -#[doc(hidden)] -#[unstable(feature = "eh_frame_registry", issue = "0")] -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub mod __frame_registry { - pub use sys_common::unwind::imp::eh_frame_registry::*; -} - // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 8be0c6f3b3d99..44961611b7bd7 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -32,6 +32,11 @@ use thread::{self, Thread}; // 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/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs index 6d82eb7dfb198..0a598b559514c 100644 --- a/src/libstd/sys/common/unwind/gcc.rs +++ b/src/libstd/sys/common/unwind/gcc.rs @@ -232,6 +232,7 @@ 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] @@ -241,6 +242,10 @@ unsafe extern fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { #[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); diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs index 3978aeb39bc46..e42a4694070cb 100644 --- a/src/libstd/sys/common/unwind/mod.rs +++ b/src/libstd/sys/common/unwind/mod.rs @@ -34,28 +34,35 @@ //! 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, personality routines invoke cleanup code associated -//! with their stack frames (i.e. destructors). Once stack has been unwound down -//! to the handler frame level, unwinding stops and the last personality routine -//! transfers control to its catch block. +//! 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. //! -//! ## Frame unwind info registration +//! Once stack has been unwound down to the handler frame level, unwinding stops +//! and the last personality routine transfers control to the catch block. //! -//! Each module has its own frame unwind info section (usually ".eh_frame"), and -//! unwinder needs to know about all of them in order for unwinding to be able to -//! cross module boundaries. +//! ## `eh_personality` and `eh_unwind_resume` //! -//! On some platforms, like Linux, this is achieved by dynamically enumerating -//! currently loaded modules via the dl_iterate_phdr() API and finding all -//! .eh_frame sections. +//! 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. //! -//! Others, like Windows, require modules to actively register their unwind info -//! sections by calling __register_frame_info() API at startup. In the latter -//! case it is essential that there is only one copy of the unwinder runtime in -//! the process. This is usually achieved by linking to the dynamic version of -//! the unwind runtime. +//! ## Frame unwind info registration //! -//! Currently Rust uses unwind runtime provided by libgcc. +//! 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)] diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 17684b74b7019..af9a01ea2e4f7 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -8,8 +8,21 @@ // 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). + #![feature(no_std)] -#![feature(linkage)] #![crate_type="rlib"] #![no_std] @@ -20,27 +33,33 @@ 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, diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index df7759877e9f8..ecb6a228e1776 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// See rsbegin.rs for details. + #![feature(no_std)] #![crate_type="rlib"]