diff --git a/src/libcore/rt.rs b/src/libcore/rt.rs
index 60e6118057d..c3e4f925c40 100644
--- a/src/libcore/rt.rs
+++ b/src/libcore/rt.rs
@@ -11,7 +11,7 @@
 //! Runtime calls emitted by the compiler.
 
 use cast::transmute;
-use libc::{c_char, c_uchar, c_void, size_t, uintptr_t};
+use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int};
 use managed::raw::BoxRepr;
 use str;
 use sys;
@@ -121,6 +121,21 @@ pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str {
     str::raw::from_buf_len(ptr, len)
 }
 
+#[lang="start"]
+pub fn start(main: *u8, argc: int, argv: *c_char,
+             crate_map: *u8) -> int {
+
+    extern {
+        fn rust_start(main: *c_void, argc: c_int, argv: *c_char,
+                      crate_map: *c_void) -> c_int;
+    }
+
+    unsafe {
+        return rust_start(main as *c_void, argc as c_int, argv,
+                          crate_map as *c_void) as int;
+    }
+}
+
 // Local Variables:
 // mode: rust;
 // fill-column: 78;
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index b30f9fcb9dd..8db27bd675d 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -838,9 +838,6 @@ pub fn link_binary(sess: Session,
         }
     }
 
-    // Always want the runtime linked in
-    cc_args.push(~"-lrustrt");
-
     // On linux librt and libdl are an indirect dependencies via rustrt,
     // and binutils 2.22+ won't add them automatically
     if sess.targ_cfg.os == session::os_linux {
@@ -880,6 +877,9 @@ pub fn link_binary(sess: Session,
     cc_args.push(~"-lmorestack");
     }
 
+    // Always want the runtime linked in
+    cc_args.push(~"-lrustrt");
+
     // FIXME (#2397): At some point we want to rpath our guesses as to where
     // extern libraries might live, based on the addl_lib_search_paths
     cc_args.push_all(rpath::get_rpath_flags(sess, &output));
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index b997c94a71b..84871f74964 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -75,16 +75,18 @@ pub enum LangItem {
     ReturnToMutFnLangItem,      // 31
     CheckNotBorrowedFnLangItem, // 32
     StrDupUniqFnLangItem,       // 33
+
+    StartFnLangItem,            // 34
 }
 
 pub struct LanguageItems {
-    items: [ Option<def_id> * 34 ]
+    items: [ Option<def_id> * 35 ]
 }
 
 pub impl LanguageItems {
     static pub fn new(&self) -> LanguageItems {
         LanguageItems {
-            items: [ None, ..34 ]
+            items: [ None, ..35 ]
         }
     }
 
@@ -136,6 +138,8 @@ pub impl LanguageItems {
             32 => "check_not_borrowed",
             33 => "strdup_uniq",
 
+            34 => "start",
+
             _ => "???"
         }
     }
@@ -248,6 +252,9 @@ pub impl LanguageItems {
     pub fn strdup_uniq_fn(&const self) -> def_id {
         self.items[StrDupUniqFnLangItem as uint].get()
     }
+    pub fn start_fn(&const self) -> def_id {
+        self.items[StartFnLangItem as uint].get()
+    }
 }
 
 fn LanguageItemCollector(crate: @crate,
@@ -296,6 +303,7 @@ fn LanguageItemCollector(crate: @crate,
     item_refs.insert(@~"check_not_borrowed",
                      CheckNotBorrowedFnLangItem as uint);
     item_refs.insert(@~"strdup_uniq", StrDupUniqFnLangItem as uint);
+    item_refs.insert(@~"start", StartFnLangItem as uint);
 
     LanguageItemCollector {
         crate: crate,
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 9844aa53f46..53555dc9ff8 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2267,7 +2267,7 @@ pub fn create_main_wrapper(ccx: @CrateContext,
         fn main_name() -> ~str { return ~"WinMain@16"; }
         #[cfg(unix)]
         fn main_name() -> ~str { return ~"main"; }
-        let llfty = T_fn(~[ccx.int_type, ccx.int_type], ccx.int_type);
+        let llfty = T_fn(~[ccx.int_type, T_ptr(T_i8())], ccx.int_type);
 
         // FIXME #4404 android JNI hacks
         let llfn = if *ccx.sess.building_library {
@@ -2285,33 +2285,50 @@ pub fn create_main_wrapper(ccx: @CrateContext,
             llvm::LLVMPositionBuilderAtEnd(bld, llbb);
         }
         let crate_map = ccx.crate_map;
-        let start_ty = T_fn(~[val_ty(rust_main), ccx.int_type, ccx.int_type,
-                             val_ty(crate_map)], ccx.int_type);
-        let start = decl_cdecl_fn(ccx.llmod, ~"rust_start", start_ty);
+        let start_def_id = ccx.tcx.lang_items.start_fn();
+        let start_fn = if start_def_id.crate == ast::local_crate {
+            ccx.sess.bug(~"start lang item is never in the local crate")
+        } else {
+            let start_fn_type = csearch::get_type(ccx.tcx,
+                                                  start_def_id).ty;
+            trans_external_path(ccx, start_def_id, start_fn_type)
+        };
+
+        let retptr = unsafe {
+            llvm::LLVMBuildAlloca(bld, ccx.int_type, noname())
+        };
 
         let args = unsafe {
+            let opaque_rust_main = llvm::LLVMBuildPointerCast(
+                bld, rust_main, T_ptr(T_i8()), noname());
+            let opaque_crate_map = llvm::LLVMBuildPointerCast(
+                bld, crate_map, T_ptr(T_i8()), noname());
+
             if *ccx.sess.building_library {
                 ~[
-                    rust_main,
+                    retptr,
+                    C_null(T_opaque_box_ptr(ccx)),
+                    opaque_rust_main,
                     llvm::LLVMConstInt(T_i32(), 0u as c_ulonglong, False),
                     llvm::LLVMConstInt(T_i32(), 0u as c_ulonglong, False),
-                    crate_map
+                    opaque_crate_map
                 ]
             } else {
                 ~[
-                    rust_main,
+                    retptr,
+                    C_null(T_opaque_box_ptr(ccx)),
+                    opaque_rust_main,
                     llvm::LLVMGetParam(llfn, 0 as c_uint),
                     llvm::LLVMGetParam(llfn, 1 as c_uint),
-                    crate_map
+                    opaque_crate_map
                 ]
             }
         };
 
-        let result = unsafe {
-            llvm::LLVMBuildCall(bld, start, vec::raw::to_ptr(args),
-                                args.len() as c_uint, noname())
-        };
         unsafe {
+            llvm::LLVMBuildCall(bld, start_fn, vec::raw::to_ptr(args),
+                                args.len() as c_uint, noname());
+            let result = llvm::LLVMBuildLoad(bld, retptr, noname());
             llvm::LLVMBuildRet(bld, result);
         }
     }