about summary refs log tree commit diff
path: root/src/librustc/back
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-11-06 19:44:58 -0800
committerBrian Anderson <banderson@mozilla.com>2012-11-07 13:53:39 -0800
commit69a8b4d8e20df44766fad153b6300b0a6e7e3d5e (patch)
tree5e4ea1b0d1bce8f3c4d96dba09ec50f1ba47de40 /src/librustc/back
parentf72ef31ede98d0605195b2a6baba38f71d0177a0 (diff)
downloadrust-69a8b4d8e20df44766fad153b6300b0a6e7e3d5e.tar.gz
rust-69a8b4d8e20df44766fad153b6300b0a6e7e3d5e.zip
Rename src/rustc to src/librustc. Use the driver crate
Diffstat (limited to 'src/librustc/back')
-rw-r--r--src/librustc/back/abi.rs78
-rw-r--r--src/librustc/back/link.rs798
-rw-r--r--src/librustc/back/rpath.rs333
-rw-r--r--src/librustc/back/target_strs.rs7
-rw-r--r--src/librustc/back/upcall.rs59
-rw-r--r--src/librustc/back/x86.rs51
-rw-r--r--src/librustc/back/x86_64.rs57
7 files changed, 1383 insertions, 0 deletions
diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs
new file mode 100644
index 00000000000..7c35e3d892d
--- /dev/null
+++ b/src/librustc/back/abi.rs
@@ -0,0 +1,78 @@
+
+
+
+const rc_base_field_refcnt: uint = 0u;
+
+const task_field_refcnt: uint = 0u;
+
+const task_field_stk: uint = 2u;
+
+const task_field_runtime_sp: uint = 3u;
+
+const task_field_rust_sp: uint = 4u;
+
+const task_field_gc_alloc_chain: uint = 5u;
+
+const task_field_dom: uint = 6u;
+
+const n_visible_task_fields: uint = 7u;
+
+const dom_field_interrupt_flag: uint = 1u;
+
+const frame_glue_fns_field_mark: uint = 0u;
+
+const frame_glue_fns_field_drop: uint = 1u;
+
+const frame_glue_fns_field_reloc: uint = 2u;
+
+const box_field_refcnt: uint = 0u;
+const box_field_tydesc: uint = 1u;
+const box_field_prev: uint = 2u;
+const box_field_next: uint = 3u;
+const box_field_body: uint = 4u;
+
+const general_code_alignment: uint = 16u;
+
+const tydesc_field_size: uint = 0u;
+const tydesc_field_align: uint = 1u;
+const tydesc_field_take_glue: uint = 2u;
+const tydesc_field_drop_glue: uint = 3u;
+const tydesc_field_free_glue: uint = 4u;
+const tydesc_field_visit_glue: uint = 5u;
+const tydesc_field_shape: uint = 6u;
+const tydesc_field_shape_tables: uint = 7u;
+const n_tydesc_fields: uint = 8u;
+
+// The two halves of a closure: code and environment.
+const fn_field_code: uint = 0u;
+const fn_field_box: uint = 1u;
+
+const vec_elt_fill: uint = 0u;
+
+const vec_elt_alloc: uint = 1u;
+
+const vec_elt_elems: uint = 2u;
+
+const slice_elt_base: uint = 0u;
+const slice_elt_len: uint = 1u;
+
+const worst_case_glue_call_args: uint = 7u;
+
+const abi_version: uint = 1u;
+
+fn memcpy_glue_name() -> ~str { return ~"rust_memcpy_glue"; }
+
+fn bzero_glue_name() -> ~str { return ~"rust_bzero_glue"; }
+
+fn yield_glue_name() -> ~str { return ~"rust_yield_glue"; }
+
+fn no_op_type_glue_name() -> ~str { return ~"rust_no_op_type_glue"; }
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
new file mode 100644
index 00000000000..61fd68c193a
--- /dev/null
+++ b/src/librustc/back/link.rs
@@ -0,0 +1,798 @@
+use libc::{c_int, c_uint, c_char};
+use driver::session;
+use session::Session;
+use lib::llvm::llvm;
+use syntax::attr;
+use middle::ty;
+use metadata::{encoder, cstore};
+use middle::trans::common::crate_ctxt;
+use metadata::common::link_meta;
+use std::map::HashMap;
+use std::sha1::sha1;
+use syntax::ast;
+use syntax::print::pprust;
+use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data, True, False,
+        PassManagerRef, FileType};
+use metadata::filesearch;
+use syntax::ast_map::{path, path_mod, path_name};
+use io::{Writer, WriterUtil};
+
+enum output_type {
+    output_type_none,
+    output_type_bitcode,
+    output_type_assembly,
+    output_type_llvm_assembly,
+    output_type_object,
+    output_type_exe,
+}
+
+impl output_type : cmp::Eq {
+    pure fn eq(other: &output_type) -> bool {
+        (self as uint) == ((*other) as uint)
+    }
+    pure fn ne(other: &output_type) -> bool { !self.eq(other) }
+}
+
+fn llvm_err(sess: Session, msg: ~str) -> ! unsafe {
+    let cstr = llvm::LLVMRustGetLastError();
+    if cstr == ptr::null() {
+        sess.fatal(msg);
+    } else { sess.fatal(msg + ~": " + str::raw::from_c_str(cstr)); }
+}
+
+fn WriteOutputFile(sess: Session,
+        PM: lib::llvm::PassManagerRef, M: ModuleRef,
+        Triple: *c_char,
+        // FIXME: When #2334 is fixed, change
+        // c_uint to FileType
+        Output: *c_char, FileType: c_uint,
+        OptLevel: c_int,
+        EnableSegmentedStacks: bool) {
+    let result = llvm::LLVMRustWriteOutputFile(
+            PM, M, Triple, Output, FileType, OptLevel, EnableSegmentedStacks);
+    if (!result) {
+        llvm_err(sess, ~"Could not write output");
+    }
+}
+
+mod jit {
+    #[legacy_exports];
+    #[nolink]
+    #[abi = "rust-intrinsic"]
+    extern mod rusti {
+        #[legacy_exports];
+        fn morestack_addr() -> *();
+    }
+
+    struct Closure {
+        code: *(),
+        env: *(),
+    }
+
+    fn exec(sess: Session,
+            pm: PassManagerRef,
+            m: ModuleRef,
+            opt: c_int,
+            stacks: bool) unsafe {
+        let manager = llvm::LLVMRustPrepareJIT(rusti::morestack_addr());
+
+        // We need to tell JIT where to resolve all linked
+        // symbols from. The equivalent of -lstd, -lcore, etc.
+        // By default the JIT will resolve symbols from the std and
+        // core linked into rustc. We don't want that,
+        // incase the user wants to use an older std library.
+
+        let cstore = sess.cstore;
+        for cstore::get_used_crate_files(cstore).each |cratepath| {
+            let path = cratepath.to_str();
+
+            debug!("linking: %s", path);
+
+            let _: () = str::as_c_str(
+                path,
+                |buf_t| {
+                    if !llvm::LLVMRustLoadCrate(manager, buf_t) {
+                        llvm_err(sess, ~"Could not link");
+                    }
+                    debug!("linked: %s", path);
+                });
+        }
+
+        // The execute function will return a void pointer
+        // to the _rust_main function. We can do closure
+        // magic here to turn it straight into a callable rust
+        // closure. It will also cleanup the memory manager
+        // for us.
+
+        let entry = llvm::LLVMRustExecuteJIT(manager,
+                                             pm, m, opt, stacks);
+
+        if ptr::is_null(entry) {
+            llvm_err(sess, ~"Could not JIT");
+        } else {
+            let closure = Closure {
+                code: entry,
+                env: ptr::null()
+            };
+            let func: fn(++argv: ~[~str]) = cast::transmute(move closure);
+
+            func(~[sess.opts.binary]);
+        }
+    }
+}
+
+mod write {
+    #[legacy_exports];
+    fn is_object_or_assembly_or_exe(ot: output_type) -> bool {
+        if ot == output_type_assembly || ot == output_type_object ||
+               ot == output_type_exe {
+            return true;
+        }
+        return false;
+    }
+
+    fn run_passes(sess: Session, llmod: ModuleRef, output: &Path) {
+        let opts = sess.opts;
+        if sess.time_llvm_passes() { llvm::LLVMRustEnableTimePasses(); }
+        let mut pm = mk_pass_manager();
+        let td = mk_target_data(
+            sess.targ_cfg.target_strs.data_layout);
+        llvm::LLVMAddTargetData(td.lltd, pm.llpm);
+        // FIXME (#2812): run the linter here also, once there are llvm-c
+        // bindings for it.
+
+        // Generate a pre-optimization intermediate file if -save-temps was
+        // specified.
+
+
+        if opts.save_temps {
+            match opts.output_type {
+              output_type_bitcode => {
+                if opts.optimize != session::No {
+                    let filename = output.with_filetype("no-opt.bc");
+                    str::as_c_str(filename.to_str(), |buf| {
+                        llvm::LLVMWriteBitcodeToFile(llmod, buf)
+                    });
+                }
+              }
+              _ => {
+                let filename = output.with_filetype("bc");
+                str::as_c_str(filename.to_str(), |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf)
+                });
+              }
+            }
+        }
+        if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
+        // FIXME (#2396): This is mostly a copy of the bits of opt's -O2 that
+        // are available in the C api.
+        // Also: We might want to add optimization levels like -O1, -O2,
+        // -Os, etc
+        // Also: Should we expose and use the pass lists used by the opt
+        // tool?
+
+        if opts.optimize != session::No {
+            let fpm = mk_pass_manager();
+            llvm::LLVMAddTargetData(td.lltd, fpm.llpm);
+
+            let FPMB = llvm::LLVMPassManagerBuilderCreate();
+            llvm::LLVMPassManagerBuilderSetOptLevel(FPMB, 2u as c_uint);
+            llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(FPMB,
+                                                                    fpm.llpm);
+            llvm::LLVMPassManagerBuilderDispose(FPMB);
+
+            llvm::LLVMRunPassManager(fpm.llpm, llmod);
+            let mut threshold = 225;
+            if opts.optimize == session::Aggressive { threshold = 275; }
+
+            let MPMB = llvm::LLVMPassManagerBuilderCreate();
+            llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
+                                                    opts.optimize as c_uint);
+            llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
+            llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB, False);
+            llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB, False);
+            llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
+                                                                   False);
+
+            if threshold != 0u {
+                llvm::LLVMPassManagerBuilderUseInlinerWithThreshold
+                    (MPMB, threshold as c_uint);
+            }
+            llvm::LLVMPassManagerBuilderPopulateModulePassManager(MPMB,
+                                                                  pm.llpm);
+
+            llvm::LLVMPassManagerBuilderDispose(MPMB);
+        }
+        if !sess.no_verify() { llvm::LLVMAddVerifierPass(pm.llpm); }
+        if is_object_or_assembly_or_exe(opts.output_type) || opts.jit {
+            let LLVMOptNone       = 0 as c_int; // -O0
+            let LLVMOptLess       = 1 as c_int; // -O1
+            let LLVMOptDefault    = 2 as c_int; // -O2, -Os
+            let LLVMOptAggressive = 3 as c_int; // -O3
+
+            let mut CodeGenOptLevel = match opts.optimize {
+              session::No => LLVMOptNone,
+              session::Less => LLVMOptLess,
+              session::Default => LLVMOptDefault,
+              session::Aggressive => LLVMOptAggressive
+            };
+
+            if opts.jit {
+                // If we are using JIT, go ahead and create and
+                // execute the engine now.
+                // JIT execution takes ownership of the module,
+                // so don't dispose and return.
+
+                jit::exec(sess, pm.llpm, llmod, CodeGenOptLevel, true);
+
+                if sess.time_llvm_passes() {
+                    llvm::LLVMRustPrintPassTimings();
+                }
+                return;
+            }
+
+            let mut FileType;
+            if opts.output_type == output_type_object ||
+                   opts.output_type == output_type_exe {
+               FileType = lib::llvm::ObjectFile;
+            } else { FileType = lib::llvm::AssemblyFile; }
+            // Write optimized bitcode if --save-temps was on.
+
+            if opts.save_temps {
+                // Always output the bitcode file with --save-temps
+
+                let filename = output.with_filetype("opt.bc");
+                llvm::LLVMRunPassManager(pm.llpm, llmod);
+                str::as_c_str(filename.to_str(), |buf| {
+                    llvm::LLVMWriteBitcodeToFile(llmod, buf)
+                });
+                pm = mk_pass_manager();
+                // Save the assembly file if -S is used
+
+                if opts.output_type == output_type_assembly {
+                    let _: () = str::as_c_str(
+                        sess.targ_cfg.target_strs.target_triple,
+                        |buf_t| {
+                            str::as_c_str(output.to_str(), |buf_o| {
+                                WriteOutputFile(
+                                    sess,
+                                    pm.llpm,
+                                    llmod,
+                                    buf_t,
+                                    buf_o,
+                                    lib::llvm::AssemblyFile as c_uint,
+                                    CodeGenOptLevel,
+                                    true)
+                            })
+                        });
+                }
+
+
+                // Save the object file for -c or --save-temps alone
+                // This .o is needed when an exe is built
+                if opts.output_type == output_type_object ||
+                       opts.output_type == output_type_exe {
+                    let _: () = str::as_c_str(
+                        sess.targ_cfg.target_strs.target_triple,
+                        |buf_t| {
+                            str::as_c_str(output.to_str(), |buf_o| {
+                                WriteOutputFile(
+                                    sess,
+                                    pm.llpm,
+                                    llmod,
+                                    buf_t,
+                                    buf_o,
+                                    lib::llvm::ObjectFile as c_uint,
+                                    CodeGenOptLevel,
+                                    true)
+                            })
+                        });
+                }
+            } else {
+                // If we aren't saving temps then just output the file
+                // type corresponding to the '-c' or '-S' flag used
+
+                let _: () = str::as_c_str(
+                    sess.targ_cfg.target_strs.target_triple,
+                    |buf_t| {
+                        str::as_c_str(output.to_str(), |buf_o| {
+                            WriteOutputFile(
+                                sess,
+                                pm.llpm,
+                                llmod,
+                                buf_t,
+                                buf_o,
+                                FileType as c_uint,
+                                CodeGenOptLevel,
+                                true)
+                        })
+                    });
+            }
+            // Clean up and return
+
+            llvm::LLVMDisposeModule(llmod);
+            if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
+            return;
+        }
+
+        if opts.output_type == output_type_llvm_assembly {
+            // Given options "-S --emit-llvm": output LLVM assembly
+            str::as_c_str(output.to_str(), |buf_o| {
+                llvm::LLVMRustAddPrintModulePass(pm.llpm, llmod, buf_o)});
+        } else {
+            // If only a bitcode file is asked for by using the '--emit-llvm'
+            // flag, then output it here
+            llvm::LLVMRunPassManager(pm.llpm, llmod);
+            str::as_c_str(output.to_str(),
+                        |buf| llvm::LLVMWriteBitcodeToFile(llmod, buf) );
+        }
+
+        llvm::LLVMDisposeModule(llmod);
+        if sess.time_llvm_passes() { llvm::LLVMRustPrintPassTimings(); }
+    }
+}
+
+
+/*
+ * Name mangling and its relationship to metadata. This is complex. Read
+ * carefully.
+ *
+ * The semantic model of Rust linkage is, broadly, that "there's no global
+ * namespace" between crates. Our aim is to preserve the illusion of this
+ * model despite the fact that it's not *quite* possible to implement on
+ * modern linkers. We initially didn't use system linkers at all, but have
+ * been convinced of their utility.
+ *
+ * There are a few issues to handle:
+ *
+ *  - Linkers operate on a flat namespace, so we have to flatten names.
+ *    We do this using the C++ namespace-mangling technique. Foo::bar
+ *    symbols and such.
+ *
+ *  - Symbols with the same name but different types need to get different
+ *    linkage-names. We do this by hashing a string-encoding of the type into
+ *    a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
+ *    we use SHA1) to "prevent collisions". This is not airtight but 16 hex
+ *    digits on uniform probability means you're going to need 2**32 same-name
+ *    symbols in the same process before you're even hitting birthday-paradox
+ *    collision probability.
+ *
+ *  - Symbols in different crates but with same names "within" the crate need
+ *    to get different linkage-names.
+ *
+ * So here is what we do:
+ *
+ *  - Separate the meta tags into two sets: exported and local. Only work with
+ *    the exported ones when considering linkage.
+ *
+ *  - Consider two exported tags as special (and mandatory): name and vers.
+ *    Every crate gets them; if it doesn't name them explicitly we infer them
+ *    as basename(crate) and "0.1", respectively. Call these CNAME, CVERS.
+ *
+ *  - Define CMETA as all the non-name, non-vers exported meta tags in the
+ *    crate (in sorted order).
+ *
+ *  - Define CMH as hash(CMETA + hashes of dependent crates).
+ *
+ *  - Compile our crate to lib CNAME-CMH-CVERS.so
+ *
+ *  - Define STH(sym) as hash(CNAME, CMH, type_str(sym))
+ *
+ *  - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
+ *    name, non-name metadata, and type sense, and versioned in the way
+ *    system linkers understand.
+ *
+ */
+
+fn build_link_meta(sess: Session, c: ast::crate, output: &Path,
+                   symbol_hasher: &hash::State) -> link_meta {
+
+    type provided_metas =
+        {name: Option<~str>,
+         vers: Option<~str>,
+         cmh_items: ~[@ast::meta_item]};
+
+    fn provided_link_metas(sess: Session, c: ast::crate) ->
+       provided_metas {
+        let mut name: Option<~str> = None;
+        let mut vers: Option<~str> = None;
+        let mut cmh_items: ~[@ast::meta_item] = ~[];
+        let linkage_metas = attr::find_linkage_metas(c.node.attrs);
+        attr::require_unique_names(sess.diagnostic(), linkage_metas);
+        for linkage_metas.each |meta| {
+            if attr::get_meta_item_name(*meta) == ~"name" {
+                match attr::get_meta_item_value_str(*meta) {
+                  Some(v) => { name = Some(v); }
+                  None => cmh_items.push(*meta)
+                }
+            } else if attr::get_meta_item_name(*meta) == ~"vers" {
+                match attr::get_meta_item_value_str(*meta) {
+                  Some(v) => { vers = Some(v); }
+                  None => cmh_items.push(*meta)
+                }
+            } else { cmh_items.push(*meta); }
+        }
+        return {name: name, vers: vers, cmh_items: cmh_items};
+    }
+
+    // This calculates CMH as defined above
+    fn crate_meta_extras_hash(symbol_hasher: &hash::State,
+                              _crate: ast::crate,
+                              metas: provided_metas,
+                              dep_hashes: ~[~str]) -> ~str {
+        fn len_and_str(s: ~str) -> ~str {
+            return fmt!("%u_%s", str::len(s), s);
+        }
+
+        fn len_and_str_lit(l: ast::lit) -> ~str {
+            return len_and_str(pprust::lit_to_str(@l));
+        }
+
+        let cmh_items = attr::sort_meta_items(metas.cmh_items);
+
+        symbol_hasher.reset();
+        for cmh_items.each |m| {
+            match m.node {
+              ast::meta_name_value(key, value) => {
+                symbol_hasher.write_str(len_and_str(key));
+                symbol_hasher.write_str(len_and_str_lit(value));
+              }
+              ast::meta_word(name) => {
+                symbol_hasher.write_str(len_and_str(name));
+              }
+              ast::meta_list(_, _) => {
+                // FIXME (#607): Implement this
+                fail ~"unimplemented meta_item variant";
+              }
+            }
+        }
+
+        for dep_hashes.each |dh| {
+            symbol_hasher.write_str(len_and_str(*dh));
+        }
+
+        return truncated_hash_result(symbol_hasher);
+    }
+
+    fn warn_missing(sess: Session, name: ~str, default: ~str) {
+        if !sess.building_library { return; }
+        sess.warn(fmt!("missing crate link meta `%s`, using `%s` as default",
+                       name, default));
+    }
+
+    fn crate_meta_name(sess: Session, _crate: ast::crate,
+                       output: &Path, metas: provided_metas) -> ~str {
+        return match metas.name {
+              Some(v) => v,
+              None => {
+                let name = match output.filestem() {
+                  None => sess.fatal(fmt!("output file name `%s` doesn't\
+                                           appear to have a stem",
+                                          output.to_str())),
+                  Some(s) => s
+                };
+                warn_missing(sess, ~"name", name);
+                name
+              }
+            };
+    }
+
+    fn crate_meta_vers(sess: Session, _crate: ast::crate,
+                       metas: provided_metas) -> ~str {
+        return match metas.vers {
+              Some(v) => v,
+              None => {
+                let vers = ~"0.0";
+                warn_missing(sess, ~"vers", vers);
+                vers
+              }
+            };
+    }
+
+    let provided_metas = provided_link_metas(sess, c);
+    let name = crate_meta_name(sess, c, output, provided_metas);
+    let vers = crate_meta_vers(sess, c, provided_metas);
+    let dep_hashes = cstore::get_dep_hashes(sess.cstore);
+    let extras_hash =
+        crate_meta_extras_hash(symbol_hasher, c, provided_metas, dep_hashes);
+
+    return {name: name, vers: vers, extras_hash: extras_hash};
+}
+
+fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str unsafe {
+    symbol_hasher.result_str()
+}
+
+
+// This calculates STH for a symbol, as defined above
+fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &hash::State, t: ty::t,
+               link_meta: link_meta) -> ~str {
+    // NB: do *not* use abbrevs here as we want the symbol names
+    // to be independent of one another in the crate.
+
+    symbol_hasher.reset();
+    symbol_hasher.write_str(link_meta.name);
+    symbol_hasher.write_str(~"-");
+    symbol_hasher.write_str(link_meta.extras_hash);
+    symbol_hasher.write_str(~"-");
+    symbol_hasher.write_str(encoder::encoded_ty(tcx, t));
+    let hash = truncated_hash_result(symbol_hasher);
+    // Prefix with _ so that it never blends into adjacent digits
+
+    return ~"_" + hash;
+}
+
+fn get_symbol_hash(ccx: @crate_ctxt, t: ty::t) -> ~str {
+    match ccx.type_hashcodes.find(t) {
+      Some(h) => return h,
+      None => {
+        let hash = symbol_hash(ccx.tcx, ccx.symbol_hasher, t, ccx.link_meta);
+        ccx.type_hashcodes.insert(t, hash);
+        return hash;
+      }
+    }
+}
+
+
+// Name sanitation. LLVM will happily accept identifiers with weird names, but
+// gas doesn't!
+fn sanitize(s: ~str) -> ~str {
+    let mut result = ~"";
+    for str::chars_each(s) |c| {
+        match c {
+          '@' => result += ~"_sbox_",
+          '~' => result += ~"_ubox_",
+          '*' => result += ~"_ptr_",
+          '&' => result += ~"_ref_",
+          ',' => result += ~"_",
+
+          '{' | '(' => result += ~"_of_",
+          'a' .. 'z'
+          | 'A' .. 'Z'
+          | '0' .. '9'
+          | '_' => str::push_char(&mut result, c),
+          _ => {
+            if c > 'z' && char::is_XID_continue(c) {
+                str::push_char(&mut result, c);
+            }
+          }
+        }
+    }
+
+    // Underscore-qualify anything that didn't start as an ident.
+    if result.len() > 0u &&
+        result[0] != '_' as u8 &&
+        ! char::is_XID_start(result[0] as char) {
+        return ~"_" + result;
+    }
+
+    return result;
+}
+
+fn mangle(sess: Session, ss: path) -> ~str {
+    // Follow C++ namespace-mangling style
+
+    let mut n = ~"_ZN"; // Begin name-sequence.
+
+    for ss.each |s| {
+        match *s { path_name(s) | path_mod(s) => {
+          let sani = sanitize(sess.str_of(s));
+          n += fmt!("%u%s", str::len(sani), sani);
+        } }
+    }
+    n += ~"E"; // End name-sequence.
+    n
+}
+
+fn exported_name(sess: Session, path: path, hash: ~str, vers: ~str) -> ~str {
+    return mangle(sess,
+                  vec::append_one(
+                      vec::append_one(path, path_name(sess.ident_of(hash))),
+                      path_name(sess.ident_of(vers))));
+}
+
+fn mangle_exported_name(ccx: @crate_ctxt, path: path, t: ty::t) -> ~str {
+    let hash = get_symbol_hash(ccx, t);
+    return exported_name(ccx.sess, path, hash, ccx.link_meta.vers);
+}
+
+fn mangle_internal_name_by_type_only(ccx: @crate_ctxt,
+                                     t: ty::t, name: ~str) ->
+   ~str {
+    let s = util::ppaux::ty_to_short_str(ccx.tcx, t);
+    let hash = get_symbol_hash(ccx, t);
+    return mangle(ccx.sess,
+                  ~[path_name(ccx.sess.ident_of(name)),
+                    path_name(ccx.sess.ident_of(s)),
+                    path_name(ccx.sess.ident_of(hash))]);
+}
+
+fn mangle_internal_name_by_path_and_seq(ccx: @crate_ctxt, path: path,
+                                        flav: ~str) -> ~str {
+    return mangle(ccx.sess,
+                  vec::append_one(path, path_name(ccx.names(flav))));
+}
+
+fn mangle_internal_name_by_path(ccx: @crate_ctxt, path: path) -> ~str {
+    return mangle(ccx.sess, path);
+}
+
+fn mangle_internal_name_by_seq(ccx: @crate_ctxt, flav: ~str) -> ~str {
+    return fmt!("%s_%u", flav, ccx.names(flav).repr);
+}
+
+// If the user wants an exe generated we need to invoke
+// cc to link the object file with some libs
+fn link_binary(sess: Session,
+               obj_filename: &Path,
+               out_filename: &Path,
+               lm: link_meta) {
+    // Converts a library file-stem into a cc -l argument
+    fn unlib(config: @session::config, stem: ~str) -> ~str {
+        if stem.starts_with("lib") &&
+            config.os != session::os_win32 {
+            stem.slice(3, stem.len())
+        } else {
+            stem
+        }
+    }
+
+    let output = if sess.building_library {
+        let long_libname =
+            os::dll_filename(fmt!("%s-%s-%s",
+                                  lm.name, lm.extras_hash, lm.vers));
+        debug!("link_meta.name:  %s", lm.name);
+        debug!("long_libname: %s", long_libname);
+        debug!("out_filename: %s", out_filename.to_str());
+        debug!("dirname(out_filename): %s", out_filename.dir_path().to_str());
+
+        out_filename.dir_path().push(long_libname)
+    } else {
+        *out_filename
+    };
+
+    log(debug, ~"output: " + output.to_str());
+
+    // The default library location, we need this to find the runtime.
+    // The location of crates will be determined as needed.
+    let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str();
+
+    // In the future, FreeBSD will use clang as default compiler.
+    // It would be flexible to use cc (system's default C compiler)
+    // instead of hard-coded gcc.
+    // For win32, there is no cc command,
+    // so we add a condition to make it use gcc.
+    let cc_prog: ~str =
+        if sess.targ_cfg.os == session::os_win32 { ~"gcc" } else { ~"cc" };
+    // The invocations of cc share some flags across platforms
+
+    let mut cc_args =
+        vec::append(~[stage], sess.targ_cfg.target_strs.cc_args);
+    cc_args.push(~"-o");
+    cc_args.push(output.to_str());
+    cc_args.push(obj_filename.to_str());
+
+    let mut lib_cmd;
+    let os = sess.targ_cfg.os;
+    if os == session::os_macos {
+        lib_cmd = ~"-dynamiclib";
+    } else {
+        lib_cmd = ~"-shared";
+    }
+
+    // # Crate linking
+
+    let cstore = sess.cstore;
+    for cstore::get_used_crate_files(cstore).each |cratepath| {
+        if cratepath.filetype() == Some(~".rlib") {
+            cc_args.push(cratepath.to_str());
+            loop;
+        }
+        let dir = cratepath.dirname();
+        if dir != ~"" { cc_args.push(~"-L" + dir); }
+        let libarg = unlib(sess.targ_cfg, cratepath.filestem().get());
+        cc_args.push(~"-l" + libarg);
+    }
+
+    let ula = cstore::get_used_link_args(cstore);
+    for ula.each |arg| { cc_args.push(*arg); }
+
+    // # Extern library linking
+
+    // User-supplied library search paths (-L on the cammand line) These are
+    // the same paths used to find Rust crates, so some of them may have been
+    // added already by the previous crate linking code. This only allows them
+    // to be found at compile time so it is still entirely up to outside
+    // forces to make sure that library can be found at runtime.
+
+    let addl_paths = sess.opts.addl_lib_search_paths;
+    for addl_paths.each |path| { cc_args.push(~"-L" + path.to_str()); }
+
+    // The names of the extern libraries
+    let used_libs = cstore::get_used_libraries(cstore);
+    for used_libs.each |l| { cc_args.push(~"-l" + *l); }
+
+    if sess.building_library {
+        cc_args.push(lib_cmd);
+
+        // On mac we need to tell the linker to let this library
+        // be rpathed
+        if sess.targ_cfg.os == session::os_macos {
+            cc_args.push(~"-Wl,-install_name,@rpath/"
+                      + output.filename().get());
+        }
+    }
+
+    // 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 {
+        cc_args.push_all(~[~"-lrt", ~"-ldl"]);
+
+        // LLVM implements the `frem` instruction as a call to `fmod`,
+        // which lives in libm. Similar to above, on some linuxes we
+        // have to be explicit about linking to it. See #2510
+        cc_args.push(~"-lm");
+    }
+
+    if sess.targ_cfg.os == session::os_freebsd {
+        cc_args.push_all(~[~"-pthread", ~"-lrt",
+                                ~"-L/usr/local/lib", ~"-lexecinfo",
+                                ~"-L/usr/local/lib/gcc46",
+                                ~"-L/usr/local/lib/gcc44", ~"-lstdc++",
+                                ~"-Wl,-z,origin",
+                                ~"-Wl,-rpath,/usr/local/lib/gcc46",
+                                ~"-Wl,-rpath,/usr/local/lib/gcc44"]);
+    }
+
+    // OS X 10.6 introduced 'compact unwind info', which is produced by the
+    // linker from the dwarf unwind info. Unfortunately, it does not seem to
+    // understand how to unwind our __morestack frame, so we have to turn it
+    // off. This has impacted some other projects like GHC.
+    if sess.targ_cfg.os == session::os_macos {
+        cc_args.push(~"-Wl,-no_compact_unwind");
+    }
+
+    // Stack growth requires statically linking a __morestack function
+    cc_args.push(~"-lmorestack");
+
+    // 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));
+
+    debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" "));
+    // We run 'cc' here
+    let prog = run::program_output(cc_prog, cc_args);
+    if 0 != prog.status {
+        sess.err(fmt!("linking with `%s` failed with code %d",
+                      cc_prog, prog.status));
+        sess.note(fmt!("%s arguments: %s",
+                       cc_prog, str::connect(cc_args, ~" ")));
+        sess.note(prog.err + prog.out);
+        sess.abort_if_errors();
+    }
+
+    // Clean up on Darwin
+    if sess.targ_cfg.os == session::os_macos {
+        run::run_program(~"dsymutil", ~[output.to_str()]);
+    }
+
+    // Remove the temporary object file if we aren't saving temps
+    if !sess.opts.save_temps {
+        if ! os::remove_file(obj_filename) {
+            sess.warn(fmt!("failed to delete object file `%s`",
+                           obj_filename.to_str()));
+        }
+    }
+}
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs
new file mode 100644
index 00000000000..8038d7bb6dd
--- /dev/null
+++ b/src/librustc/back/rpath.rs
@@ -0,0 +1,333 @@
+use std::map;
+use std::map::HashMap;
+use metadata::cstore;
+use driver::session;
+use metadata::filesearch;
+
+export get_rpath_flags;
+
+pure fn not_win32(os: session::os) -> bool {
+  match os {
+      session::os_win32 => false,
+      _ => true
+  }
+}
+
+fn get_rpath_flags(sess: session::Session, out_filename: &Path) -> ~[~str] {
+    let os = sess.targ_cfg.os;
+
+    // No rpath on windows
+    if os == session::os_win32 {
+        return ~[];
+    }
+
+    debug!("preparing the RPATH!");
+
+    let sysroot = sess.filesearch.sysroot();
+    let output = out_filename;
+    let libs = cstore::get_used_crate_files(sess.cstore);
+    // We don't currently rpath extern libraries, but we know
+    // where rustrt is and we know every rust program needs it
+    let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess));
+
+    let target_triple = sess.opts.target_triple;
+    let rpaths = get_rpaths(os, &sysroot, output, libs, target_triple);
+    rpaths_to_flags(rpaths)
+}
+
+fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
+    let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
+    sess.filesearch.sysroot().push_rel(&r).push(os::dll_filename("rustrt"))
+}
+
+fn rpaths_to_flags(rpaths: &[Path]) -> ~[~str] {
+    vec::map(rpaths, |rpath| fmt!("-Wl,-rpath,%s",rpath.to_str()))
+}
+
+fn get_rpaths(os: session::os,
+              sysroot: &Path,
+              output: &Path,
+              libs: &[Path],
+              target_triple: &str) -> ~[Path] {
+    debug!("sysroot: %s", sysroot.to_str());
+    debug!("output: %s", output.to_str());
+    debug!("libs:");
+    for libs.each |libpath| {
+        debug!("    %s", libpath.to_str());
+    }
+    debug!("target_triple: %s", target_triple);
+
+    // Use relative paths to the libraries. Binaries can be moved
+    // as long as they maintain the relative relationship to the
+    // crates they depend on.
+    let rel_rpaths = get_rpaths_relative_to_output(os, output, libs);
+
+    // Make backup absolute paths to the libraries. Binaries can
+    // be moved as long as the crates they link against don't move.
+    let abs_rpaths = get_absolute_rpaths(libs);
+
+    // And a final backup rpath to the global library location.
+    let fallback_rpaths = ~[get_install_prefix_rpath(target_triple)];
+
+    fn log_rpaths(desc: &str, rpaths: &[Path]) {
+        debug!("%s rpaths:", desc);
+        for rpaths.each |rpath| {
+            debug!("    %s", rpath.to_str());
+        }
+    }
+
+    log_rpaths(~"relative", rel_rpaths);
+    log_rpaths(~"absolute", abs_rpaths);
+    log_rpaths(~"fallback", fallback_rpaths);
+
+    let mut rpaths = rel_rpaths;
+    rpaths.push_all(abs_rpaths);
+    rpaths.push_all(fallback_rpaths);
+
+    // Remove duplicates
+    let rpaths = minimize_rpaths(rpaths);
+    return rpaths;
+}
+
+fn get_rpaths_relative_to_output(os: session::os,
+                                 output: &Path,
+                                 libs: &[Path]) -> ~[Path] {
+    vec::map(libs, |a| {
+        get_rpath_relative_to_output(os, output, a)
+    })
+}
+
+fn get_rpath_relative_to_output(os: session::os,
+                                output: &Path,
+                                lib: &Path) -> Path {
+    assert not_win32(os);
+
+    // Mac doesn't appear to support $ORIGIN
+    let prefix = match os {
+        session::os_linux | session::os_freebsd => "$ORIGIN",
+        session::os_macos => "@executable_path",
+        session::os_win32 => core::util::unreachable()
+    };
+
+    Path(prefix).push_rel(&get_relative_to(&os::make_absolute(output),
+                                           &os::make_absolute(lib)))
+}
+
+// Find the relative path from one file to another
+fn get_relative_to(abs1: &Path, abs2: &Path) -> Path {
+    assert abs1.is_absolute;
+    assert abs2.is_absolute;
+    let abs1 = abs1.normalize();
+    let abs2 = abs2.normalize();
+    debug!("finding relative path from %s to %s",
+           abs1.to_str(), abs2.to_str());
+    let split1 = abs1.components;
+    let split2 = abs2.components;
+    let len1 = vec::len(split1);
+    let len2 = vec::len(split2);
+    assert len1 > 0;
+    assert len2 > 0;
+
+    let max_common_path = uint::min(len1, len2) - 1;
+    let mut start_idx = 0;
+    while start_idx < max_common_path
+        && split1[start_idx] == split2[start_idx] {
+        start_idx += 1;
+    }
+
+    let mut path = ~[];
+    for uint::range(start_idx, len1 - 1) |_i| { path.push(~".."); };
+
+    path.push_all(vec::view(split2, start_idx, len2 - 1));
+
+    if vec::is_not_empty(path) {
+        return Path("").push_many(path);
+    } else {
+        return Path(".");
+    }
+}
+
+fn get_absolute_rpaths(libs: &[Path]) -> ~[Path] {
+    vec::map(libs, |a| get_absolute_rpath(a) )
+}
+
+fn get_absolute_rpath(lib: &Path) -> Path {
+    os::make_absolute(lib).dir_path()
+}
+
+fn get_install_prefix_rpath(target_triple: &str) -> Path {
+    let install_prefix = env!("CFG_PREFIX");
+
+    if install_prefix == ~"" {
+        fail ~"rustc compiled without CFG_PREFIX environment variable";
+    }
+
+    let tlib = filesearch::relative_target_lib_path(target_triple);
+    os::make_absolute(&Path(install_prefix).push_rel(&tlib))
+}
+
+fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] {
+    let set = map::HashMap();
+    let mut minimized = ~[];
+    for rpaths.each |rpath| {
+        let s = rpath.to_str();
+        if !set.contains_key(s) {
+            minimized.push(*rpath);
+            set.insert(s, ());
+        }
+    }
+    return minimized;
+}
+
+#[cfg(unix)]
+mod test {
+    #[legacy_exports];
+    #[test]
+    fn test_rpaths_to_flags() {
+        let flags = rpaths_to_flags(~[Path("path1"),
+                                      Path("path2")]);
+        assert flags == ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"];
+    }
+
+    #[test]
+    fn test_prefix_rpath() {
+        let res = get_install_prefix_rpath("triple");
+        let d = Path(env!("CFG_PREFIX"))
+            .push_rel(&Path("lib/rustc/triple/lib"));
+        debug!("test_prefix_path: %s vs. %s",
+               res.to_str(),
+               d.to_str());
+        assert str::ends_with(res.to_str(), d.to_str());
+    }
+
+    #[test]
+    fn test_prefix_rpath_abs() {
+        let res = get_install_prefix_rpath("triple");
+        assert res.is_absolute;
+    }
+
+    #[test]
+    fn test_minimize1() {
+        let res = minimize_rpaths([Path("rpath1"),
+                                   Path("rpath2"),
+                                   Path("rpath1")]);
+        assert res == ~[Path("rpath1"), Path("rpath2")];
+    }
+
+    #[test]
+    fn test_minimize2() {
+        let res = minimize_rpaths(~[Path("1a"), Path("2"), Path("2"),
+                                    Path("1a"), Path("4a"),Path("1a"),
+                                    Path("2"), Path("3"), Path("4a"),
+                                    Path("3")]);
+        assert res == ~[Path("1a"), Path("2"), Path("4a"), Path("3")];
+    }
+
+    #[test]
+    fn test_relative_to1() {
+        let p1 = Path("/usr/bin/rustc");
+        let p2 = Path("/usr/lib/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
+    }
+
+    #[test]
+    fn test_relative_to2() {
+        let p1 = Path("/usr/bin/rustc");
+        let p2 = Path("/usr/bin/../lib/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
+    }
+
+    #[test]
+    fn test_relative_to3() {
+        let p1 = Path("/usr/bin/whatever/rustc");
+        let p2 = Path("/usr/lib/whatever/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../../lib/whatever");
+    }
+
+    #[test]
+    fn test_relative_to4() {
+        let p1 = Path("/usr/bin/whatever/../rustc");
+        let p2 = Path("/usr/lib/whatever/mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib/whatever");
+    }
+
+    #[test]
+    fn test_relative_to5() {
+        let p1 = Path("/usr/bin/whatever/../rustc");
+        let p2 = Path("/usr/lib/whatever/../mylib");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("../lib");
+    }
+
+    #[test]
+    fn test_relative_to6() {
+        let p1 = Path("/1");
+        let p2 = Path("/2/3");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("2");
+    }
+
+    #[test]
+    fn test_relative_to7() {
+        let p1 = Path("/1/2");
+        let p2 = Path("/3");
+        let res = get_relative_to(&p1, &p2);
+        assert res == Path("..");
+    }
+
+    #[test]
+    fn test_relative_to8() {
+        let p1 = Path("/home/brian/Dev/rust/build/").push_rel(
+            &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
+        let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
+            &Path("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
+        let res = get_relative_to(&p1, &p2);
+        debug!("test_relative_tu8: %s vs. %s",
+               res.to_str(),
+               Path(".").to_str());
+        assert res == Path(".");
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn test_rpath_relative() {
+      let o = session::os_linux;
+      let res = get_rpath_relative_to_output(o,
+            &Path("bin/rustc"), &Path("lib/libstd.so"));
+      assert res.to_str() == ~"$ORIGIN/../lib";
+    }
+
+    #[test]
+    #[cfg(target_os = "freebsd")]
+    fn test_rpath_relative() {
+        let o = session::os_freebsd;
+        let res = get_rpath_relative_to_output(o,
+            &Path("bin/rustc"), &Path("lib/libstd.so"));
+        assert res.to_str() == ~"$ORIGIN/../lib";
+    }
+
+    #[test]
+    #[cfg(target_os = "macos")]
+    fn test_rpath_relative() {
+        // this is why refinements would be nice
+        let o = session::os_macos;
+        let res = get_rpath_relative_to_output(o,
+                                               &Path("bin/rustc"),
+                                               &Path("lib/libstd.so"));
+        assert res.to_str() == ~"@executable_path/../lib";
+    }
+
+    #[test]
+    fn test_get_absolute_rpath() {
+        let res = get_absolute_rpath(&Path("lib/libstd.so"));
+        debug!("test_get_absolute_rpath: %s vs. %s",
+               res.to_str(),
+               os::make_absolute(&Path("lib")).to_str());
+
+        assert res == os::make_absolute(&Path("lib"));
+    }
+}
diff --git a/src/librustc/back/target_strs.rs b/src/librustc/back/target_strs.rs
new file mode 100644
index 00000000000..798c4868a7c
--- /dev/null
+++ b/src/librustc/back/target_strs.rs
@@ -0,0 +1,7 @@
+type t = {
+    module_asm: ~str,
+    meta_sect_name: ~str,
+    data_layout: ~str,
+    target_triple: ~str,
+    cc_args: ~[~str]
+};
diff --git a/src/librustc/back/upcall.rs b/src/librustc/back/upcall.rs
new file mode 100644
index 00000000000..4b823680f14
--- /dev/null
+++ b/src/librustc/back/upcall.rs
@@ -0,0 +1,59 @@
+
+use driver::session;
+use middle::trans::base;
+use middle::trans::common::{T_fn, T_i1, T_i8, T_i32,
+                               T_int, T_nil,
+                               T_opaque_vec, T_ptr, T_unique_ptr,
+                               T_size_t, T_void, T_vec2};
+use lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};
+
+type upcalls =
+    {trace: ValueRef,
+     call_shim_on_c_stack: ValueRef,
+     call_shim_on_rust_stack: ValueRef,
+     rust_personality: ValueRef,
+     reset_stack_limit: ValueRef};
+
+fn declare_upcalls(targ_cfg: @session::config,
+                   llmod: ModuleRef) -> @upcalls {
+    fn decl(llmod: ModuleRef, prefix: ~str, name: ~str,
+            tys: ~[TypeRef], rv: TypeRef) ->
+       ValueRef {
+        let arg_tys = tys.map(|t| *t);
+        let fn_ty = T_fn(arg_tys, rv);
+        return base::decl_cdecl_fn(llmod, prefix + name, fn_ty);
+    }
+    fn nothrow(f: ValueRef) -> ValueRef {
+        base::set_no_unwind(f); f
+    }
+    let d = |a,b,c| decl(llmod, ~"upcall_", a, b, c);
+    let dv = |a,b| decl(llmod, ~"upcall_", a, b, T_void());
+
+    let int_t = T_int(targ_cfg);
+
+    return @{trace: dv(~"trace", ~[T_ptr(T_i8()),
+                              T_ptr(T_i8()),
+                              int_t]),
+          call_shim_on_c_stack:
+              d(~"call_shim_on_c_stack",
+                // arguments: void *args, void *fn_ptr
+                ~[T_ptr(T_i8()), T_ptr(T_i8())],
+                int_t),
+          call_shim_on_rust_stack:
+              d(~"call_shim_on_rust_stack",
+                ~[T_ptr(T_i8()), T_ptr(T_i8())], int_t),
+          rust_personality:
+              nothrow(d(~"rust_personality", ~[], T_i32())),
+          reset_stack_limit:
+              nothrow(dv(~"reset_stack_limit", ~[]))
+         };
+}
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs
new file mode 100644
index 00000000000..8d4b50f9ac4
--- /dev/null
+++ b/src/librustc/back/x86.rs
@@ -0,0 +1,51 @@
+use driver::session;
+use session::sess_os_to_meta_os;
+use metadata::loader::meta_section_name;
+
+fn get_target_strs(target_os: session::os) -> target_strs::t {
+    return {
+        module_asm: ~"",
+
+        meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)),
+
+        data_layout: match target_os {
+          session::os_macos => {
+            ~"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" +
+                ~"-i32:32:32-i64:32:64" +
+                ~"-f32:32:32-f64:32:64-v64:64:64" +
+                ~"-v128:128:128-a0:0:64-f80:128:128" + ~"-n8:16:32"
+          }
+
+          session::os_win32 => {
+            ~"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32"
+          }
+
+          session::os_linux => {
+            ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
+          }
+
+          session::os_freebsd => {
+            ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
+          }
+        },
+
+        target_triple: match target_os {
+          session::os_macos => ~"i686-apple-darwin",
+          session::os_win32 => ~"i686-pc-mingw32",
+          session::os_linux => ~"i686-unknown-linux-gnu",
+          session::os_freebsd => ~"i686-unknown-freebsd"
+        },
+
+        cc_args: ~[~"-m32"]
+    };
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs
new file mode 100644
index 00000000000..ec2f5b18490
--- /dev/null
+++ b/src/librustc/back/x86_64.rs
@@ -0,0 +1,57 @@
+use driver::session;
+use session::sess_os_to_meta_os;
+use metadata::loader::meta_section_name;
+
+fn get_target_strs(target_os: session::os) -> target_strs::t {
+    return {
+        module_asm: ~"",
+
+        meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)),
+
+        data_layout: match target_os {
+          session::os_macos => {
+            ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
+                ~"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
+                ~"s0:64:64-f80:128:128-n8:16:32:64"
+          }
+
+          session::os_win32 => {
+            // FIXME: Test this. Copied from linux (#2398)
+            ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
+                ~"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
+                ~"s0:64:64-f80:128:128-n8:16:32:64-S128"
+          }
+
+          session::os_linux => {
+            ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
+                ~"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
+                ~"s0:64:64-f80:128:128-n8:16:32:64-S128"
+          }
+
+          session::os_freebsd => {
+            ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
+                ~"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
+                ~"s0:64:64-f80:128:128-n8:16:32:64-S128"
+          }
+        },
+
+        target_triple: match target_os {
+          session::os_macos => ~"x86_64-apple-darwin",
+          session::os_win32 => ~"x86_64-pc-mingw32",
+          session::os_linux => ~"x86_64-unknown-linux-gnu",
+          session::os_freebsd => ~"x86_64-unknown-freebsd",
+        },
+
+        cc_args: ~[~"-m64"]
+    };
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//