]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/back/link.rs
Replace all ~"" with "".to_owned()
[rust.git] / src / librustc / back / link.rs
index d68fa0ca24134b24f3fde08d040b6570020b53e4..3a75a027246c66f8719d0f7394a8d5435a7e008d 100644 (file)
 
 use std::c_str::{ToCStr, CString};
 use std::char;
+use std::io::{fs, TempDir, Process};
+use std::io;
 use std::os::consts::{macos, freebsd, linux, android, win32};
 use std::ptr;
 use std::str;
-use std::io;
-use std::io::{fs, TempDir, Process};
-use std::vec_ng::Vec;
+use std::strbuf::StrBuf;
 use flate;
 use serialize::hex::ToHex;
 use syntax::abi;
@@ -54,7 +54,7 @@ pub enum OutputType {
     OutputTypeExe,
 }
 
-pub fn llvm_err(sess: Session, msg: ~str) -> ! {
+pub fn llvm_err(sess: &Session, msg: ~str) -> ! {
     unsafe {
         let cstr = llvm::LLVMRustGetLastError();
         if cstr == ptr::null() {
@@ -68,7 +68,7 @@ pub fn llvm_err(sess: Session, msg: ~str) -> ! {
 }
 
 pub fn WriteOutputFile(
-        sess: Session,
+        sess: &Session,
         target: lib::llvm::TargetMachineRef,
         pm: lib::llvm::PassManagerRef,
         m: ModuleRef,
@@ -79,7 +79,7 @@ pub fn WriteOutputFile(
             let result = llvm::LLVMRustWriteOutputFile(
                     target, pm, m, output, file_type);
             if !result {
-                llvm_err(sess, ~"could not write output");
+                llvm_err(sess, "could not write output".to_owned());
             }
         })
     }
@@ -103,9 +103,8 @@ pub mod write {
 
     use std::c_str::ToCStr;
     use std::io::Process;
-    use std::libc::{c_uint, c_int};
+    use libc::{c_uint, c_int};
     use std::str;
-    use std::vec_ng::Vec;
 
     // On android, we by default compile for armv7 processors. This enables
     // things like double word CAS instructions (rather than emulating them)
@@ -125,7 +124,7 @@ fn target_feature<'a>(sess: &'a Session) -> &'a str {
         }
     }
 
-    pub fn run_passes(sess: Session,
+    pub fn run_passes(sess: &Session,
                       trans: &CrateTranslation,
                       output_types: &[OutputType],
                       output: &OutputFilenames) {
@@ -154,13 +153,26 @@ pub fn run_passes(sess: Session,
                              (sess.targ_cfg.os == abi::OsMacos &&
                               sess.targ_cfg.arch == abi::X86_64);
 
+            let reloc_model = match sess.opts.cg.relocation_model.as_slice() {
+                "pic" => lib::llvm::RelocPIC,
+                "static" => lib::llvm::RelocStatic,
+                "default" => lib::llvm::RelocDefault,
+                "dynamic-no-pic" => lib::llvm::RelocDynamicNoPic,
+                _ => {
+                    sess.err(format!("{} is not a valid relocation mode",
+                             sess.opts.cg.relocation_model));
+                    sess.abort_if_errors();
+                    return;
+                }
+            };
+
             let tm = sess.targ_cfg.target_strs.target_triple.with_c_str(|t| {
                 sess.opts.cg.target_cpu.with_c_str(|cpu| {
-                    target_feature(&sess).with_c_str(|features| {
+                    target_feature(sess).with_c_str(|features| {
                         llvm::LLVMRustCreateTargetMachine(
                             t, cpu, features,
                             lib::llvm::CodeModelDefault,
-                            lib::llvm::RelocPIC,
+                            reloc_model,
                             opt_level,
                             true,
                             use_softfp,
@@ -211,9 +223,8 @@ pub fn run_passes(sess: Session,
             // Emit the bytecode if we're either saving our temporaries or
             // emitting an rlib. Whenever an rlib is created, the bytecode is
             // inserted into the archive in order to allow LTO against it.
-            let crate_types = sess.crate_types.borrow();
             if sess.opts.cg.save_temps ||
-               (crate_types.get().contains(&session::CrateTypeRlib) &&
+               (sess.crate_types.borrow().contains(&session::CrateTypeRlib) &&
                 sess.opts.output_types.contains(&OutputTypeExe)) {
                 output.temp_path(OutputTypeBitcode).with_c_str(|buf| {
                     llvm::LLVMWriteBitcodeToFile(llmod, buf);
@@ -323,15 +334,15 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
         }
     }
 
-    pub fn run_assembler(sess: Session, outputs: &OutputFilenames) {
+    pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
         let cc = super::get_cc_prog(sess);
         let assembly = outputs.temp_path(OutputTypeAssembly);
         let object = outputs.path(OutputTypeObject);
 
         // FIXME (#9639): This needs to handle non-utf8 paths
         let args = [
-            ~"-c",
-            ~"-o", object.as_str().unwrap().to_owned(),
+            "-c".to_owned(),
+            "-o".to_owned(), object.as_str().unwrap().to_owned(),
             assembly.as_str().unwrap().to_owned()];
 
         debug!("{} '{}'", cc, args.connect("' '"));
@@ -340,7 +351,9 @@ pub fn run_assembler(sess: Session, outputs: &OutputFilenames) {
                 if !prog.status.success() {
                     sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
                     sess.note(format!("{} arguments: '{}'", cc, args.connect("' '")));
-                    sess.note(str::from_utf8_owned(prog.error + prog.output).unwrap());
+                    let mut note = prog.error.clone();
+                    note.push_all(prog.output.as_slice());
+                    sess.note(str::from_utf8(note.as_slice()).unwrap().to_owned());
                     sess.abort_if_errors();
                 }
             },
@@ -351,7 +364,7 @@ pub fn run_assembler(sess: Session, outputs: &OutputFilenames) {
         }
     }
 
-    unsafe fn configure_llvm(sess: Session) {
+    unsafe fn configure_llvm(sess: &Session) {
         use sync::one::{Once, ONCE_INIT};
         static mut INIT: Once = ONCE_INIT;
 
@@ -534,8 +547,11 @@ fn truncated_hash_result(symbol_hasher: &mut Sha256) -> ~str {
 
 
 // This calculates STH for a symbol, as defined above
-fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &mut Sha256,
-               t: ty::t, link_meta: &LinkMeta) -> ~str {
+fn symbol_hash(tcx: &ty::ctxt,
+               symbol_hasher: &mut Sha256,
+               t: ty::t,
+               link_meta: &LinkMeta)
+               -> ~str {
     // NB: do *not* use abbrevs here as we want the symbol names
     // to be independent of one another in the crate.
 
@@ -545,22 +561,21 @@ fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &mut Sha256,
     symbol_hasher.input_str(link_meta.crate_hash.as_str());
     symbol_hasher.input_str("-");
     symbol_hasher.input_str(encoder::encoded_ty(tcx, t));
-    let mut hash = truncated_hash_result(symbol_hasher);
     // Prefix with 'h' so that it never blends into adjacent digits
-    hash.unshift_char('h');
-    hash
+    let mut hash = StrBuf::from_str("h");
+    hash.push_str(truncated_hash_result(symbol_hasher));
+    hash.into_owned()
 }
 
 fn get_symbol_hash(ccx: &CrateContext, t: ty::t) -> ~str {
-    match ccx.type_hashcodes.borrow().get().find(&t) {
+    match ccx.type_hashcodes.borrow().find(&t) {
         Some(h) => return h.to_str(),
         None => {}
     }
 
-    let mut type_hashcodes = ccx.type_hashcodes.borrow_mut();
     let mut symbol_hasher = ccx.symbol_hasher.borrow_mut();
-    let hash = symbol_hash(ccx.tcx, symbol_hasher.get(), t, &ccx.link_meta);
-    type_hashcodes.get().insert(t, hash.clone());
+    let hash = symbol_hash(ccx.tcx(), &mut *symbol_hasher, t, &ccx.link_meta);
+    ccx.type_hashcodes.borrow_mut().insert(t, hash.clone());
     hash
 }
 
@@ -569,7 +584,7 @@ fn get_symbol_hash(ccx: &CrateContext, t: ty::t) -> ~str {
 // gas doesn't!
 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
 pub fn sanitize(s: &str) -> ~str {
-    let mut result = ~"";
+    let mut result = StrBuf::new();
     for c in s.chars() {
         match c {
             // Escape these with $ sequences
@@ -594,19 +609,20 @@ pub fn sanitize(s: &str) -> ~str {
             | '_' | '.' | '$' => result.push_char(c),
 
             _ => {
-                let mut tstr = ~"";
+                let mut tstr = StrBuf::new();
                 char::escape_unicode(c, |c| tstr.push_char(c));
                 result.push_char('$');
-                result.push_str(tstr.slice_from(1));
+                result.push_str(tstr.as_slice().slice_from(1));
             }
         }
     }
 
     // Underscore-qualify anything that didn't start as an ident.
+    let result = result.into_owned();
     if result.len() > 0u &&
         result[0] != '_' as u8 &&
         ! char::is_XID_start(result[0] as char) {
-        return ~"_" + result;
+        return "_".to_owned() + result;
     }
 
     return result;
@@ -629,9 +645,9 @@ pub fn mangle<PI: Iterator<PathElem>>(mut path: PI,
     // To be able to work on all platforms and get *some* reasonable output, we
     // use C++ name-mangling.
 
-    let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
+    let mut n = StrBuf::from_str("_ZN"); // _Z == Begin name-sequence, N == nested
 
-    fn push(n: &mut ~str, s: &str) {
+    fn push(n: &mut StrBuf, s: &str) {
         let sani = sanitize(s);
         n.push_str(format!("{}{}", sani.len(), sani));
     }
@@ -651,7 +667,7 @@ fn push(n: &mut ~str, s: &str) {
     }
 
     n.push_char('E'); // End name-sequence.
-    n
+    n.into_owned()
 }
 
 pub fn exported_name(path: PathElems, hash: &str, vers: &str) -> ~str {
@@ -668,7 +684,7 @@ pub fn exported_name(path: PathElems, hash: &str, vers: &str) -> ~str {
 
 pub fn mangle_exported_name(ccx: &CrateContext, path: PathElems,
                             t: ty::t, id: ast::NodeId) -> ~str {
-    let mut hash = get_symbol_hash(ccx, t);
+    let mut hash = StrBuf::from_owned_str(get_symbol_hash(ccx, t));
 
     // Paths can be completely identical for different nodes,
     // e.g. `fn foo() { { fn a() {} } { fn a() {} } }`, so we
@@ -688,23 +704,15 @@ pub fn mangle_exported_name(ccx: &CrateContext, path: PathElems,
     hash.push_char(EXTRA_CHARS[extra2] as char);
     hash.push_char(EXTRA_CHARS[extra3] as char);
 
-    exported_name(path, hash, ccx.link_meta.crateid.version_or_default())
-}
-
-pub fn mangle_internal_name_by_type_only(ccx: &CrateContext,
-                                         t: ty::t,
-                                         name: &str) -> ~str {
-    let s = ppaux::ty_to_short_str(ccx.tcx, t);
-    let path = [PathName(token::intern(name)),
-                PathName(token::intern(s))];
-    let hash = get_symbol_hash(ccx, t);
-    mangle(ast_map::Values(path.iter()), Some(hash.as_slice()), None)
+    exported_name(path,
+                  hash.as_slice(),
+                  ccx.link_meta.crateid.version_or_default())
 }
 
 pub fn mangle_internal_name_by_type_and_seq(ccx: &CrateContext,
                                             t: ty::t,
                                             name: &str) -> ~str {
-    let s = ppaux::ty_to_str(ccx.tcx, t);
+    let s = ppaux::ty_to_str(ccx.tcx(), t);
     let path = [PathName(token::intern(s)),
                 gensym_name(name)];
     let hash = get_symbol_hash(ccx, t);
@@ -719,7 +727,7 @@ pub fn output_lib_filename(id: &CrateId) -> ~str {
     format!("{}-{}-{}", id.name, crate_id_hash(id), id.version_or_default())
 }
 
-pub fn get_cc_prog(sess: Session) -> ~str {
+pub fn get_cc_prog(sess: &Session) -> ~str {
     match sess.opts.cg.linker {
         Some(ref linker) => return linker.to_owned(),
         None => {}
@@ -730,14 +738,14 @@ pub fn get_cc_prog(sess: Session) -> ~str {
     // instead of hard-coded gcc.
     // For win32, there is no cc command, so we add a condition to make it use gcc.
     match sess.targ_cfg.os {
-        abi::OsWin32 => return ~"gcc",
+        abi::OsWin32 => return "gcc".to_owned(),
         _ => {},
     }
 
     get_system_tool(sess, "cc")
 }
 
-pub fn get_ar_prog(sess: Session) -> ~str {
+pub fn get_ar_prog(sess: &Session) -> ~str {
     match sess.opts.cg.ar {
         Some(ref ar) => return ar.to_owned(),
         None => {}
@@ -746,7 +754,7 @@ pub fn get_ar_prog(sess: Session) -> ~str {
     get_system_tool(sess, "ar")
 }
 
-fn get_system_tool(sess: Session, tool: &str) -> ~str {
+fn get_system_tool(sess: &Session, tool: &str) -> ~str {
     match sess.targ_cfg.os {
         abi::OsAndroid => match sess.opts.cg.android_cross_path {
             Some(ref path) => {
@@ -765,7 +773,7 @@ fn get_system_tool(sess: Session, tool: &str) -> ~str {
     }
 }
 
-fn remove(sess: Session, path: &Path) {
+fn remove(sess: &Session, path: &Path) {
     match fs::unlink(path) {
         Ok(..) => {}
         Err(e) => {
@@ -776,13 +784,12 @@ fn remove(sess: Session, path: &Path) {
 
 /// Perform the linkage portion of the compilation phase. This will generate all
 /// of the requested outputs for this compilation session.
-pub fn link_binary(sess: Session,
+pub fn link_binary(sess: &Session,
                    trans: &CrateTranslation,
                    outputs: &OutputFilenames,
                    id: &CrateId) -> Vec<Path> {
     let mut out_filenames = Vec::new();
-    let crate_types = sess.crate_types.borrow();
-    for &crate_type in crate_types.get().iter() {
+    for &crate_type in sess.crate_types.borrow().iter() {
         let out_file = link_binary_output(sess, trans, crate_type, outputs, id);
         out_filenames.push(out_file);
     }
@@ -830,7 +837,7 @@ pub fn filename_for_input(sess: &Session, crate_type: session::CrateType,
     }
 }
 
-fn link_binary_output(sess: Session,
+fn link_binary_output(sess: &Session,
                       trans: &CrateTranslation,
                       crate_type: session::CrateType,
                       outputs: &OutputFilenames,
@@ -840,7 +847,7 @@ fn link_binary_output(sess: Session,
         Some(ref file) => file.clone(),
         None => {
             let out_filename = outputs.path(OutputTypeExe);
-            filename_for_input(&sess, crate_type, id, &out_filename)
+            filename_for_input(sess, crate_type, id, &out_filename)
         }
     };
 
@@ -883,15 +890,13 @@ fn link_binary_output(sess: Session,
 // rlib primarily contains the object file of the crate, but it also contains
 // all of the object files from native libraries. This is done by unzipping
 // native libraries and inserting all of the contents into this archive.
-fn link_rlib(sess: Session,
-             trans: Option<&CrateTranslation>, // None == no metadata/bytecode
-             obj_filename: &Path,
-             out_filename: &Path) -> Archive {
+fn link_rlib<'a>(sess: &'a Session,
+                 trans: Option<&CrateTranslation>, // None == no metadata/bytecode
+                 obj_filename: &Path,
+                 out_filename: &Path) -> Archive<'a> {
     let mut a = Archive::create(sess, out_filename, obj_filename);
 
-    let used_libraries = sess.cstore.get_used_libraries();
-    let used_libraries = used_libraries.borrow();
-    for &(ref l, kind) in used_libraries.get().iter() {
+    for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
         match kind {
             cstore::NativeStatic => {
                 a.add_native_library(l.as_slice()).unwrap();
@@ -944,16 +949,22 @@ fn link_rlib(sess: Session,
             // For LTO purposes, the bytecode of this library is also inserted
             // into the archive.
             let bc = obj_filename.with_extension("bc");
+            let bc_deflated = obj_filename.with_extension("bc.deflate");
             match fs::File::open(&bc).read_to_end().and_then(|data| {
-                fs::File::create(&bc).write(flate::deflate_bytes(data).as_slice())
+                fs::File::create(&bc_deflated)
+                    .write(match flate::deflate_bytes(data.as_slice()) {
+                        Some(compressed) => compressed,
+                        None => sess.fatal("failed to compress bytecode")
+                     }.as_slice())
             }) {
                 Ok(()) => {}
                 Err(e) => {
-                    sess.err(format!("failed to compress bytecode: {}", e));
+                    sess.err(format!("failed to write compressed bytecode: {}", e));
                     sess.abort_if_errors()
                 }
             }
-            a.add_file(&bc, false);
+            a.add_file(&bc_deflated, false);
+            remove(sess, &bc_deflated);
             if !sess.opts.cg.save_temps &&
                !sess.opts.output_types.contains(&OutputTypeBitcode) {
                 remove(sess, &bc);
@@ -985,7 +996,7 @@ fn link_rlib(sess: Session,
 // There's no need to include metadata in a static archive, so ensure to not
 // link in the metadata object file (and also don't prepare the archive with a
 // metadata file).
-fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
+fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
     let mut a = link_rlib(sess, None, obj_filename, out_filename);
     a.add_native_library("morestack").unwrap();
     a.add_native_library("compiler-rt").unwrap();
@@ -1000,7 +1011,7 @@ fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
             }
         };
         a.add_rlib(&p, name, sess.lto()).unwrap();
-        let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
+        let native_libs = csearch::get_native_libraries(&sess.cstore, cnum);
         for &(kind, ref lib) in native_libs.iter() {
             let name = match kind {
                 cstore::NativeStatic => "static library",
@@ -1016,7 +1027,7 @@ fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
 //
 // This will invoke the system linker/cc to create the resulting file. This
 // links to all upstream files as well.
-fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
+fn link_natively(sess: &Session, dylib: bool, obj_filename: &Path,
                  out_filename: &Path) {
     let tmpdir = TempDir::new("rustc").expect("needs a temp dir");
     // The invocations of cc share some flags across platforms
@@ -1040,7 +1051,9 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
             if !prog.status.success() {
                 sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
                 sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '")));
-                sess.note(str::from_utf8_owned(prog.error + prog.output).unwrap());
+                let mut output = prog.error.clone();
+                output.push_all(prog.output.as_slice());
+                sess.note(str::from_utf8(output.as_slice()).unwrap().to_owned());
                 sess.abort_if_errors();
             }
         },
@@ -1066,7 +1079,7 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
     }
 }
 
-fn link_args(sess: Session,
+fn link_args(sess: &Session,
              dylib: bool,
              tmpdir: &Path,
              obj_filename: &Path,
@@ -1075,14 +1088,14 @@ fn link_args(sess: Session,
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let lib_path = sess.filesearch.get_target_lib_path();
-    let stage: ~str = ~"-L" + lib_path.as_str().unwrap();
+    let lib_path = sess.filesearch().get_target_lib_path();
+    let stage: ~str = "-L".to_owned() + lib_path.as_str().unwrap();
 
     let mut args = vec!(stage);
 
     // FIXME (#9639): This needs to handle non-utf8 paths
     args.push_all([
-        ~"-o", out_filename.as_str().unwrap().to_owned(),
+        "-o".to_owned(), out_filename.as_str().unwrap().to_owned(),
         obj_filename.as_str().unwrap().to_owned()]);
 
     // Stack growth requires statically linking a __morestack function. Note
@@ -1100,7 +1113,7 @@ fn link_args(sess: Session,
     // 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");
+    args.push("-lmorestack".to_owned());
 
     // 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
@@ -1118,14 +1131,14 @@ fn link_args(sess: Session,
     //
     // FIXME(#11937) we should invoke the system linker directly
     if sess.targ_cfg.os != abi::OsWin32 {
-        args.push(~"-nodefaultlibs");
+        args.push("-nodefaultlibs".to_owned());
     }
 
     if sess.targ_cfg.os == abi::OsLinux {
         // GNU-style linkers will use this to omit linking to libraries which
         // don't actually fulfill any relocations, but only for libraries which
         // follow this flag. Thus, use it before specifying libraries to link to.
-        args.push(~"-Wl,--as-needed");
+        args.push("-Wl,--as-needed".to_owned());
 
         // GNU-style linkers support optimization with -O. --gc-sections
         // removes metadata and potentially other useful things, so don't
@@ -1133,7 +1146,7 @@ fn link_args(sess: Session,
         // do.
         if sess.opts.optimize == session::Default ||
            sess.opts.optimize == session::Aggressive {
-            args.push(~"-Wl,-O1");
+            args.push("-Wl,-O1".to_owned());
         }
     }
 
@@ -1141,13 +1154,40 @@ fn link_args(sess: Session,
         // Make sure that we link to the dynamic libgcc, otherwise cross-module
         // DWARF stack unwinding will not work.
         // This behavior may be overridden by --link-args "-static-libgcc"
-        args.push(~"-shared-libgcc");
+        args.push("-shared-libgcc".to_owned());
+
+        // And here, we see obscure linker flags #45. On windows, it has been
+        // found to be necessary to have this flag to compile liblibc.
+        //
+        // First a bit of background. On Windows, the file format is not ELF,
+        // but COFF (at least according to LLVM). COFF doesn't officially allow
+        // for section names over 8 characters, apparently. Our metadata
+        // section, ".note.rustc", you'll note is over 8 characters.
+        //
+        // On more recent versions of gcc on mingw, apparently the section name
+        // is *not* truncated, but rather stored elsewhere in a separate lookup
+        // table. On older versions of gcc, they apparently always truncated the
+        // section names (at least in some cases). Truncating the section name
+        // actually creates "invalid" objects [1] [2], but only for some
+        // introspection tools, not in terms of whether it can be loaded.
+        //
+        // Long story shory, passing this flag forces the linker to *not*
+        // truncate section names (so we can find the metadata section after
+        // it's compiled). The real kicker is that rust compiled just fine on
+        // windows for quite a long time *without* this flag, so I have no idea
+        // why it suddenly started failing for liblibc. Regardless, we
+        // definitely don't want section name truncation, so we're keeping this
+        // flag for windows.
+        //
+        // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
+        // [2] - https://code.google.com/p/go/issues/detail?id=2139
+        args.push("-Wl,--enable-long-section-names".to_owned());
     }
 
     if sess.targ_cfg.os == abi::OsAndroid {
         // Many of the symbols defined in compiler-rt are also defined in libgcc.
         // Android linker doesn't like that by default.
-        args.push(~"-Wl,--allow-multiple-definition");
+        args.push("-Wl,--allow-multiple-definition".to_owned());
     }
 
     // Take careful note of the ordering of the arguments we pass to the linker
@@ -1192,22 +1232,22 @@ fn link_args(sess: Session,
     if dylib {
         // On mac we need to tell the linker to let this library be rpathed
         if sess.targ_cfg.os == abi::OsMacos {
-            args.push(~"-dynamiclib");
-            args.push(~"-Wl,-dylib");
+            args.push("-dynamiclib".to_owned());
+            args.push("-Wl,-dylib".to_owned());
             // FIXME (#9639): This needs to handle non-utf8 paths
             if !sess.opts.cg.no_rpath {
-                args.push(~"-Wl,-install_name,@rpath/" +
+                args.push("-Wl,-install_name,@rpath/".to_owned() +
                           out_filename.filename_str().unwrap());
             }
         } else {
-            args.push(~"-shared")
+            args.push("-shared".to_owned())
         }
     }
 
     if sess.targ_cfg.os == abi::OsFreebsd {
-        args.push_all([~"-L/usr/local/lib",
-                       ~"-L/usr/local/lib/gcc46",
-                       ~"-L/usr/local/lib/gcc44"]);
+        args.push_all(["-L/usr/local/lib".to_owned(),
+                       "-L/usr/local/lib/gcc46".to_owned(),
+                       "-L/usr/local/lib/gcc44".to_owned()]);
     }
 
     // FIXME (#2397): At some point we want to rpath our guesses as to
@@ -1224,14 +1264,12 @@ fn link_args(sess: Session,
     //
     // 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");
+    args.push("-lcompiler-rt".to_owned());
 
     // Finally add all the linker arguments provided on the command line along
     // with any #[link_args] attributes found inside the crate
     args.push_all(sess.opts.cg.link_args.as_slice());
-    let used_link_args = sess.cstore.get_used_link_args();
-    let used_link_args = used_link_args.borrow();
-    for arg in used_link_args.get().iter() {
+    for arg in sess.cstore.get_used_link_args().borrow().iter() {
         args.push(arg.clone());
     }
     return args;
@@ -1248,9 +1286,8 @@ fn link_args(sess: Session,
 // Also note that the native libraries linked here are only the ones located
 // in the current crate. Upstream crates with native library dependencies
 // may have their native library pulled in above.
-fn add_local_native_libraries(args: &mut Vec<~str> , sess: Session) {
-    let addl_lib_search_paths = sess.opts.addl_lib_search_paths.borrow();
-    for path in addl_lib_search_paths.get().iter() {
+fn add_local_native_libraries(args: &mut Vec<~str>, sess: &Session) {
+    for path in sess.opts.addl_lib_search_paths.borrow().iter() {
         // FIXME (#9639): This needs to handle non-utf8 paths
         args.push("-L" + path.as_str().unwrap().to_owned());
     }
@@ -1261,15 +1298,13 @@ fn add_local_native_libraries(args: &mut Vec<~str> , sess: Session) {
         args.push("-L" + path.as_str().unwrap().to_owned());
     }
 
-    let used_libraries = sess.cstore.get_used_libraries();
-    let used_libraries = used_libraries.borrow();
-    for &(ref l, kind) in used_libraries.get().iter() {
+    for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
         match kind {
             cstore::NativeUnknown | cstore::NativeStatic => {
                 args.push("-l" + *l);
             }
             cstore::NativeFramework => {
-                args.push(~"-framework");
+                args.push("-framework".to_owned());
                 args.push(l.to_owned());
             }
         }
@@ -1281,7 +1316,7 @@ fn add_local_native_libraries(args: &mut Vec<~str> , sess: Session) {
 // Rust crates are not considered at all when creating an rlib output. All
 // dependencies will be linked when producing the final output (instead of
 // the intermediate rlib version)
-fn add_upstream_rust_crates(args: &mut Vec<~str> , sess: Session,
+fn add_upstream_rust_crates(args: &mut Vec<~str>, sess: &Session,
                             dylib: bool, tmpdir: &Path) {
 
     // As a limitation of the current implementation, we require that everything
@@ -1302,8 +1337,8 @@ fn add_upstream_rust_crates(args: &mut Vec<~str> , sess: Session,
     // * If one form of linking fails, the second is also attempted
     // * If both forms fail, then we emit an error message
 
-    let dynamic = get_deps(sess.cstore, cstore::RequireDynamic);
-    let statik = get_deps(sess.cstore, cstore::RequireStatic);
+    let dynamic = get_deps(&sess.cstore, cstore::RequireDynamic);
+    let statik = get_deps(&sess.cstore, cstore::RequireStatic);
     match (dynamic, statik, sess.opts.cg.prefer_dynamic, dylib) {
         (_, Some(deps), false, false) => {
             add_static_crates(args, sess, tmpdir, deps)
@@ -1352,9 +1387,8 @@ fn add_upstream_rust_crates(args: &mut Vec<~str> , sess: Session,
     }
 
     // Converts a library file-stem into a cc -l argument
-    fn unlib(config: @session::Config, stem: &str) -> ~str {
-        if stem.starts_with("lib") &&
-            config.os != abi::OsWin32 {
+    fn unlib(config: &session::Config, stem: &str) -> ~str {
+        if stem.starts_with("lib") && config.os != abi::OsWin32 {
             stem.slice(3, stem.len()).to_owned()
         } else {
             stem.to_owned()
@@ -1376,8 +1410,8 @@ fn get_deps(cstore: &cstore::CStore,  preference: cstore::LinkagePreference)
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
-    fn add_static_crates(args: &mut Vec<~str> , sess: Session, tmpdir: &Path,
-                         crates: Vec<(ast::CrateNum, Path)> ) {
+    fn add_static_crates(args: &mut Vec<~str>, sess: &Session, tmpdir: &Path,
+                         crates: Vec<(ast::CrateNum, Path)>) {
         for (cnum, cratepath) in crates.move_iter() {
             // When performing LTO on an executable output, all of the
             // bytecode from the upstream libraries has already been
@@ -1423,7 +1457,7 @@ fn add_static_crates(args: &mut Vec<~str> , sess: Session, tmpdir: &Path,
     }
 
     // Same thing as above, but for dynamic crates instead of static crates.
-    fn add_dynamic_crates(args: &mut Vec<~str> , sess: Session,
+    fn add_dynamic_crates(args: &mut Vec<~str>, sess: &Session,
                           crates: Vec<(ast::CrateNum, Path)> ) {
         // If we're performing LTO, then it should have been previously required
         // that all upstream rust dependencies were available in an rlib format.
@@ -1434,7 +1468,7 @@ fn add_dynamic_crates(args: &mut Vec<~str> , sess: Session,
             // what its name is
             let dir = cratepath.dirname_str().unwrap();
             if !dir.is_empty() { args.push("-L" + dir); }
-            let libarg = unlib(sess.targ_cfg, cratepath.filestem_str().unwrap());
+            let libarg = unlib(&sess.targ_cfg, cratepath.filestem_str().unwrap());
             args.push("-l" + libarg);
         }
     }
@@ -1453,20 +1487,29 @@ fn add_dynamic_crates(args: &mut Vec<~str> , sess: Session,
 //    crate as well.
 //
 // The use case for this is a little subtle. In theory the native
-// dependencies of a crate a purely an implementation detail of the crate
+// dependencies of a crate are purely an implementation detail of the crate
 // itself, but the problem arises with generic and inlined functions. If a
 // generic function calls a native function, then the generic function must
 // be instantiated in the target crate, meaning that the native symbol must
 // also be resolved in the target crate.
-fn add_upstream_native_libraries(args: &mut Vec<~str> , sess: Session) {
-    let cstore = sess.cstore;
-    cstore.iter_crate_data(|cnum, _| {
-        let libs = csearch::get_native_libraries(cstore, cnum);
+fn add_upstream_native_libraries(args: &mut Vec<~str>, sess: &Session) {
+    // Be sure to use a topological sorting of crates becuase there may be
+    // interdependencies between native libraries. When passing -nodefaultlibs,
+    // for example, almost all native libraries depend on libc, so we have to
+    // make sure that's all the way at the right (liblibc is near the base of
+    // the dependency chain).
+    //
+    // This passes RequireStatic, but the actual requirement doesn't matter,
+    // we're just getting an ordering of crate numbers, we're not worried about
+    // the paths.
+    let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
+    for (cnum, _) in crates.move_iter() {
+        let libs = csearch::get_native_libraries(&sess.cstore, cnum);
         for &(kind, ref lib) in libs.iter() {
             match kind {
                 cstore::NativeUnknown => args.push("-l" + *lib),
                 cstore::NativeFramework => {
-                    args.push(~"-framework");
+                    args.push("-framework".to_owned());
                     args.push(lib.to_owned());
                 }
                 cstore::NativeStatic => {
@@ -1474,5 +1517,5 @@ fn add_upstream_native_libraries(args: &mut Vec<~str> , sess: Session) {
                 }
             }
         }
-    });
+    }
 }