From 0b3df19c6a02a743dae904245c6f98424e75af8c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 12 Mar 2014 09:49:38 -0700 Subject: [PATCH] rustc: Tweak where -lmorestack is on link commands In removing many fields from the crate map, executables no longer always have an explicit dependency on all upstream libraries. This means that the linker is no longer picking them up as it used to. To the best of my knowledge, the current situation is happening: * On linux, we're passing the --as-needed flag to the linker, meaning that libraries are stripped out if there are no references to symbols in them. * Executables may not reference libstd at all, such as "fn main() {}" * When linking, the linker will discard libstd because there are no references to symbols in it. I presume that this means that all previous libs have had all their symbols resolved, so none of the libs are pulling in libstd as a dependency. * The only real dependence on libstd comes from the rust_stack_exhausted symbol (which comes from libmorestack), but -lmorestack is at the end so by the time this comes up libstd is completely gone, leading to undefined references to rust_stack_exhausted I'm not entirely convinced that this is what's happening, but it appears to be along these lines. The one thing that I'm sure of is that removing the crate map (and hence implicit dependency on all upstream libraries) has changed how objects depend on upstream libraries. --- src/librustc/back/link.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 1c1121f0940..d68fa0ca241 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -1085,6 +1085,23 @@ fn link_args(sess: Session, ~"-o", out_filename.as_str().unwrap().to_owned(), obj_filename.as_str().unwrap().to_owned()]); + // Stack growth requires statically linking a __morestack function. Note + // that this is listed *before* all other libraries, even though it may be + // used to resolve symbols in other libraries. The only case that this + // wouldn't be pulled in by the object file is if the object file had no + // functions. + // + // If we're building an executable, there must be at least one function (the + // main function), and if we're building a dylib then we don't need it for + // later libraries because they're all dylibs (not rlibs). + // + // I'm honestly not entirely sure why this needs to come first. Apparently + // the --as-needed flag above sometimes strips out libstd from the command + // line, but inserting this farther to the left makes the + // "rust_stack_exhausted" symbol an outstanding undefined symbol, which + // flags libstd as a required library (or whatever provides the symbol). + args.push(~"-lmorestack"); + // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. @@ -1200,11 +1217,13 @@ fn link_args(sess: Session, args.push_all(rpath::get_rpath_flags(sess, out_filename).as_slice()); } - // Stack growth requires statically linking a __morestack function - args.push(~"-lmorestack"); - // compiler-rt contains implementations of low-level LLVM helpers - // It should go before platform and user libraries, so it has first dibs - // at resolving symbols that also appear in libgcc. + // compiler-rt contains implementations of low-level LLVM helpers. This is + // used to resolve symbols from the object file we just created, as well as + // any system static libraries that may be expecting gcc instead. Most + // symbols in libgcc also appear in compiler-rt. + // + // This is the end of the command line, so this library is used to resolve + // *all* undefined symbols in all other libraries, and this is intentional. args.push(~"-lcompiler-rt"); // Finally add all the linker arguments provided on the command line along