diff --git a/.gitignore b/.gitignore
index acd47803969e0..5e8c40d03fbef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,6 @@
 *.elc
 *.epub
 *.exe
-*.pdb
 *.fn
 *.html
 *.kdev4
@@ -29,6 +28,7 @@
 *.orig
 *.out
 *.patch
+*.pdb
 *.pdf
 *.pg
 *.pot
@@ -50,6 +50,10 @@
 .cproject
 .hg/
 .hgignore
+.idea
+__pycache__/
+*.py[cod]
+*$py.class
 .project
 .settings/
 .valgrindrc
@@ -65,6 +69,7 @@
 /llvm/
 /mingw-build/
 /nd/
+/obj/
 /rt/
 /rustllvm/
 /src/libunicode/DerivedCoreProperties.txt
@@ -73,13 +78,10 @@
 /src/libunicode/PropList.txt
 /src/libunicode/Scripts.txt
 /src/libunicode/UnicodeData.txt
-/stage0/
-/stage1/
-/stage2/
-/stage3/
+/stage[0-9]+/
+/target
 /test/
 /tmp/
-/obj/
 TAGS
 TAGS.emacs
 TAGS.vi
@@ -89,11 +91,9 @@ config.mk
 config.stamp
 keywords.md
 lexer.ml
-src/.DS_Store
 src/etc/dl
 src/librustc_llvm/llvmdeps.rs
 tmp.*.rs
 version.md
 version.ml
 version.texi
-/target
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index c0af457ed236c..17b5778994789 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -33,9 +33,8 @@ use mir::mir_map::MirMap;
 use session::Session;
 use session::config::PanicStrategy;
 use session::search_paths::PathKind;
-use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
+use util::nodemap::{FnvHashMap, NodeSet, DefIdMap};
 use std::any::Any;
-use std::cell::RefCell;
 use std::rc::Rc;
 use std::path::PathBuf;
 use syntax::ast;
@@ -174,7 +173,6 @@ pub trait CrateStore<'tcx> : Any {
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx>;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
-    fn item_symbol(&self, def: DefId) -> String;
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>;
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>;
     fn method_arg_names(&self, did: DefId) -> Vec<String>;
@@ -210,6 +208,7 @@ pub trait CrateStore<'tcx> : Any {
     fn is_impl(&self, did: DefId) -> bool;
     fn is_default_impl(&self, impl_did: DefId) -> bool;
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool;
+    fn is_foreign_item(&self, did: DefId) -> bool;
     fn is_static_method(&self, did: DefId) -> bool;
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool;
     fn is_typedef(&self, did: DefId) -> bool;
@@ -275,7 +274,6 @@ pub trait CrateStore<'tcx> : Any {
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>;
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
-                           item_symbols: &RefCell<NodeMap<String>>,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
                            mir_map: &MirMap<'tcx>,
@@ -353,7 +351,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
-    fn item_symbol(&self, def: DefId) -> String { bug!("item_symbol") }
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>
         { bug!("trait_def") }
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>
@@ -394,6 +391,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool
         { bug!("is_extern_item") }
+    fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
     fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") }
     fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false }
     fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") }
@@ -476,7 +474,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum> { None }
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
-                           item_symbols: &RefCell<NodeMap<String>>,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
                            mir_map: &MirMap<'tcx>,
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index fe22cfdb43f73..0b398fd0d47c5 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -115,9 +115,10 @@ fn calculate_type(sess: &session::Session,
         // got long ago), so don't bother with anything.
         config::CrateTypeRlib => return Vec::new(),
 
-        // Staticlibs must have all static dependencies. If any fail to be
-        // found, we generate some nice pretty errors.
-        config::CrateTypeStaticlib => {
+        // Staticlibs and cdylibs must have all static dependencies. If any fail
+        // to be found, we generate some nice pretty errors.
+        config::CrateTypeStaticlib |
+        config::CrateTypeCdylib => {
             match attempt_static(sess) {
                 Some(v) => return v,
                 None => {}
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index bca5af69edfd0..55d75ace08151 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -145,7 +145,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // Creates a new reachability computation context.
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
         let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
-            *ty != config::CrateTypeExecutable
+            *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib
         });
         ReachableContext {
             tcx: tcx,
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index b7dfc86720458..325887684914b 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
     let needs_check = sess.crate_types.borrow().iter().any(|kind| {
         match *kind {
             config::CrateTypeDylib |
+            config::CrateTypeCdylib |
             config::CrateTypeExecutable |
             config::CrateTypeStaticlib => true,
             config::CrateTypeRlib => false,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 7d1d5dba39839..0984c5e820984 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -300,6 +300,7 @@ pub enum CrateType {
     CrateTypeDylib,
     CrateTypeRlib,
     CrateTypeStaticlib,
+    CrateTypeCdylib,
 }
 
 #[derive(Clone)]
@@ -1103,7 +1104,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let no_analysis = debugging_opts.no_analysis;
 
     let mut output_types = HashMap::new();
-    if !debugging_opts.parse_only && !no_trans {
+    if !debugging_opts.parse_only {
         for list in matches.opt_strs("emit") {
             for output_type in list.split(',') {
                 let mut parts = output_type.splitn(2, '=');
@@ -1326,6 +1327,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
                 "rlib"      => CrateTypeRlib,
                 "staticlib" => CrateTypeStaticlib,
                 "dylib"     => CrateTypeDylib,
+                "cdylib"    => CrateTypeCdylib,
                 "bin"       => CrateTypeExecutable,
                 _ => {
                     return Err(format!("unknown crate type: `{}`",
@@ -1413,7 +1415,8 @@ impl fmt::Display for CrateType {
             CrateTypeExecutable => "bin".fmt(f),
             CrateTypeDylib => "dylib".fmt(f),
             CrateTypeRlib => "rlib".fmt(f),
-            CrateTypeStaticlib => "staticlib".fmt(f)
+            CrateTypeStaticlib => "staticlib".fmt(f),
+            CrateTypeCdylib => "cdylib".fmt(f),
         }
     }
 }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 1bea01c4849e7..2e4cbfd86279b 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::DefIndex;
+use hir::svh::Svh;
 use lint;
 use middle::cstore::CrateStore;
 use middle::dependency_format;
@@ -310,6 +312,14 @@ impl Session {
     pub fn nonzeroing_move_hints(&self) -> bool {
         self.opts.debugging_opts.enable_nonzeroing_move_hints
     }
+
+    /// Returns the symbol name for the registrar function,
+    /// given the crate Svh and the function DefIndex.
+    pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex)
+                                            -> String {
+        format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize())
+    }
+
     pub fn sysroot<'a>(&'a self) -> &'a Path {
         match self.opts.maybe_sysroot {
             Some (ref sysroot) => sysroot,
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 5246c6739d960..ee9983038b162 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -14,12 +14,38 @@ use hir::def_id::{DefId, CRATE_DEF_INDEX};
 use ty::{self, Ty, TyCtxt};
 use syntax::ast;
 
+use std::cell::Cell;
+
+thread_local! {
+    static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false)
+}
+
+/// Enforces that item_path_str always returns an absolute path.
+/// This is useful when building symbols that contain types,
+/// where we want the crate name to be part of the symbol.
+pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
+    FORCE_ABSOLUTE.with(|force| {
+        let old = force.get();
+        force.set(true);
+        let result = f();
+        force.set(old);
+        result
+    })
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns a string identifying this def-id. This string is
     /// suitable for user output. It is relative to the current crate
-    /// root.
+    /// root, unless with_forced_absolute_paths was used.
     pub fn item_path_str(self, def_id: DefId) -> String {
-        let mut buffer = LocalPathBuffer::new(RootMode::Local);
+        let mode = FORCE_ABSOLUTE.with(|force| {
+            if force.get() {
+                RootMode::Absolute
+            } else {
+                RootMode::Local
+            }
+        });
+        let mut buffer = LocalPathBuffer::new(mode);
         self.push_item_path(&mut buffer, def_id);
         buffer.into_string()
     }
@@ -75,7 +101,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             RootMode::Absolute => {
                 // In absolute mode, just write the crate name
                 // unconditionally.
-                buffer.push(&self.crate_name(cnum));
+                if cnum == LOCAL_CRATE {
+                    buffer.push(&self.crate_name(cnum));
+                } else {
+                    buffer.push(&self.sess.cstore.original_crate_name(cnum));
+                }
             }
         }
     }
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index cdbad685008f2..7073b9bf050a6 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -391,6 +391,7 @@ fn you_know_nothing(jon_snow: &mut i32) {
                        //        but it is already borrowed
     };
 }
+```
 
 In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it
 cannot be borrowed by the `starks` closure at the same time. To fix this issue,
@@ -501,6 +502,33 @@ fn foo(a: &mut i32) {
 ```
 "##,
 
+E0502: r##"
+This error indicates that you are trying to borrow a variable as mutable when it
+has already been borrowed as immutable.
+
+Example of erroneous code:
+
+```compile_fail
+fn bar(x: &mut i32) {}
+fn foo(a: &mut i32) {
+    let ref y = a; // a is borrowed as immutable.
+    bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
+            //        as immutable
+}
+```
+To fix this error, ensure that you don't have any other references to the
+variable before trying to access it mutably:
+```
+fn bar(x: &mut i32) {}
+fn foo(a: &mut i32) {
+    bar(a);
+    let ref y = a; // ok!
+}
+```
+For more information on the rust ownership system, take a look at
+https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
+"##,
+
 E0504: r##"
 This error occurs when an attempt is made to move a borrowed variable into a
 closure.
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 46356add8c682..05d84d9fd7846 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1175,6 +1175,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          Some(ref n) if *n == "dylib" => {
                              Some(config::CrateTypeDylib)
                          }
+                         Some(ref n) if *n == "cdylib" => {
+                             Some(config::CrateTypeCdylib)
+                         }
                          Some(ref n) if *n == "lib" => {
                              Some(config::default_lib_output())
                          }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 2a4b30e016f28..45a665c99b8cd 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -504,10 +504,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
             control.after_write_deps.stop = Compilation::Stop;
         }
 
-        if sess.opts.no_trans {
-            control.after_analysis.stop = Compilation::Stop;
-        }
-
         if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
             control.after_llvm.stop = Compilation::Stop;
         }
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index 4bf428ef46d9b..0da3f092d1e52 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -33,7 +33,7 @@ pub const tag_items_data_item_family: usize = 0x24;
 
 pub const tag_items_data_item_type: usize = 0x25;
 
-pub const tag_items_data_item_symbol: usize = 0x26;
+// GAP 0x26
 
 pub const tag_items_data_item_variant: usize = 0x27;
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 63c6af704bbfe..7e1bd50a795c1 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -17,6 +17,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob};
 use decoder;
 use loader::{self, CratePaths};
 
+use rustc::hir::def_id::DefIndex;
 use rustc::hir::svh::Svh;
 use rustc::dep_graph::{DepGraph, DepNode};
 use rustc::session::{config, Session};
@@ -578,9 +579,10 @@ impl<'a> CrateReader<'a> {
         macros
     }
 
-    /// Look for a plugin registrar. Returns library path and symbol name.
+    /// Look for a plugin registrar. Returns library path, crate
+    /// SVH and DefIndex of the registrar function.
     pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
-                                 -> Option<(PathBuf, String)> {
+                                 -> Option<(PathBuf, Svh, DefIndex)> {
         let ekrate = self.read_extension_crate(span, &CrateInfo {
              name: name.to_string(),
              ident: name.to_string(),
@@ -598,12 +600,14 @@ impl<'a> CrateReader<'a> {
             span_fatal!(self.sess, span, E0456, "{}", &message[..]);
         }
 
+        let svh = decoder::get_crate_hash(ekrate.metadata.as_slice());
         let registrar =
-            decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
-            .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id));
+            decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice());
 
         match (ekrate.dylib.as_ref(), registrar) {
-            (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)),
+            (Some(dylib), Some(reg)) => {
+                Some((dylib.to_path_buf(), svh, reg))
+            }
             (None, Some(_)) => {
                 span_err!(self.sess, span, E0457,
                           "plugin `{}` only found in rlib format, but must be available \
@@ -743,6 +747,7 @@ impl<'a> CrateReader<'a> {
             match *ct {
                 config::CrateTypeExecutable => need_exe_alloc = true,
                 config::CrateTypeDylib |
+                config::CrateTypeCdylib |
                 config::CrateTypeStaticlib => need_lib_alloc = true,
                 config::CrateTypeRlib => {}
             }
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 8d464099783a6..6461869344d65 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -23,7 +23,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::map as hir_map;
 use rustc::mir::repr::Mir;
 use rustc::mir::mir_map::MirMap;
-use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
+use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap};
 use rustc::session::config::PanicStrategy;
 
 use std::cell::RefCell;
@@ -105,12 +105,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_item_attrs(&cdata, def_id.index)
     }
 
-    fn item_symbol(&self, def: DefId) -> String
-    {
-        let cdata = self.get_crate_data(def.krate);
-        decoder::get_symbol(&cdata, def.index)
-    }
-
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx>
     {
         let cdata = self.get_crate_data(def.krate);
@@ -252,6 +246,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::is_extern_item(&cdata, did.index, tcx)
     }
 
+    fn is_foreign_item(&self, did: DefId) -> bool {
+        let cdata = self.get_crate_data(did.krate);
+        decoder::is_foreign_item(&cdata, did.index)
+    }
+
     fn is_static_method(&self, def: DefId) -> bool
     {
         let cdata = self.get_crate_data(def.krate);
@@ -512,7 +511,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            reexports: &def::ExportMap,
-                           item_symbols: &RefCell<NodeMap<String>>,
                            link_meta: &LinkMeta,
                            reachable: &NodeSet,
                            mir_map: &MirMap<'tcx>,
@@ -522,7 +520,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
             diag: tcx.sess.diagnostic(),
             tcx: tcx,
             reexports: reexports,
-            item_symbols: item_symbols,
             link_meta: link_meta,
             cstore: self,
             reachable: reachable,
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index e233dda7e91ee..2c1114e3ee713 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -186,10 +186,6 @@ fn item_sort(item: rbml::Doc) -> Option<char> {
     })
 }
 
-fn item_symbol(item: rbml::Doc) -> String {
-    reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string()
-}
-
 fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
     let id = reader::doc_as_u64(d);
     let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
@@ -609,18 +605,6 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd,
     }
 }
 
-pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String {
-    return item_symbol(cdata.lookup_item(id));
-}
-
-/// If you have a crate_metadata, call get_symbol instead
-pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String {
-    let index = load_index(data);
-    let pos = index.lookup_item(data, id).unwrap();
-    let doc = reader::doc_at(data, pos as usize).unwrap().doc;
-    item_symbol(doc)
-}
-
 /// Iterates over the language items in the given crate.
 pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
     F: FnMut(DefIndex, usize) -> bool,
@@ -1611,6 +1595,16 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd,
     }
 }
 
+pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool {
+    let item_doc = cdata.lookup_item(id);
+    let parent_item_id = match item_parent_item(cdata, item_doc) {
+        None => return false,
+        Some(item_id) => item_id,
+    };
+    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
+    item_family(parent_item_doc) == ForeignMod
+}
+
 pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
     let item_doc = cdata.lookup_item(id);
     match item_family(item_doc) {
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 020f12d753e63..80c139b1be124 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -33,7 +33,7 @@ use rustc::ty::util::IntTypeExt;
 use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
 use rustc::session::config::{self, PanicStrategy};
-use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
+use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
 use rustc_serialize::Encodable;
 use std::cell::RefCell;
@@ -58,7 +58,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     pub diag: &'a Handler,
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub reexports: &'a def::ExportMap,
-    pub item_symbols: &'a RefCell<NodeMap<String>>,
     pub link_meta: &'a LinkMeta,
     pub cstore: &'a cstore::CStore,
     pub type_abbrevs: tyencode::abbrev_map<'tcx>,
@@ -204,20 +203,6 @@ fn encode_region(ecx: &EncodeContext,
     rbml_w.end_tag();
 }
 
-fn encode_symbol(ecx: &EncodeContext,
-                 rbml_w: &mut Encoder,
-                 id: NodeId) {
-    match ecx.item_symbols.borrow().get(&id) {
-        Some(x) => {
-            debug!("encode_symbol(id={}, str={})", id, *x);
-            rbml_w.wr_tagged_str(tag_items_data_item_symbol, x);
-        }
-        None => {
-            bug!("encode_symbol: id not found {}", id);
-        }
-    }
-}
-
 fn encode_disr_val(_: &EncodeContext,
                    rbml_w: &mut Encoder,
                    disr_val: ty::Disr) {
@@ -512,10 +497,6 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     encode_name(rbml_w, name);
     encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
 
-    if ecx.item_symbols.borrow().contains_key(&ctor_id) {
-        encode_symbol(ecx, rbml_w, ctor_id);
-    }
-
     let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id));
     let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id));
     encode_stability(rbml_w, stab);
@@ -704,10 +685,6 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             }
             encode_constness(rbml_w, sig.constness);
             encode_defaultness(rbml_w, impl_item.defaultness);
-            if !any_types {
-                let m_id = ecx.local_id(m.def_id);
-                encode_symbol(ecx, rbml_w, m_id);
-            }
             encode_method_argument_names(rbml_w, &sig.decl);
         }
     }
@@ -885,7 +862,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             encode_family(rbml_w, 'c');
         }
         encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_symbol(ecx, rbml_w, item.id);
         encode_name(rbml_w, item.name);
         encode_visibility(rbml_w, vis);
         encode_stability(rbml_w, stab);
@@ -922,9 +898,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
             encode_mir(ecx, rbml_w, item.id);
         }
-        if tps_len == 0 {
-            encode_symbol(ecx, rbml_w, item.id);
-        }
         encode_constness(rbml_w, constness);
         encode_visibility(rbml_w, vis);
         encode_stability(rbml_w, stab);
@@ -1344,6 +1317,8 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     index.record(def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
     encode_def_id_and_key(ecx, rbml_w, def_id);
+    let parent_id = ecx.tcx.map.get_parent(nitem.id);
+    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
     encode_visibility(rbml_w, &nitem.vis);
     match nitem.node {
       hir::ForeignItemFn(ref fndecl, _) => {
@@ -1353,8 +1328,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
             encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem));
             encode_mir(ecx, rbml_w, nitem.id);
-        } else {
-            encode_symbol(ecx, rbml_w, nitem.id);
         }
         encode_attributes(rbml_w, &nitem.attrs);
         let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
@@ -1375,7 +1348,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
         encode_stability(rbml_w, stab);
         encode_deprecation(rbml_w, depr);
-        encode_symbol(ecx, rbml_w, nitem.id);
         encode_name(rbml_w, nitem.name);
       }
     }
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
index 036e46c380398..11e1841f7493e 100644
--- a/src/librustc_plugin/load.rs
+++ b/src/librustc_plugin/load.rs
@@ -101,7 +101,8 @@ impl<'a> PluginLoader<'a> {
     fn load_plugin(&mut self, span: Span, name: &str, args: Vec<P<ast::MetaItem>>) {
         let registrar = self.reader.find_plugin_registrar(span, name);
 
-        if let Some((lib, symbol)) = registrar {
+        if let Some((lib, svh, index)) = registrar {
+            let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index);
             let fun = self.dylink_registrar(span, lib, symbol);
             self.plugins.push(PluginRegistrar {
                 fun: fun,
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 00d9658cb5943..4101874c6fd50 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use super::archive::{ArchiveBuilder, ArchiveConfig};
-use super::linker::{Linker, GnuLinker, MsvcLinker};
+use super::linker::Linker;
 use super::rpath::RPathConfig;
 use super::rpath;
 use super::msvc;
@@ -228,6 +228,7 @@ pub fn invalid_output_for_target(sess: &Session,
                                  crate_type: config::CrateType) -> bool {
     match (sess.target.target.options.dynamic_linking,
            sess.target.target.options.executables, crate_type) {
+        (false, _, config::CrateTypeCdylib) |
         (false, _, config::CrateTypeDylib) => true,
         (_, false, config::CrateTypeExecutable) => true,
         _ => false
@@ -250,6 +251,7 @@ pub fn filename_for_input(sess: &Session,
         config::CrateTypeRlib => {
             outputs.out_directory.join(&format!("lib{}.rlib", libname))
         }
+        config::CrateTypeCdylib |
         config::CrateTypeDylib => {
             let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
                                     &sess.target.target.options.dll_suffix);
@@ -278,9 +280,10 @@ pub fn each_linked_rlib(sess: &Session,
                         f: &mut FnMut(ast::CrateNum, &Path)) {
     let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter();
     let fmts = sess.dependency_formats.borrow();
-    let fmts = fmts.get(&config::CrateTypeExecutable).or_else(|| {
-        fmts.get(&config::CrateTypeStaticlib)
-    }).unwrap_or_else(|| {
+    let fmts = fmts.get(&config::CrateTypeExecutable)
+                   .or_else(|| fmts.get(&config::CrateTypeStaticlib))
+                   .or_else(|| fmts.get(&config::CrateTypeCdylib));
+    let fmts = fmts.unwrap_or_else(|| {
         bug!("could not find formats for rlibs")
     });
     for (cnum, path) in crates {
@@ -335,13 +338,9 @@ fn link_binary_output(sess: &Session,
         config::CrateTypeStaticlib => {
             link_staticlib(sess, &objects, &out_filename, tmpdir.path());
         }
-        config::CrateTypeExecutable => {
-            link_natively(sess, false, &objects, &out_filename, trans, outputs,
-                          tmpdir.path());
-        }
-        config::CrateTypeDylib => {
-            link_natively(sess, true, &objects, &out_filename, trans, outputs,
-                          tmpdir.path());
+        _ => {
+            link_natively(sess, crate_type, &objects, &out_filename, trans,
+                          outputs, tmpdir.path());
         }
     }
 
@@ -609,13 +608,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], 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,
-                 objects: &[PathBuf], out_filename: &Path,
+fn link_natively(sess: &Session,
+                 crate_type: config::CrateType,
+                 objects: &[PathBuf],
+                 out_filename: &Path,
                  trans: &CrateTranslation,
                  outputs: &OutputFilenames,
                  tmpdir: &Path) {
-    info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects,
-          out_filename);
+    info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
 
     // The invocations of cc share some flags across platforms
     let (pname, mut cmd) = get_linker(sess);
@@ -624,23 +624,19 @@ fn link_natively(sess: &Session, dylib: bool,
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     cmd.args(&sess.target.target.options.pre_link_args);
 
-    let pre_link_objects = if dylib {
-        &sess.target.target.options.pre_link_objects_dll
-    } else {
+    let pre_link_objects = if crate_type == config::CrateTypeExecutable {
         &sess.target.target.options.pre_link_objects_exe
+    } else {
+        &sess.target.target.options.pre_link_objects_dll
     };
     for obj in pre_link_objects {
         cmd.arg(root.join(obj));
     }
 
     {
-        let mut linker = if sess.target.target.options.is_like_msvc {
-            Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
-        } else {
-            Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
-        };
-        link_args(&mut *linker, sess, dylib, tmpdir,
-                  objects, out_filename, trans, outputs);
+        let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
+        link_args(&mut *linker, sess, crate_type, tmpdir,
+                  objects, out_filename, outputs);
         if !sess.target.target.options.no_compiler_rt {
             linker.link_staticlib("compiler-rt");
         }
@@ -705,11 +701,10 @@ fn link_natively(sess: &Session, dylib: bool,
 
 fn link_args(cmd: &mut Linker,
              sess: &Session,
-             dylib: bool,
+             crate_type: config::CrateType,
              tmpdir: &Path,
              objects: &[PathBuf],
              out_filename: &Path,
-             trans: &CrateTranslation,
              outputs: &OutputFilenames) {
 
     // The default library location, we need this to find the runtime.
@@ -727,26 +722,28 @@ fn link_args(cmd: &mut Linker,
 
     // If we're building a dynamic library then some platforms need to make sure
     // that all symbols are exported correctly from the dynamic library.
-    if dylib {
-        cmd.export_symbols(sess, trans, tmpdir);
+    if crate_type != config::CrateTypeExecutable {
+        cmd.export_symbols(tmpdir, crate_type);
     }
 
     // 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.
-    if dylib {
+    if crate_type == config::CrateTypeDylib {
         cmd.add_object(&outputs.with_extension("metadata.o"));
     }
 
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
     if !sess.opts.cg.link_dead_code {
-        cmd.gc_sections(dylib);
+        let keep_metadata = crate_type == config::CrateTypeDylib;
+        cmd.gc_sections(keep_metadata);
     }
 
     let used_link_args = sess.cstore.used_link_args();
 
-    if !dylib && t.options.position_independent_executables {
+    if crate_type == config::CrateTypeExecutable &&
+       t.options.position_independent_executables {
         let empty_vec = Vec::new();
         let empty_str = String::new();
         let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
@@ -801,12 +798,12 @@ fn link_args(cmd: &mut Linker,
     // in this DAG so far because they're only dylibs and dylibs can only depend
     // on other dylibs (e.g. other native deps).
     add_local_native_libraries(cmd, sess);
-    add_upstream_rust_crates(cmd, sess, dylib, tmpdir);
+    add_upstream_rust_crates(cmd, sess, crate_type, tmpdir);
     add_upstream_native_libraries(cmd, sess);
 
     // # Telling the linker what we're doing
 
-    if dylib {
+    if crate_type != config::CrateTypeExecutable {
         cmd.build_dylib(out_filename);
     }
 
@@ -904,8 +901,10 @@ fn add_local_native_libraries(cmd: &mut Linker, 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(cmd: &mut Linker, sess: &Session,
-                            dylib: bool, tmpdir: &Path) {
+fn add_upstream_rust_crates(cmd: &mut Linker,
+                            sess: &Session,
+                            crate_type: config::CrateType,
+                            tmpdir: &Path) {
     // All of the heavy lifting has previously been accomplished by the
     // dependency_format module of the compiler. This is just crawling the
     // output of that module, adding crates as necessary.
@@ -915,11 +914,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
     // involves just passing the right -l flag.
 
     let formats = sess.dependency_formats.borrow();
-    let data = if dylib {
-        formats.get(&config::CrateTypeDylib).unwrap()
-    } else {
-        formats.get(&config::CrateTypeExecutable).unwrap()
-    };
+    let data = formats.get(&crate_type).unwrap();
 
     // Invoke get_used_crates to ensure that we get a topological sorting of
     // crates.
@@ -934,7 +929,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
             Linkage::NotLinked |
             Linkage::IncludedFromDylib => {}
             Linkage::Static => {
-                add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0)
+                add_static_crate(cmd, sess, tmpdir, crate_type,
+                                 &src.rlib.unwrap().0)
             }
             Linkage::Dynamic => {
                 add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
@@ -979,9 +975,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
     // (aka we're making an executable), we can just pass the rlib blindly to
     // the linker (fast) because it's fine if it's not actually included as
     // we're at the end of the dependency chain.
-    fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path,
-                        dylib: bool, cratepath: &Path) {
-        if !sess.lto() && !dylib {
+    fn add_static_crate(cmd: &mut Linker,
+                        sess: &Session,
+                        tmpdir: &Path,
+                        crate_type: config::CrateType,
+                        cratepath: &Path) {
+        if !sess.lto() && crate_type != config::CrateTypeDylib {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
             return
         }
@@ -1017,7 +1016,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
 
             if any_objects {
                 archive.build();
-                if dylib {
+                if crate_type == config::CrateTypeDylib {
                     cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
                 } else {
                     cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 8055e97034e3f..62435572278a1 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -15,13 +15,85 @@ use std::io::prelude::*;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use context::SharedCrateContext;
+use monomorphize::Instance;
+
 use back::archive;
 use middle::dependency_format::Linkage;
 use session::Session;
-use session::config::CrateTypeDylib;
+use session::config::{CrateType, CrateTypeCdylib, CrateTypeDylib};
 use session::config;
 use syntax::ast;
-use CrateTranslation;
+
+/// For all the linkers we support, and information they might
+/// need out of the shared crate context before we get rid of it.
+pub struct LinkerInfo {
+    dylib_exports: Vec<String>,
+    cdylib_exports: Vec<String>
+}
+
+fn exported_symbols<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+                              reachable: &[String],
+                              crate_type: CrateType)
+                              -> Vec<String> {
+    if !scx.sess().crate_types.borrow().contains(&crate_type) {
+        return vec![];
+    }
+
+    let mut symbols = reachable.to_vec();
+
+    // Make sure to keep the metadata in dylibs (cdylibs don't have it).
+    if crate_type == CrateTypeDylib {
+        symbols.push(scx.metadata_symbol_name());
+    }
+
+    // Take a look at how all upstream crates are linked into this
+    // dynamic library. For all statically linked libraries we take all
+    // their reachable symbols and emit them as well.
+    let cstore = &scx.sess().cstore;
+    let formats = scx.sess().dependency_formats.borrow();
+    let deps = formats[&crate_type].iter();
+    symbols.extend(deps.enumerate().filter_map(|(i, f)| {
+        if *f == Linkage::Static {
+            Some((i + 1) as ast::CrateNum)
+        } else {
+            None
+        }
+    }).flat_map(|cnum| {
+        cstore.reachable_ids(cnum)
+    }).map(|did| -> String {
+        Instance::mono(scx, did).symbol_name(scx)
+    }));
+    symbols
+}
+
+impl<'a, 'tcx> LinkerInfo {
+    pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
+               reachable: &[String]) -> LinkerInfo {
+        LinkerInfo {
+            dylib_exports: exported_symbols(scx, reachable, CrateTypeDylib),
+            cdylib_exports: exported_symbols(scx, reachable, CrateTypeCdylib)
+        }
+    }
+
+    pub fn to_linker(&'a self,
+                     cmd: &'a mut Command,
+                     sess: &'a Session) -> Box<Linker+'a> {
+        if sess.target.target.options.is_like_msvc {
+            Box::new(MsvcLinker {
+                cmd: cmd,
+                sess: sess,
+                info: self
+            }) as Box<Linker>
+        } else {
+            Box::new(GnuLinker {
+                cmd: cmd,
+                sess: sess,
+                info: self
+            }) as Box<Linker>
+        }
+    }
+}
 
 /// Linker abstraction used by back::link to build up the command to invoke a
 /// linker.
@@ -42,7 +114,7 @@ pub trait Linker {
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
-    fn gc_sections(&mut self, is_dylib: bool);
+    fn gc_sections(&mut self, keep_metadata: bool);
     fn position_independent_executable(&mut self);
     fn optimize(&mut self);
     fn debuginfo(&mut self);
@@ -53,13 +125,13 @@ pub trait Linker {
     fn hint_dynamic(&mut self);
     fn whole_archives(&mut self);
     fn no_whole_archives(&mut self);
-    fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
-                      tmpdir: &Path);
+    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
 }
 
 pub struct GnuLinker<'a> {
-    pub cmd: &'a mut Command,
-    pub sess: &'a Session,
+    cmd: &'a mut Command,
+    sess: &'a Session,
+    info: &'a LinkerInfo
 }
 
 impl<'a> GnuLinker<'a> {
@@ -113,7 +185,7 @@ impl<'a> Linker for GnuLinker<'a> {
         }
     }
 
-    fn gc_sections(&mut self, is_dylib: bool) {
+    fn gc_sections(&mut self, keep_metadata: bool) {
         // The dead_strip option to the linker specifies that functions and data
         // unreachable by the entry point will be removed. This is quite useful
         // with Rust's compilation model of compiling libraries at a time into
@@ -139,7 +211,7 @@ impl<'a> Linker for GnuLinker<'a> {
         // eliminate the metadata. If we're building an executable, however,
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
-        } else if !is_dylib {
+        } else if !keep_metadata {
             self.cmd.arg("-Wl,--gc-sections");
         }
     }
@@ -198,14 +270,43 @@ impl<'a> Linker for GnuLinker<'a> {
         self.cmd.arg("-Wl,-Bdynamic");
     }
 
-    fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) {
-        // noop, visibility in object files takes care of this
+    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
+        let path = tmpdir.join("list");
+        let prefix = if self.sess.target.target.options.is_like_osx {
+            "_"
+        } else {
+            ""
+        };
+        let res = (|| -> io::Result<()> {
+            let mut f = BufWriter::new(File::create(&path)?);
+            let symbols = if crate_type == CrateType::CrateTypeCdylib {
+                &self.info.cdylib_exports
+            } else {
+                &self.info.dylib_exports
+            };
+            for sym in symbols {
+                writeln!(f, "{}{}", prefix, sym)?;
+            }
+            Ok(())
+        })();
+        if let Err(e) = res {
+            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+        }
+        let mut arg = OsString::new();
+        if self.sess.target.target.options.is_like_osx {
+            arg.push("-Wl,-exported_symbols_list,");
+        } else {
+            arg.push("-Wl,--retain-symbols-file=");
+        }
+        arg.push(&path);
+        self.cmd.arg(arg);
     }
 }
 
 pub struct MsvcLinker<'a> {
-    pub cmd: &'a mut Command,
-    pub sess: &'a Session,
+    cmd: &'a mut Command,
+    sess: &'a Session,
+    info: &'a LinkerInfo
 }
 
 impl<'a> Linker for MsvcLinker<'a> {
@@ -220,7 +321,9 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(arg);
     }
 
-    fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
+    fn gc_sections(&mut self, _keep_metadata: bool) {
+        self.cmd.arg("/OPT:REF,ICF");
+    }
 
     fn link_dylib(&mut self, lib: &str) {
         self.cmd.arg(&format!("{}.lib", lib));
@@ -322,8 +425,9 @@ impl<'a> Linker for MsvcLinker<'a> {
     // crates. Upstream rlibs may be linked statically to this dynamic library,
     // in which case they may continue to transitively be used and hence need
     // their symbols exported.
-    fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
-                      tmpdir: &Path) {
+    fn export_symbols(&mut self,
+                      tmpdir: &Path,
+                      crate_type: CrateType) {
         let path = tmpdir.join("lib.def");
         let res = (|| -> io::Result<()> {
             let mut f = BufWriter::new(File::create(&path)?);
@@ -332,37 +436,18 @@ impl<'a> Linker for MsvcLinker<'a> {
             // straight to exports.
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
-
-            // Write out all our local symbols
-            for sym in trans.reachable.iter() {
-                writeln!(f, "  {}", sym)?;
-            }
-
-            // Take a look at how all upstream crates are linked into this
-            // dynamic library. For all statically linked libraries we take all
-            // their reachable symbols and emit them as well.
-            let cstore = &sess.cstore;
-            let formats = sess.dependency_formats.borrow();
-            let symbols = formats[&CrateTypeDylib].iter();
-            let symbols = symbols.enumerate().filter_map(|(i, f)| {
-                if *f == Linkage::Static {
-                    Some((i + 1) as ast::CrateNum)
-                } else {
-                    None
-                }
-            }).flat_map(|cnum| {
-                cstore.reachable_ids(cnum)
-            }).map(|did| {
-                cstore.item_symbol(did)
-            });
+            let symbols = if crate_type == CrateType::CrateTypeCdylib {
+                &self.info.cdylib_exports
+            } else {
+                &self.info.dylib_exports
+            };
             for symbol in symbols {
                 writeln!(f, "  {}", symbol)?;
             }
-
             Ok(())
         })();
         if let Err(e) = res {
-            sess.fatal(&format!("failed to write lib.def file: {}", e));
+            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 649d37e802d14..31bc11fb215b0 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -30,7 +30,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
            output_names: &config::OutputFilenames) {
     if sess.opts.cg.prefer_dynamic {
         sess.struct_err("cannot prefer dynamic linking when performing LTO")
-            .note("only 'staticlib' and 'bin' outputs are supported with LTO")
+            .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
+                   supported with LTO")
             .emit();
         sess.abort_if_errors();
     }
@@ -38,7 +39,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
     // Make sure we actually can run LTO
     for crate_type in sess.crate_types.borrow().iter() {
         match *crate_type {
-            config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
+            config::CrateTypeExecutable |
+            config::CrateTypeCdylib |
+            config::CrateTypeStaticlib => {}
             _ => {
                 sess.fatal("lto can only be run for executables and \
                             static library outputs");
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 0cf82d66b2b68..170c8f75b5056 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -97,17 +97,19 @@
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use common::{CrateContext, gensym_name};
+use common::{CrateContext, SharedCrateContext, gensym_name};
 use monomorphize::Instance;
 use util::sha2::{Digest, Sha256};
 
-use rustc::middle::cstore;
+use rustc::middle::{cstore, weak_lang_items};
 use rustc::hir::def_id::DefId;
+use rustc::hir::map as hir_map;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc::ty::item_path::{ItemPathBuffer, RootMode};
+use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::hir::map::definitions::{DefPath, DefPathData};
 
 use std::fmt::Write;
+use syntax::attr;
 use syntax::parse::token::{self, InternedString};
 use serialize::hex::ToHex;
 
@@ -116,10 +118,14 @@ pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) ->
     def_path_to_string(tcx, &def_path)
 }
 
-pub fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String {
+fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String {
     let mut s = String::with_capacity(def_path.data.len() * 16);
 
-    s.push_str(&tcx.crate_name(def_path.krate));
+    if def_path.krate == cstore::LOCAL_CRATE {
+        s.push_str(&tcx.crate_name(def_path.krate));
+    } else {
+        s.push_str(&tcx.sess.cstore.original_crate_name(def_path.krate));
+    }
     s.push_str("/");
     s.push_str(&tcx.crate_disambiguator(def_path.krate));
 
@@ -134,7 +140,7 @@ pub fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefP
     s
 }
 
-fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
                              // path to the item this name is for
                              def_path: &DefPath,
@@ -152,9 +158,9 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
            def_path, parameters);
 
-    let tcx = ccx.tcx();
+    let tcx = scx.tcx();
 
-    let mut hash_state = ccx.symbol_hasher().borrow_mut();
+    let mut hash_state = scx.symbol_hasher().borrow_mut();
 
     hash_state.reset();
 
@@ -187,66 +193,100 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                           instance: &Instance<'tcx>,
-                                           suffix: Option<&str>)
-                                           -> String {
-    let &Instance { def: mut def_id, ref substs } = instance;
+impl<'a, 'tcx> Instance<'tcx> {
+    pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
+        let Instance { def: def_id, ref substs } = self;
+
+        debug!("symbol_name(def_id={:?}, substs={:?})",
+               def_id, substs);
 
-    debug!("exported_name_with_opt_suffix(def_id={:?}, substs={:?}, suffix={:?})",
-           def_id, substs, suffix);
+        let node_id = scx.tcx().map.as_local_node_id(def_id);
 
-    if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
-        if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) {
-            def_id = src_def_id;
+        if let Some(id) = node_id {
+            if scx.sess().plugin_registrar_fn.get() == Some(id) {
+                let svh = &scx.link_meta().crate_hash;
+                let idx = def_id.index;
+                return scx.sess().generate_plugin_registrar_symbol(svh, idx);
+            }
         }
-    }
 
-    let def_path = ccx.tcx().def_path(def_id);
-    assert_eq!(def_path.krate, def_id.krate);
-
-    // We want to compute the "type" of this item. Unfortunately, some
-    // kinds of items (e.g., closures) don't have an entry in the
-    // item-type array. So walk back up the find the closest parent
-    // that DOES have an entry.
-    let mut ty_def_id = def_id;
-    let instance_ty;
-    loop {
-        let key = ccx.tcx().def_key(ty_def_id);
-        match key.disambiguated_data.data {
-            DefPathData::TypeNs(_) |
-            DefPathData::ValueNs(_) => {
-                instance_ty = ccx.tcx().lookup_item_type(ty_def_id);
-                break;
+        // FIXME(eddyb) Precompute a custom symbol name based on attributes.
+        let attrs = scx.tcx().get_attrs(def_id);
+        let is_foreign = if let Some(id) = node_id {
+            match scx.tcx().map.get(id) {
+                hir_map::NodeForeignItem(_) => true,
+                _ => false
             }
-            _ => {
-                // if we're making a symbol for something, there ought
-                // to be a value or type-def or something in there
-                // *somewhere*
-                ty_def_id.index = key.parent.unwrap_or_else(|| {
-                    bug!("finding type for {:?}, encountered def-id {:?} with no \
-                         parent", def_id, ty_def_id);
-                });
+        } else {
+            scx.sess().cstore.is_foreign_item(def_id)
+        };
+
+        if let Some(name) = weak_lang_items::link_name(&attrs) {
+            return name.to_string();
+        }
+
+        if is_foreign {
+            if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
+                return name.to_string();
             }
+            // Don't mangle foreign items.
+            return scx.tcx().item_name(def_id).as_str().to_string();
         }
-    }
 
-    // Erase regions because they may not be deterministic when hashed
-    // and should not matter anyhow.
-    let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty);
+        if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) {
+            // Use provided name
+            return name.to_string();
+        }
 
-    let hash = get_symbol_hash(ccx, &def_path, instance_ty, substs.types.as_slice());
+        if attr::contains_name(&attrs, "no_mangle") {
+            // Don't mangle
+            return scx.tcx().item_name(def_id).as_str().to_string();
+        }
 
-    let mut buffer = SymbolPathBuffer {
-        names: Vec::with_capacity(def_path.data.len())
-    };
-    ccx.tcx().push_item_path(&mut buffer, def_id);
+        let def_path = scx.tcx().def_path(def_id);
+
+        // We want to compute the "type" of this item. Unfortunately, some
+        // kinds of items (e.g., closures) don't have an entry in the
+        // item-type array. So walk back up the find the closest parent
+        // that DOES have an entry.
+        let mut ty_def_id = def_id;
+        let instance_ty;
+        loop {
+            let key = scx.tcx().def_key(ty_def_id);
+            match key.disambiguated_data.data {
+                DefPathData::TypeNs(_) |
+                DefPathData::ValueNs(_) => {
+                    instance_ty = scx.tcx().lookup_item_type(ty_def_id);
+                    break;
+                }
+                _ => {
+                    // if we're making a symbol for something, there ought
+                    // to be a value or type-def or something in there
+                    // *somewhere*
+                    ty_def_id.index = key.parent.unwrap_or_else(|| {
+                        bug!("finding type for {:?}, encountered def-id {:?} with no \
+                             parent", def_id, ty_def_id);
+                    });
+                }
+            }
+        }
 
-    if let Some(suffix) = suffix {
-        buffer.push(suffix);
-    }
+        // Erase regions because they may not be deterministic when hashed
+        // and should not matter anyhow.
+        let instance_ty = scx.tcx().erase_regions(&instance_ty.ty);
+
+        let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice());
+
+        let mut buffer = SymbolPathBuffer {
+            names: Vec::with_capacity(def_path.data.len())
+        };
 
-    mangle(buffer.names.into_iter(), Some(&hash[..]))
+        item_path::with_forced_absolute_paths(|| {
+            scx.tcx().push_item_path(&mut buffer, def_id);
+        });
+
+        mangle(buffer.names.into_iter(), Some(&hash[..]))
+    }
 }
 
 struct SymbolPathBuffer {
@@ -264,19 +304,6 @@ impl ItemPathBuffer for SymbolPathBuffer {
     }
 }
 
-pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               instance: &Instance<'tcx>)
-                               -> String {
-    exported_name_with_opt_suffix(ccx, instance, None)
-}
-
-pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                           instance: &Instance<'tcx>,
-                                           suffix: &str)
-                                           -> String {
-   exported_name_with_opt_suffix(ccx, instance, Some(suffix))
-}
-
 /// Only symbols that are invisible outside their compilation unit should use a
 /// name generated by this function.
 pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -289,7 +316,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>
         data: vec![],
         krate: cstore::LOCAL_CRATE,
     };
-    let hash = get_symbol_hash(ccx, &def_path, t, &[]);
+    let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]);
     mangle(path.iter().cloned(), Some(&hash[..]))
 }
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 65c3aa12ba6c8..361eb701b63fa 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -30,14 +30,14 @@ pub use self::ValueOrigin::*;
 use super::CrateTranslation;
 use super::ModuleTranslation;
 
-use back::{link, symbol_names};
+use back::link;
+use back::linker::LinkerInfo;
 use lint;
 use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
 use llvm;
 use rustc::cfg;
 use rustc::hir::def_id::DefId;
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
-use middle::weak_lang_items;
 use rustc::hir::pat_util::simple_name;
 use rustc::ty::subst::{self, Substs};
 use rustc::traits;
@@ -2337,15 +2337,6 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
             set_global_section(ccx, g, item);
             update_linkage(ccx, g, Some(item.id), OriginalTranslation);
         }
-        hir::ItemForeignMod(ref m) => {
-            if m.abi == Abi::RustIntrinsic || m.abi == Abi::PlatformIntrinsic {
-                return;
-            }
-            for fi in &m.items {
-                let lname = imported_name(fi.name, &fi.attrs).to_string();
-                ccx.item_symbols().borrow_mut().insert(fi.id, lname);
-            }
-        }
         _ => {}
     }
 }
@@ -2430,60 +2421,12 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
     }
 }
 
-pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               instance: Instance<'tcx>,
-                               attrs: &[ast::Attribute])
-                               -> String {
-    let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
-
-    match ccx.external_srcs().borrow().get(&id) {
-        Some(&did) => {
-            let sym = ccx.sess().cstore.item_symbol(did);
-            debug!("found item {} in other crate...", sym);
-            return sym;
-        }
-        None => {}
-    }
-
-    match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) {
-        // Use provided name
-        Some(name) => name.to_string(),
-        _ => {
-            if attr::contains_name(attrs, "no_mangle") {
-                // Don't mangle
-                ccx.tcx().map.name(id).as_str().to_string()
-            } else {
-                match weak_lang_items::link_name(attrs) {
-                    Some(name) => name.to_string(),
-                    None => {
-                        // Usual name mangling
-                        symbol_names::exported_name(ccx, &instance)
-                    }
-                }
-            }
-        }
-    }
-}
-
-pub fn imported_name(name: ast::Name, attrs: &[ast::Attribute]) -> InternedString {
-    match attr::first_attr_value_str_by_name(attrs, "link_name") {
-        Some(ln) => ln.clone(),
-        None => match weak_lang_items::link_name(attrs) {
-            Some(name) => name,
-            None => name.as_str(),
-        }
-    }
-}
-
 fn contains_null(s: &str) -> bool {
     s.bytes().any(|b| b == 0)
 }
 
-pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
-                                krate: &hir::Crate,
-                                reachable: &NodeSet,
-                                mir_map: &MirMap<'tcx>)
-                                -> Vec<u8> {
+fn write_metadata(cx: &SharedCrateContext,
+                  reachable_ids: &NodeSet) -> Vec<u8> {
     use flate;
 
     let any_library = cx.sess()
@@ -2498,19 +2441,16 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
     let cstore = &cx.tcx().sess.cstore;
     let metadata = cstore.encode_metadata(cx.tcx(),
                                           cx.export_map(),
-                                          cx.item_symbols(),
                                           cx.link_meta(),
-                                          reachable,
-                                          mir_map,
-                                          krate);
+                                          reachable_ids,
+                                          cx.mir_map(),
+                                          cx.tcx().map.krate());
     let mut compressed = cstore.metadata_encoding_version().to_vec();
     compressed.extend_from_slice(&flate::deflate_bytes(&metadata));
 
     let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]);
     let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false);
-    let name = format!("rust_metadata_{}_{}",
-                       cx.link_meta().crate_name,
-                       cx.link_meta().crate_hash);
+    let name = cx.metadata_symbol_name();
     let buf = CString::new(name).unwrap();
     let llglobal = unsafe {
         llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr())
@@ -2665,10 +2605,7 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter {
 /// This list is later used by linkers to determine the set of symbols needed to
 /// be exposed from a dynamic library and it's also encoded into the metadata.
 pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet {
-    scx.reachable().iter().map(|x| *x).filter(|id| {
-        // First, only worry about nodes which have a symbol name
-        scx.item_symbols().borrow().contains_key(id)
-    }).filter(|&id| {
+    scx.reachable().iter().map(|x| *x).filter(|&id| {
         // Next, we want to ignore some FFI functions that are not exposed from
         // this crate. Reachable FFI functions can be lumped into two
         // categories:
@@ -2686,7 +2623,20 @@ pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet {
             hir_map::NodeForeignItem(..) => {
                 scx.sess().cstore.is_statically_included_foreign_item(id)
             }
-            _ => true,
+
+            // Only consider nodes that actually have exported symbols.
+            hir_map::NodeItem(&hir::Item {
+                node: hir::ItemStatic(..), .. }) |
+            hir_map::NodeItem(&hir::Item {
+                node: hir::ItemFn(..), .. }) |
+            hir_map::NodeImplItem(&hir::ImplItem {
+                node: hir::ImplItemKind::Method(..), .. }) => {
+                let def_id = scx.tcx().map.local_def_id(id);
+                let scheme = scx.tcx().lookup_item_type(def_id);
+                scheme.generics.types.is_empty()
+            }
+
+            _ => false
         }
     }).collect()
 }
@@ -2728,6 +2678,19 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              check_overflow,
                                              check_dropflag);
 
+    let reachable_symbol_ids = filter_reachable_ids(&shared_ccx);
+
+    // Translate the metadata.
+    let metadata = time(tcx.sess.time_passes(), "write metadata", || {
+        write_metadata(&shared_ccx, &reachable_symbol_ids)
+    });
+
+    let metadata_module = ModuleTranslation {
+        llcx: shared_ccx.metadata_llcx(),
+        llmod: shared_ccx.metadata_llmod(),
+    };
+    let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
+
     let codegen_units = collect_and_partition_translation_items(&shared_ccx);
     let codegen_unit_count = codegen_units.len();
     assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count ||
@@ -2735,6 +2698,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units);
 
+    let modules = crate_context_list.iter()
+        .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() })
+        .collect();
+
+    // Skip crate items and just output metadata in -Z no-trans mode.
+    if tcx.sess.opts.no_trans {
+        let linker_info = LinkerInfo::new(&shared_ccx, &[]);
+        return CrateTranslation {
+            modules: modules,
+            metadata_module: metadata_module,
+            link: link_meta,
+            metadata: metadata,
+            reachable: vec![],
+            no_builtins: no_builtins,
+            linker_info: linker_info
+        };
+    }
+
     {
         let ccx = crate_context_list.get_ccx(0);
 
@@ -2764,13 +2745,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let reachable_symbol_ids = filter_reachable_ids(&shared_ccx);
-
-    // Translate the metadata.
-    let metadata = time(tcx.sess.time_passes(), "write metadata", || {
-        write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map)
-    });
-
     if shared_ccx.sess().trans_stats() {
         let stats = shared_ccx.stats();
         println!("--- trans stats ---");
@@ -2800,13 +2774,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let modules = crate_context_list.iter()
-        .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() })
-        .collect();
-
     let sess = shared_ccx.sess();
-    let mut reachable_symbols = reachable_symbol_ids.iter().map(|id| {
-        shared_ccx.item_symbols().borrow()[id].to_string()
+    let mut reachable_symbols = reachable_symbol_ids.iter().map(|&id| {
+        let def_id = shared_ccx.tcx().map.local_def_id(id);
+        Instance::mono(&shared_ccx, def_id).symbol_name(&shared_ccx)
     }).collect::<Vec<_>>();
     if sess.entry_fn.borrow().is_some() {
         reachable_symbols.push("main".to_string());
@@ -2821,7 +2792,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             reachable_symbols.extend(syms.into_iter().filter(|did| {
                 sess.cstore.is_extern_item(shared_ccx.tcx(), *did)
             }).map(|did| {
-                sess.cstore.item_symbol(did)
+                Instance::mono(&shared_ccx, did).symbol_name(&shared_ccx)
             }));
         }
     }
@@ -2836,12 +2807,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         create_imps(&crate_context_list);
     }
 
-    let metadata_module = ModuleTranslation {
-        llcx: shared_ccx.metadata_llcx(),
-        llmod: shared_ccx.metadata_llmod(),
-    };
-    let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
-
+    let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols);
     CrateTranslation {
         modules: modules,
         metadata_module: metadata_module,
@@ -2849,6 +2815,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         metadata: metadata,
         reachable: reachable_symbols,
         no_builtins: no_builtins,
+        linker_info: linker_info
     }
 }
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index c0c5ea818b2d7..d7f565a9cd449 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -499,43 +499,20 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         return immediate_rvalue(llfn, fn_ptr_ty);
     }
 
-    let attrs;
     let local_id = ccx.tcx().map.as_local_node_id(def_id);
-    let maybe_node = local_id.and_then(|id| tcx.map.find(id));
-    let (sym, attrs, local_item) = match maybe_node {
+    let local_item = match local_id.and_then(|id| tcx.map.find(id)) {
         Some(hir_map::NodeItem(&hir::Item {
-            ref attrs, id, span, node: hir::ItemFn(..), ..
+            span, node: hir::ItemFn(..), ..
         })) |
         Some(hir_map::NodeTraitItem(&hir::TraitItem {
-            ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), ..
+            span, node: hir::MethodTraitItem(_, Some(_)), ..
         })) |
         Some(hir_map::NodeImplItem(&hir::ImplItem {
-            ref attrs, id, span, node: hir::ImplItemKind::Method(..), ..
+            span, node: hir::ImplItemKind::Method(..), ..
         })) => {
-            let sym = exported_name(ccx, instance, attrs);
-
-            if declare::get_defined_value(ccx, &sym).is_some() {
-                ccx.sess().span_fatal(span,
-                    &format!("symbol `{}` is already defined", sym));
-            }
-
-            (sym, &attrs[..], Some(id))
-        }
-
-        Some(hir_map::NodeForeignItem(&hir::ForeignItem {
-            ref attrs, name, node: hir::ForeignItemFn(..), ..
-        })) => {
-            (imported_name(name, attrs).to_string(), &attrs[..], None)
-        }
-
-        None => {
-            attrs = ccx.sess().cstore.item_attrs(def_id);
-            (ccx.sess().cstore.item_symbol(def_id), &attrs[..], None)
-        }
-
-        ref variant => {
-            bug!("get_fn: unexpected variant: {:?}", variant)
+            Some(span)
         }
+        _ => None
     };
 
     // This is subtle and surprising, but sometimes we have to bitcast
@@ -562,8 +539,16 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // reference. It also occurs when testing libcore and in some
     // other weird situations. Annoying.
 
+    let sym = instance.symbol_name(ccx.shared());
     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
+        if let Some(span) = local_item {
+            if declare::get_defined_value(ccx, &sym).is_some() {
+                ccx.sess().span_fatal(span,
+                    &format!("symbol `{}` is already defined", sym));
+            }
+        }
+
         if common::val_ty(llfn) != llptrty {
             if local_item.is_some() {
                 bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}",
@@ -580,7 +565,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         assert_eq!(common::val_ty(llfn), llptrty);
         debug!("get_fn: not casting pointer!");
 
-        attributes::from_fn_attrs(ccx, attrs, llfn);
+        let attrs = ccx.tcx().get_attrs(def_id);
+        attributes::from_fn_attrs(ccx, &attrs, llfn);
         if local_item.is_some() {
             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
             attributes::unwind(llfn, true);
@@ -589,11 +575,6 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         llfn
     };
 
-    // Always insert into item_symbols, in case this item is exported.
-    if let Some(id) = local_item {
-        ccx.item_symbols().borrow_mut().insert(id, sym);
-    }
-
     ccx.instances().borrow_mut().insert(instance, llfn);
 
     immediate_rvalue(llfn, fn_ptr_ty)
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 1c393f8091eee..5e0d34c2a674d 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -150,7 +150,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         return llfn;
     }
 
-    let symbol = symbol_names::exported_name(ccx, &instance);
+    let symbol = instance.symbol_name(ccx.shared());
 
     // Compute the rust-call form of the closure call method.
     let sig = &tcx.closure_type(closure_id, substs).sig;
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 3e876eb3d7de0..bd36c18a47ee2 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -19,7 +19,7 @@ use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use {abi, adt, closure, debuginfo, expr, machine};
-use base::{self, exported_name, imported_name, push_ctxt};
+use base::{self, push_ctxt};
 use callee::Callee;
 use collector;
 use trans_item::TransItem;
@@ -1017,34 +1017,31 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
         return Datum::new(g, ty, Lvalue::new("static"));
     }
 
+    let sym = instance.symbol_name(ccx.shared());
+
     let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) {
         let llty = type_of::type_of(ccx, ty);
         match ccx.tcx().map.get(id) {
             hir_map::NodeItem(&hir::Item {
-                ref attrs, span, node: hir::ItemStatic(..), ..
+                span, node: hir::ItemStatic(..), ..
             }) => {
                 // If this static came from an external crate, then
                 // we need to get the symbol from metadata instead of
                 // using the current crate's name/version
                 // information in the hash of the symbol
-                let sym = exported_name(ccx, instance, attrs);
                 debug!("making {}", sym);
 
                 // Create the global before evaluating the initializer;
                 // this is necessary to allow recursive statics.
-                let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| {
+                declare::define_global(ccx, &sym, llty).unwrap_or_else(|| {
                     ccx.sess().span_fatal(span,
                         &format!("symbol `{}` is already defined", sym))
-                });
-
-                ccx.item_symbols().borrow_mut().insert(id, sym);
-                g
+                })
             }
 
             hir_map::NodeForeignItem(&hir::ForeignItem {
-                ref attrs, name, span, node: hir::ForeignItemStatic(..), ..
+                ref attrs, span, node: hir::ForeignItemStatic(..), ..
             }) => {
-                let ident = imported_name(name, attrs);
                 let g = if let Some(name) =
                         attr::first_attr_value_str_by_name(&attrs, "linkage") {
                     // If this is a static with a linkage specified, then we need to handle
@@ -1066,7 +1063,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
                     };
                     unsafe {
                         // Declare a symbol `foo` with the desired linkage.
-                        let g1 = declare::declare_global(ccx, &ident, llty2);
+                        let g1 = declare::declare_global(ccx, &sym, llty2);
                         llvm::SetLinkage(g1, linkage);
 
                         // Declare an internal global `extern_with_linkage_foo` which
@@ -1076,10 +1073,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
                         // `extern_with_linkage_foo` will instead be initialized to
                         // zero.
                         let mut real_name = "_rust_extern_with_linkage_".to_string();
-                        real_name.push_str(&ident);
+                        real_name.push_str(&sym);
                         let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{
                             ccx.sess().span_fatal(span,
-                                &format!("symbol `{}` is already defined", ident))
+                                &format!("symbol `{}` is already defined", sym))
                         });
                         llvm::SetLinkage(g2, llvm::InternalLinkage);
                         llvm::LLVMSetInitializer(g2, g1);
@@ -1087,7 +1084,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
                     }
                 } else {
                     // Generate an external declaration.
-                    declare::declare_global(ccx, &ident, llty)
+                    declare::declare_global(ccx, &sym, llty)
                 };
 
                 for attr in attrs {
@@ -1104,8 +1101,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
     } else {
         // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
         // FIXME(nagisa): investigate whether it can be changed into define_global
-        let name = ccx.sess().cstore.item_symbol(def_id);
-        let g = declare::declare_global(ccx, &name, type_of::type_of(ccx, ty));
+        let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty));
         // Thread-local statics in some other crate need to *always* be linked
         // against in a thread-local fashion, so we need to be sure to apply the
         // thread-local attribute locally if it was present remotely. If we
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 60c6af84ebbb6..1ddcbc79aed5f 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -71,7 +71,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
 
     export_map: ExportMap,
     reachable: NodeSet,
-    item_symbols: RefCell<NodeMap<String>>,
     link_meta: LinkMeta,
     symbol_hasher: RefCell<Sha256>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -395,7 +394,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             metadata_llcx: metadata_llcx,
             export_map: export_map,
             reachable: reachable,
-            item_symbols: RefCell::new(NodeMap()),
             link_meta: link_meta,
             symbol_hasher: RefCell::new(symbol_hasher),
             tcx: tcx,
@@ -439,10 +437,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         &self.reachable
     }
 
-    pub fn item_symbols<'a>(&'a self) -> &'a RefCell<NodeMap<String>> {
-        &self.item_symbols
-    }
-
     pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
         &self.trait_cache
     }
@@ -503,6 +497,20 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             Substs::new(VecPerParamSpace::empty(),
                         scheme.generics.regions.map(|_| ty::ReStatic)))
     }
+
+    pub fn symbol_hasher(&self) -> &RefCell<Sha256> {
+        &self.symbol_hasher
+    }
+
+    pub fn mir_map(&self) -> &MirMap<'tcx> {
+        &self.mir_map
+    }
+
+    pub fn metadata_symbol_name(&self) -> String {
+        format!("rust_metadata_{}_{}",
+                self.link_meta().crate_name,
+                self.link_meta().crate_hash)
+    }
 }
 
 impl<'tcx> LocalCrateContext<'tcx> {
@@ -710,10 +718,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.shared.reachable
     }
 
-    pub fn item_symbols<'a>(&'a self) -> &'a RefCell<NodeMap<String>> {
-        &self.shared.item_symbols
-    }
-
     pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
         &self.shared.link_meta
     }
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index bccb5aa050b51..0188a6d54de2d 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -145,6 +145,7 @@ pub struct CrateTranslation {
     pub metadata: Vec<u8>,
     pub reachable: Vec<String>,
     pub no_builtins: bool,
+    pub linker_info: back::linker::LinkerInfo
 }
 
 __build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index dfaf84ecef023..b0f8edac0a623 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use back::symbol_names;
 use llvm::ValueRef;
 use llvm;
 use rustc::hir::def_id::DefId;
@@ -88,7 +87,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         monomorphizing.insert(fn_id, depth + 1);
     }
 
-    let symbol = symbol_names::exported_name(ccx, &instance);
+    let symbol = instance.symbol_name(ccx.shared());
 
     debug!("monomorphize_fn mangled to {}", symbol);
     assert!(declare::get_defined_value(ccx, &symbol).is_none());
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index 284a227276dd0..11e9e9f3204a2 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -14,7 +14,6 @@
 //! item-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
-use back::symbol_names;
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor};
 use syntax::ast;
@@ -53,7 +52,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
             if attr.check_name(SYMBOL_NAME) {
                 // for now, can only use on monomorphic names
                 let instance = Instance::mono(self.ccx.shared(), def_id);
-                let name = symbol_names::exported_name(self.ccx, &instance);
+                let name = instance.symbol_name(self.ccx.shared());
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
             } else if attr.check_name(ITEM_PATH) {
                 let path = tcx.item_path_str(def_id);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ce83c4a258ce9..3fbcdaf650eeb 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -795,7 +795,17 @@ impl Clean<Lifetime> for hir::Lifetime {
 
 impl Clean<Lifetime> for hir::LifetimeDef {
     fn clean(&self, _: &DocContext) -> Lifetime {
-        Lifetime(self.lifetime.name.to_string())
+        if self.bounds.len() > 0 {
+            let mut s = format!("{}: {}",
+                                self.lifetime.name.to_string(),
+                                self.bounds[0].name.to_string());
+            for bound in self.bounds.iter().skip(1) {
+                s.push_str(&format!(" + {}", bound.name.to_string()));
+            }
+            Lifetime(s)
+        } else {
+            Lifetime(self.lifetime.name.to_string())
+        }
     }
 }
 
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index d256e939afcfc..a52a914fea680 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -640,6 +640,10 @@ span.since {
     margin-right: 5px;
 }
 
+:target > code {
+   background: #FDFFD3;
+}
+
 /* Media Queries */
 
 @media (max-width: 700px) {
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 6c61d6b914c56..abfa65580646d 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -67,8 +67,7 @@ struct Context<'a, 'b:'a> {
 
     name_positions: HashMap<String, usize>,
 
-    /// Updated as arguments are consumed or methods are entered
-    nest_level: usize,
+    /// Updated as arguments are consumed
     next_arg: usize,
 }
 
@@ -164,9 +163,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 let pos = match arg.position {
                     parse::ArgumentNext => {
                         let i = self.next_arg;
-                        if self.check_positional_ok() {
-                            self.next_arg += 1;
-                        }
+                        self.next_arg += 1;
                         Exact(i)
                     }
                     parse::ArgumentIs(i) => Exact(i),
@@ -189,25 +186,13 @@ impl<'a, 'b> Context<'a, 'b> {
                 self.verify_arg_type(Named(s.to_string()), Unsigned);
             }
             parse::CountIsNextParam => {
-                if self.check_positional_ok() {
-                    let next_arg = self.next_arg;
-                    self.verify_arg_type(Exact(next_arg), Unsigned);
-                    self.next_arg += 1;
-                }
+                let next_arg = self.next_arg;
+                self.verify_arg_type(Exact(next_arg), Unsigned);
+                self.next_arg += 1;
             }
         }
     }
 
-    fn check_positional_ok(&mut self) -> bool {
-        if self.nest_level != 0 {
-            self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
-                                           arguments nested inside methods");
-            false
-        } else {
-            true
-        }
-    }
-
     fn describe_num_args(&self) -> String {
         match self.args.len() {
             0 => "no arguments given".to_string(),
@@ -655,7 +640,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         name_positions: HashMap::new(),
         name_types: HashMap::new(),
         name_ordering: name_ordering,
-        nest_level: 0,
         next_arg: 0,
         literal: String::new(),
         pieces: Vec::new(),
diff --git a/src/test/compile-fail/auxiliary/cdylib-dep.rs b/src/test/compile-fail/auxiliary/cdylib-dep.rs
new file mode 100644
index 0000000000000..a3d0222a14c97
--- /dev/null
+++ b/src/test/compile-fail/auxiliary/cdylib-dep.rs
@@ -0,0 +1,11 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+#![crate_type = "dylib"]
diff --git a/src/test/compile-fail/cdylib-deps-must-be-static.rs b/src/test/compile-fail/cdylib-deps-must-be-static.rs
new file mode 100644
index 0000000000000..c0a2dcba5c0a3
--- /dev/null
+++ b/src/test/compile-fail/cdylib-deps-must-be-static.rs
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+// error-pattern: dependency `cdylib_dep` not found in rlib format
+// aux-build:cdylib-dep.rs
+
+#![crate_type = "cdylib"]
+
+extern crate cdylib_dep;
diff --git a/src/test/compile-fail/symbol-names/impl1.rs b/src/test/compile-fail/symbol-names/impl1.rs
index 39bee26da20b8..93fa48b880fdf 100644
--- a/src/test/compile-fail/symbol-names/impl1.rs
+++ b/src/test/compile-fail/symbol-names/impl1.rs
@@ -25,7 +25,7 @@ mod bar {
     use foo::Foo;
 
     impl Foo {
-        #[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz
+        #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
         #[rustc_item_path] //~ ERROR item-path(bar::<impl foo::Foo>::baz)
         fn baz() { }
     }
diff --git a/src/test/run-make/cdylib/Makefile b/src/test/run-make/cdylib/Makefile
new file mode 100644
index 0000000000000..8d53b5dc210d1
--- /dev/null
+++ b/src/test/run-make/cdylib/Makefile
@@ -0,0 +1,10 @@
+include ../tools.mk
+
+all:
+	$(RUSTC) bar.rs -O
+	$(RUSTC) foo.rs -O
+	$(CC) $(CFLAGS) foo.c -lfoo -o $(call RUN_BINFILE,foo) -L $(TMPDIR)
+	$(call RUN,foo)
+	rm $(call DYLIB,foo)
+	$(RUSTC) foo.rs -C lto
+	$(call RUN,foo)
diff --git a/src/test/run-make/cdylib/bar.rs b/src/test/run-make/cdylib/bar.rs
new file mode 100644
index 0000000000000..fcb1efe397d4a
--- /dev/null
+++ b/src/test/run-make/cdylib/bar.rs
@@ -0,0 +1,13 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+#![crate_type = "rlib"]
+
+pub fn bar() {}
diff --git a/src/test/run-make/cdylib/foo.c b/src/test/run-make/cdylib/foo.c
new file mode 100644
index 0000000000000..1c950427c658b
--- /dev/null
+++ b/src/test/run-make/cdylib/foo.c
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+#include <assert.h>
+
+extern void foo();
+extern unsigned bar(unsigned a, unsigned b);
+
+int main() {
+  foo();
+  assert(bar(1, 2) == 3);
+  return 0;
+}
diff --git a/src/test/run-make/cdylib/foo.rs b/src/test/run-make/cdylib/foo.rs
new file mode 100644
index 0000000000000..cdac6d1903525
--- /dev/null
+++ b/src/test/run-make/cdylib/foo.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+#![crate_type = "cdylib"]
+
+extern crate bar;
+
+#[no_mangle]
+pub extern fn foo() {
+    bar::bar();
+}
+
+#[no_mangle]
+pub extern fn bar(a: u32, b: u32) -> u32 {
+    a + b
+}