Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Remove dependency on libgcc-dw2-1.dll from win32 executables. #29177

Merged
merged 10 commits into from
Nov 1, 2015
Prev Previous commit
Next Next commit
Moar comments.
  • Loading branch information
vadimcn committed Oct 21, 2015
commit d710f8ba1f2ef8b35d3603875b454955d2d2585c
6 changes: 3 additions & 3 deletions src/librustc_back/target/windows_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ pub fn opts() -> TargetOptions {
"-nostdlib".to_string(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this necessary? I thought that -nodefaultlibs would do what this comment indicates, and the man pages at least indicate that -nostdlib means that only the directories on the command line will be searched (e.g. doesn't mention anything about startup files or objects).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My man page's section for -nostdlib begins with this exact sentence . I could have used -nostartfiles since we are also passing -nodefaultlibs, but just to make sure...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait I was looking at the man page for ld not gcc, nevermind!

),
pre_link_objects_exe: vec!(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you be sure to add a comment for these fields? They'll probably want to point somewhere else, but just an indication about where to find info about what they're doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are explained in the struct definition. Is that not enough?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I was looking more of a "why are these passed on this platform" moreso than "what does this field do"

"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!(
Expand Down
9 changes: 0 additions & 9 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/libstd/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions src/libstd/sys/common/unwind/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you be sure to add a comment here pointing to a location which documents what this all is?

// 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);
Expand Down
41 changes: 24 additions & 17 deletions src/libstd/sys/common/unwind/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
21 changes: 20 additions & 1 deletion src/rtstartup/rsbegin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,21 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, so this is about the location that it'd be awesome to have a nice long doc block explaining what this is all doing. Could you add some docs here basically describing the whole scheme for why this works and such? Things like:

  • Why we have our custom startup objects (e.g. why the standard ones aren't sufficient).
  • What these startup objects are doing, e.g. what's happening in the standard library and what's happening in MinGW and where it's all getting linked.
  • What each item is in these objects.

etc

// 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]
Expand All @@ -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] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to clarify, this works because:

  • The linker will construct the .eh_frame section from the list of items contained within it on the command line. This is, however, guarantee to be the first, so &__EH_FRAME_BEGIN__ is guaranteed to be a pointer to the start of the section.
  • Similarly, rsend.o is guarnateed to be at the end, so it's guaranteed that &__EH_FRAME_END__ is at the end of the section.

Does that sound right? Also out of curiosity, what is the __EH_FRAME_END__ symbol used for? It's not explicitly referenced here, so is it referenced or dynamically loaded from the CRT or elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's my understanding of how this works.

Also out of curiosity, what is the EH_FRAME_END symbol used for?

It's used to support the weight of eh_frame section, thus the extra wide base.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm ok, and by "weight" and "extra wide base" do you mean how __EH_FRAME_END__ is a u32 while the start is a [u8; 0]? (a fact I just realized)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...the other reason is that you can't have a static variable (the zero footer) without a name (at least that I know of).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By extra wide base I meant the underscores :) just kidding :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh dear it looks like my ignorance is leaking, a zero footer makes sense to me!


// 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,
Expand Down
2 changes: 2 additions & 0 deletions src/rtstartup/rsend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down