Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRemove dependency on libgcc-dw2-1.dll from win32 executables. #29177
Conversation
vadimcn
added some commits
Oct 18, 2015
rust-highfive
assigned
arielb1
Oct 20, 2015
This comment has been minimized.
This comment has been minimized.
|
r? @arielb1 (rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
rust-highfive
assigned
alexcrichton
and unassigned
arielb1
Oct 20, 2015
This comment has been minimized.
This comment has been minimized.
|
@vadimcn you never cease to amaze me, fantastic work! I'll try to get around to this tomorrow, and you may be met with a barrage of questions :) |
retep998
reviewed
Oct 20, 2015
| "rsbegin.o".to_string(), | ||
| ), | ||
| late_link_args: vec!( | ||
| "-lmingwex".to_string(), |
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| # $(2) - object name | ||
| define COPY_LIBC_STARTUP | ||
|
|
||
| $(1)/$(2) : $$(CFG_LIBC_DIR)/$(2) |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Perhaps instead of CFG_LIBC_DIR this could use gcc -print-file-name=$(2) to figure out the location of the object?
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| @@ -22,3 +22,4 @@ 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_LIBC_STARTUP_OBJECTS_i686-pc-windows-gnu := crt2.o dllcrt2.o | |||
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Could you add a comment here as to why these two objects are being included? It's fine to be a "pointer comment" to somewhere else as well (same with x86_64 below)
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
I have no strong objection... it just... doesn't seem scalable to comment on a variable at every point of use. Eventually, when we get rid of "gcc as a linker driver" of all platforms (we want that, right?), this line will be repeated in every one of those .mk files...
The purpose is explained in targets.mk, where one can arrive via a simple grep search.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Ah yeah that's fine, just want to make sure that there's enough data here for someone to figure out why all this exists in the future.
alexcrichton
reviewed
Oct 20, 2015
| $$(eval $$(call TARGET_RUSTRT_STARTUP_OBJ,$(1),$(2),$(3),$$(obj))) ) | ||
|
|
||
| $$(foreach obj,$$(CFG_LIBC_STARTUP_OBJECTS_$(2)), \ | ||
| $$(eval $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core : $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Oh wow interesting, I had no idea this was even valid syntax... Could this perhaps use something like:
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.core : $$(foreach obj,..,$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))That'd at least keep it a little more conventional with the rest of the makefiles
alexcrichton
reviewed
Oct 20, 2015
| @@ -140,6 +140,8 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { | |||
| # #[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 () {} | |||
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Hm, these are so volatile that it seems like a pretty good indication to me that we either need to start ignoring these tests or figure out a better way to deal with this, it's unfortunate to have these keep getting duplicated... Not critical though!
alexcrichton
reviewed
Oct 20, 2015
| @@ -63,7 +60,32 @@ 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(), | |||
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
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).
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
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...
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| "-ladvapi32".to_string(), | ||
| "-lshell32".to_string(), | ||
| "-luser32".to_string(), | ||
| "-lkernel32".to_string(), |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
This is an interesting list! Were these added because no_default_libraries is now true? In the spirit of "no default libraries" none of these should actually be specified (e.g. they have to be explicitly linked in). This has the risk of being a breaking change, however, but it's one that I think I'd be fine stomaching.
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
The trouble is, they have to come after all other libs, and be in this specific sequence. Just consider them a part of the platform runtime. I think compiler-rt should also go here, btw.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Most of our other platforms don't implicitly pass -l arguments because they pass -nodefaultlibs to gcc, and when that started I just didn't take care of MinGW at the time as I didn't really fully understand it. So in theory libraries like libstd and liblibc and such are the ones that pass these -l flags, and they can control the ordering via the normal methods (e.g. in the source or via the crate DAG).
The compiler-rt library is passed by the compiler at the very end of the linker, and it's got a flag in the custom target spec as well to say "don't pass this as it's not available on this platform"
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
I meant that we should just stick compiler-rt into late_link_args and eliminate its special status.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Ah yeah that's a good point, but probably good to consider separately!
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 23, 2015
Member
Hm it may be the case that some parts of those previous libraries depend on things like advapi32, but I was able to succesfully compile an executable with just:
-lmingw32 -lmingwex -lkernel32 -lmsvcrt -lgcc
If we include mingwex or mingw32 I think we must include gcc because they're probably generated by gcc (and need the intrinsics). I think we can successfully link without advapi32, shell32, and user32, though?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 23, 2015
Author
Contributor
Ah, hm. I stand corrected!
Well, on second look, there is a small chance of backcompat fall-out:
nm -A -u libmingwex.a | grep __imp__ mostly shows symbols from kernel32, but not all of them are:
lib32_libmingwex_a-getlogin.o: U __imp__GetUserNameA@8 is from advapi32.dll,
lib32_libmingwex_a-wassert.o: U __imp__MessageBoxW@16 is from user32.dll
The last one actually breaks linking when building libflate, because I guess miniz uses assert internally.
There might be other crates who are in the same boat.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 23, 2015
Member
In terms of intrinsically required libraries by the compiler, however, I don't these may want to not be in this list. These libraries are injected into all compilations ever for this target, and it can end up creating hidden dependencies and such (like in this case), when the "most correct" thing to do would probably be to only include those the compiler itself requires. I think we need mingw32/mingwex to build executables as crt2.o references some symbols from those, and then kernel32/msvcrt/gcc are dependencies of those libraries, so those are all required for dlls/exes. If libflate is the one, though, that depends on advapi32 or user32, then libflate itself should declare that I think (it should also in theory declare that it depends on mingwex).
That being said, though, we probably want to just link these into the standard library (e.g. add -luser32 which I think may be missing today) and we should already be covered by -ladvapi32 in the standard library?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 23, 2015
Author
Contributor
libflate does not depend on user32 directly, it depends on mingwex, which depends on user32.
Assert is actually a bit of a weird case, because normally assert's helper function lives libc (I think). Linking to mingwex by default papers over the fact that that on mingw it isn't provided by libc (though msvcrt does export assert, not sure why mingw folks were not happy with it).
I worry that this might be rather common to have crates that depend on a C library, that uses assert (and thus depends on mingwex), which don't specify mingwex as a #[link] dependency, because on all other platforms linking to libc is enough.
How about we drop advapi32 and shell32 but keep user32? (see my last commit)
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| // Do not use the standard system startup files or libraries when linking | ||
| "-nostdlib".to_string(), | ||
| ), | ||
| pre_link_objects_exe: vec!( |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
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.
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
They are explained in the struct definition. Is that not enough?
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Ah I was looking more of a "why are these passed on this platform" moreso than "what does this field do"
alexcrichton
reviewed
Oct 20, 2015
| @@ -1315,7 +1315,7 @@ fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |||
| // The "catch-resume" block is where we're running this landing pad but | |||
| // we actually need to not catch the exception, so just resume the | |||
| // exception to return. | |||
| Resume(catch_resume, vals); | |||
| trans_unwind_resume(catch_resume, vals); | |||
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
This in theory isn't necessary, right? (it's only used for MSVC targets which don't have custom_unwind_resume set?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
Hmm, true. Still, it's probably a good thing to centralize checking of the custom_unwind_resume flag?
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] | ||
| pub mod __frame_registry { | ||
| pub use sys_common::unwind::imp::eh_frame_registry::*; | ||
| } |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Could this be moved into src/libstd/rt.rs? That's got other public symbols like some unwinding ones, and it's already auto-unstable as well.
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| #[cfg_attr(target_os = "bitrig", | ||
| link(name = "c++abi"))] | ||
| #[cfg_attr(all(target_os = "windows", target_env="gnu"), | ||
| link(name = "gcc_eh"))] |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
So just to clarify gcc_eh is a static library which contains all these unwinding functions? We were just previously linking to the dynamic version and using those instead?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
Yes, gcc_eh exports all those _Unwind_XXX functions. The dynamic version of libgcc, is actually a bundle of libgcc.a and libgcc_eh.a.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Ah ok, so I know that with MinGW you can sometimes get seh, dwarf, or sjlj exceptions, so does that matter here? For example I think we're basically only compatible with the dwarf strategy on 32-bit and seh on 64 (right?) and is gcc_eh just whatever the installation happens to be? Or is it guaranteed to always be the one we use?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
Yes, gcc_eh depends on the flavor of gcc installed. If it's the sjlj one, we'll just fail to link, I think.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 28, 2015
Member
Ah and as one final clarification, after talking with @brson, so this means that we are statically linking the unwinding support into the standard library? If so, should this be kind = "static"? Also if so, we may want to checkup on the licenses to ensure that we're covered to statically link this code from gcc (we probably are though)
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 28, 2015
Author
Contributor
If so, should this be kind = "static"?
It probably should. However this doesn't work right now, because it's in the system libs directory, which rustc is not aware of, so it fails to find it.
Also if so, we may want to checkup on the licenses to ensure that we're covered to statically link this code from gcc (we probably are though)
Yes, I believe so. libgcc_eh is covered by the linking exception.
This comment has been minimized.
This comment has been minimized.
retep998
Oct 28, 2015
Member
If so, should this be kind = "static"?
It probably should. However this doesn't work right now, because it's in the system libs directory, which rustc is not aware of, so it fails to find it.
This is the same issue that I've been complaining about with getting dllimport fixed.
alexcrichton
reviewed
Oct 20, 2015
| #[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); |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
If this just calls the standard _Unwind_Resume, how come a custom lang item is needed here? Shouldn't the gnu-32 target not need this?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
I didn't want to leave it up to the linker to choose which _Unwind_Resume this gets resolved to (what if -lgcc_s is added by the user?).
Having this as a lang item seems safer (also conceptually tidier, IMO, since this is a part of language runtime, just like eh_personality).
This comment has been minimized.
This comment has been minimized.
alexcrichton
reviewed
Oct 20, 2015
| } | ||
|
|
||
| #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] | ||
| pub mod eh_frame_registry { |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Can you be sure to add a comment here pointing to a location which documents what this all is?
alexcrichton
reviewed
Oct 20, 2015
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
| // option. This file may not be copied, modified, or distributed | ||
| // except according to those terms. | ||
|
|
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
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
alexcrichton
reviewed
Oct 20, 2015
| } | ||
| #[cfg(not(test))] | ||
| #[no_mangle] | ||
| pub unsafe extern fn rust_eh_register_frames(eh_frame_begin: *const u8, |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 20, 2015
Member
Could the symbol references in rsstart.o just point to __register_frame_info directly instead of going through the standard library? Or is there a downside to that?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 20, 2015
Author
Contributor
I wanted these symbols to be Rust-specific for more control over linkage. __register_frame_info should be completely encapsulated in libstd. We could replace gcc unwinder with some other implementation after all.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Ah ok, could you be sure to add this in the doc comment down below? Sounds fine to me!
vadimcn
added some commits
Oct 21, 2015
This comment has been minimized.
This comment has been minimized.
|
Looks better? |
alexcrichton
reviewed
Oct 21, 2015
| #[no_mangle] | ||
| #[link_section = ".eh_frame"] | ||
| // Marks beginning of the stack frame unwind info section | ||
| pub static __EH_FRAME_BEGIN__: [u8; 0] = []; |
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
So just to clarify, this works because:
- The linker will construct the
.eh_framesection 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.ois 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?
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
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.
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
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)
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
...the other reason is that you can't have a static variable (the zero footer) without a name (at least that I know of).
This comment has been minimized.
This comment has been minimized.
vadimcn
Oct 21, 2015
Author
Contributor
By extra wide base I meant the underscores :) just kidding :)
This comment has been minimized.
This comment has been minimized.
alexcrichton
Oct 21, 2015
Member
Oh dear it looks like my ignorance is leaking, a zero footer makes sense to me!
This comment has been minimized.
This comment has been minimized.
|
cc @brson, just wanna give you a heads up about the we-are-building-our-own-object-files strategy. It seems fine to me but figured you may want to know! |
This comment has been minimized.
This comment has been minimized.
|
This is basically r+ from me, but I think I'd prefer to hold this off until after the 1.5 beta is released so this lands in 1.6 instead (just so we have some extra time to weed out any problems here). Does that sound ok? |
This comment has been minimized.
This comment has been minimized.
|
That's next Thursday, right? Fine by me. |
This comment has been minimized.
This comment has been minimized.
|
OK cool, now I just wish I could bors r+ date=2015-... |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
Oct 28, 2015
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
Uh-oh, that's a stage0 ICE. Crashes in |
This comment has been minimized.
This comment has been minimized.
|
Looks like this was my own fault. The tricks I played with injection of the |
vadimcn commentedOct 20, 2015
Note: for now, this change only affects
-windows-gnubuilds.So why was this
libgccdylib dependency needed in the first place?The stack unwinder needs to know about locations of unwind tables of all the modules loaded in the current process. The easiest portable way of achieving this is to have each module register itself with the unwinder when loaded into the process. All modules compiled by GCC do this by calling the __register_frame_info() in their startup code (that's
crtbegin.oandcrtend.o, which are automatically linked into any gcc output).Another important piece is that there should be only one copy of the unwinder (and thus unwind tables registry) in the process. This pretty much means that the unwinder must be in a shared library (unless everything is statically linked).
Now, Rust compiler tries very hard to make sure that any given Rust crate appears in the final output just once. So if we link the unwinder statically to one of Rust's crates, everything should be fine.
Unfortunately, GCC startup objects are built under assumption that
libgccis the one true place for the unwind info registry, so I couldn't find any better way than to replace them. So out gocrtbegin/crtend, in comersbegin/rsend!A side benefit of this change is that rustc is now more in control of the command line that goes to the linker, so we could stop using
gccas the linker driver and just invokelddirectly.