about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/tutorial-ffi.md23
-rw-r--r--src/librustc/back/arm.rs14
-rw-r--r--src/librustc/back/link.rs31
-rw-r--r--src/librustc/back/mips.rs14
-rw-r--r--src/librustc/back/rpath.rs30
-rw-r--r--src/librustc/back/x86.rs14
-rw-r--r--src/librustc/back/x86_64.rs14
-rw-r--r--src/librustc/driver/driver.rs28
-rw-r--r--src/librustc/driver/session.rs17
-rw-r--r--src/librustc/middle/entry.rs5
-rw-r--r--src/librustc/middle/trans/base.rs11
-rw-r--r--src/librustc/middle/trans/cabi_x86.rs2
-rw-r--r--src/librustc/middle/trans/foreign.rs8
-rw-r--r--src/libsyntax/abi.rs49
14 files changed, 151 insertions, 109 deletions
diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md
index 57dc926dfa9..7d975d0ef62 100644
--- a/doc/tutorial-ffi.md
+++ b/doc/tutorial-ffi.md
@@ -418,15 +418,32 @@ calling foreign functions. Some foreign functions, most notably the Windows API,
 conventions. Rust provides a way to tell the compiler which convention to use:
 
 ~~~~
-#[cfg(target_os = "win32")]
+#[cfg(target_os = "win32", target_arch = "x86")]
 #[link_name = "kernel32"]
 extern "stdcall" {
     fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
 }
 ~~~~
 
-This applies to the entire `extern` block, and must be either `"cdecl"` or
-`"stdcall"`. The compiler may eventually support other calling conventions.
+This applies to the entire `extern` block. The list of supported ABI constraints
+are:
+
+* `stdcall`
+* `aapcs`
+* `cdecl`
+* `fastcall`
+* `Rust`
+* `rust-intrinsic`
+* `system`
+* `C`
+
+Most of the abis in this list are self-explanatory, but the `system` abi may
+seem a little odd. This constraint selects whatever the appropriate ABI is for
+interoperating with the target's libraries. For example, on win32 with a x86
+architecture, this means that the abi used would be `stdcall`. On x86_64,
+however, windows uses the `C` calling convention, so `C` would be used. This
+means that in our previous example, we could have used `extern "system" { ... }`
+to define a block for all windows systems, not just x86 ones.
 
 # Interoperability with foreign code
 
diff --git a/src/librustc/back/arm.rs b/src/librustc/back/arm.rs
index 42855b63ff8..a3ac468a5f0 100644
--- a/src/librustc/back/arm.rs
+++ b/src/librustc/back/arm.rs
@@ -10,17 +10,17 @@
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 5b0f424360b..a33db012819 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -32,6 +32,7 @@ use std::run;
 use std::str;
 use std::vec;
 use std::rt::io::fs;
+use syntax::abi;
 use syntax::ast;
 use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
 use syntax::attr;
@@ -864,13 +865,13 @@ pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str
 }
 
 
-pub fn output_dll_filename(os: session::Os, lm: LinkMeta) -> ~str {
+pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str {
     let (dll_prefix, dll_suffix) = match os {
-        session::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
-        session::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
-        session::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
-        session::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
-        session::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
+        abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
+        abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
+        abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
+        abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
+        abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
     };
     format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
 }
@@ -885,7 +886,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
     match sess.opts.linker {
         Some(ref linker) => linker.to_str(),
         None => match sess.targ_cfg.os {
-            session::OsAndroid =>
+            abi::OsAndroid =>
                 match &sess.opts.android_cross_path {
                     &Some(ref path) => {
                         format!("{}/bin/arm-linux-androideabi-gcc", *path)
@@ -895,7 +896,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
                                     (--android-cross-path)")
                     }
                 },
-            session::OsWin32 => ~"g++",
+            abi::OsWin32 => ~"g++",
             _ => ~"cc"
         }
     }
@@ -943,7 +944,7 @@ pub fn link_binary(sess: Session,
     }
 
     // Clean up on Darwin
-    if sess.targ_cfg.os == session::OsMacos {
+    if sess.targ_cfg.os == abi::OsMacos {
         // FIXME (#9639): This needs to handle non-utf8 paths
         run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]);
     }
@@ -972,7 +973,7 @@ pub fn link_args(sess: Session,
     // Converts a library file-stem into a cc -l argument
     fn unlib(config: @session::config, stem: ~str) -> ~str {
         if stem.starts_with("lib") &&
-            config.os != session::OsWin32 {
+            config.os != abi::OsWin32 {
             stem.slice(3, stem.len()).to_owned()
         } else {
             stem
@@ -1016,7 +1017,7 @@ pub fn link_args(sess: Session,
         obj_filename.as_str().unwrap().to_owned()]);
 
     let lib_cmd = match sess.targ_cfg.os {
-        session::OsMacos => ~"-dynamiclib",
+        abi::OsMacos => ~"-dynamiclib",
         _ => ~"-shared"
     };
 
@@ -1067,7 +1068,7 @@ pub fn link_args(sess: Session,
 
         // On mac we need to tell the linker to let this library
         // be rpathed
-        if sess.targ_cfg.os == session::OsMacos {
+        if sess.targ_cfg.os == abi::OsMacos {
             // FIXME (#9639): This needs to handle non-utf8 paths
             args.push("-Wl,-install_name,@rpath/"
                       + output.filename_str().unwrap());
@@ -1076,7 +1077,7 @@ pub fn link_args(sess: Session,
 
     // 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::OsLinux {
+    if sess.targ_cfg.os == abi::OsLinux {
         args.push_all([~"-lrt", ~"-ldl"]);
 
         // LLVM implements the `frem` instruction as a call to `fmod`,
@@ -1084,12 +1085,12 @@ pub fn link_args(sess: Session,
         // have to be explicit about linking to it. See #2510
         args.push(~"-lm");
     }
-    else if sess.targ_cfg.os == session::OsAndroid {
+    else if sess.targ_cfg.os == abi::OsAndroid {
         args.push_all([~"-ldl", ~"-llog",  ~"-lsupc++", ~"-lgnustl_shared"]);
         args.push(~"-lm");
     }
 
-    if sess.targ_cfg.os == session::OsFreebsd {
+    if sess.targ_cfg.os == abi::OsFreebsd {
         args.push_all([~"-pthread", ~"-lrt",
                        ~"-L/usr/local/lib", ~"-lexecinfo",
                        ~"-L/usr/local/lib/gcc46",
diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs
index 52d8463adfe..cbe39efdf8c 100644
--- a/src/librustc/back/mips.rs
+++ b/src/librustc/back/mips.rs
@@ -9,18 +9,18 @@
 // except according to those terms.
 
 use back::target_strs;
-use driver::session;
 use driver::session::sess_os_to_meta_os;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs
index 6f76b228d3e..5e6a5080dce 100644
--- a/src/librustc/back/rpath.rs
+++ b/src/librustc/back/rpath.rs
@@ -15,9 +15,10 @@ use metadata::filesearch;
 
 use std::hashmap::HashSet;
 use std::{os, vec};
+use syntax::abi;
 
-fn not_win32(os: session::Os) -> bool {
-  os != session::OsWin32
+fn not_win32(os: abi::Os) -> bool {
+  os != abi::OsWin32
 }
 
 pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
@@ -25,7 +26,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
     let os = sess.targ_cfg.os;
 
     // No rpath on windows
-    if os == session::OsWin32 {
+    if os == abi::OsWin32 {
         return ~[];
     }
 
@@ -55,7 +56,7 @@ pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
     rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect()
 }
 
-fn get_rpaths(os: session::Os,
+fn get_rpaths(os: abi::Os,
               sysroot: &Path,
               output: &Path,
               libs: &[Path],
@@ -100,13 +101,13 @@ fn get_rpaths(os: session::Os,
     return rpaths;
 }
 
-fn get_rpaths_relative_to_output(os: session::Os,
+fn get_rpaths_relative_to_output(os: abi::Os,
                                  output: &Path,
                                  libs: &[Path]) -> ~[~str] {
     libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect()
 }
 
-pub fn get_rpath_relative_to_output(os: session::Os,
+pub fn get_rpath_relative_to_output(os: abi::Os,
                                     output: &Path,
                                     lib: &Path)
                                  -> ~str {
@@ -116,10 +117,10 @@ pub fn get_rpath_relative_to_output(os: session::Os,
 
     // Mac doesn't appear to support $ORIGIN
     let prefix = match os {
-        session::OsAndroid | session::OsLinux | session::OsFreebsd
+        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
                           => "$ORIGIN",
-        session::OsMacos => "@loader_path",
-        session::OsWin32 => unreachable!()
+        abi::OsMacos => "@loader_path",
+        abi::OsWin32 => unreachable!()
     };
 
     let mut lib = os::make_absolute(lib);
@@ -169,13 +170,10 @@ pub fn minimize_rpaths(rpaths: &[~str]) -> ~[~str] {
 mod test {
     use std::os;
 
-    // FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then
-    // these redundant #[cfg(test)] blocks can be removed
-    #[cfg(test)]
-    #[cfg(test)]
     use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
     use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
     use driver::session;
+    use syntax::abi;
 
     #[test]
     fn test_rpaths_to_flags() {
@@ -219,7 +217,7 @@ mod test {
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     fn test_rpath_relative() {
-      let o = session::OsLinux;
+      let o = abi::OsLinux;
       let res = get_rpath_relative_to_output(o,
             &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
       assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@@ -228,7 +226,7 @@ mod test {
     #[test]
     #[cfg(target_os = "freebsd")]
     fn test_rpath_relative() {
-        let o = session::OsFreebsd;
+        let o = abi::OsFreebsd;
         let res = get_rpath_relative_to_output(o,
             &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
         assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@@ -237,7 +235,7 @@ mod test {
     #[test]
     #[cfg(target_os = "macos")]
     fn test_rpath_relative() {
-        let o = session::OsMacos;
+        let o = abi::OsMacos;
         let res = get_rpath_relative_to_output(o,
                                                &Path::new("bin/rustc"),
                                                &Path::new("lib/libstd.so"));
diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs
index 4518ec0a148..b3c92bc4057 100644
--- a/src/librustc/back/x86.rs
+++ b/src/librustc/back/x86.rs
@@ -11,35 +11,35 @@
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"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::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
         },
diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs
index 3833f0d2b94..3237085dfb9 100644
--- a/src/librustc/back/x86_64.rs
+++ b/src/librustc/back/x86_64.rs
@@ -11,41 +11,41 @@
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"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::OsWin32 => {
+          abi::OsWin32 => {
             // 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::OsLinux => {
+          abi::OsLinux => {
             ~"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::OsAndroid => {
+          abi::OsAndroid => {
             ~"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::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"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"
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index c57cd134e01..0fc17e46281 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -69,11 +69,11 @@ pub fn source_name(input: &input) -> @str {
 pub fn default_configuration(sess: Session) ->
    ast::CrateConfig {
     let tos = match sess.targ_cfg.os {
-        session::OsWin32 =>   @"win32",
-        session::OsMacos =>   @"macos",
-        session::OsLinux =>   @"linux",
-        session::OsAndroid => @"android",
-        session::OsFreebsd => @"freebsd"
+        abi::OsWin32 =>   @"win32",
+        abi::OsMacos =>   @"macos",
+        abi::OsLinux =>   @"linux",
+        abi::OsAndroid => @"android",
+        abi::OsFreebsd => @"freebsd"
     };
 
     // ARM is bi-endian, however using NDK seems to default
@@ -353,7 +353,7 @@ pub fn phase_5_run_llvm_passes(sess: Session,
     // segmented stacks are enabled.  However, unwind info directives in assembly
     // output are OK, so we generate assembly first and then run it through
     // an external assembler.
-    if sess.targ_cfg.os == session::OsWin32 &&
+    if sess.targ_cfg.os == abi::OsWin32 &&
         (sess.opts.output_type == link::output_type_object ||
          sess.opts.output_type == link::output_type_exe) {
         let output_type = link::output_type_assembly;
@@ -567,19 +567,19 @@ pub fn pretty_print_input(sess: Session,
                         is_expanded);
 }
 
-pub fn get_os(triple: &str) -> Option<session::Os> {
+pub fn get_os(triple: &str) -> Option<abi::Os> {
     for &(name, os) in os_names.iter() {
         if triple.contains(name) { return Some(os) }
     }
     None
 }
-static os_names : &'static [(&'static str, session::Os)] = &'static [
-    ("mingw32", session::OsWin32),
-    ("win32",   session::OsWin32),
-    ("darwin",  session::OsMacos),
-    ("android", session::OsAndroid),
-    ("linux",   session::OsLinux),
-    ("freebsd", session::OsFreebsd)];
+static os_names : &'static [(&'static str, abi::Os)] = &'static [
+    ("mingw32", abi::OsWin32),
+    ("win32",   abi::OsWin32),
+    ("darwin",  abi::OsMacos),
+    ("android", abi::OsAndroid),
+    ("linux",   abi::OsLinux),
+    ("freebsd", abi::OsFreebsd)];
 
 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
     for &(arch, abi) in architecture_abis.iter() {
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 8c1693935c7..57edb355d32 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -31,9 +31,6 @@ use syntax;
 use std::int;
 use std::hashmap::{HashMap,HashSet};
 
-#[deriving(Eq)]
-pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
-
 #[deriving(Clone)]
 pub enum crate_type {
     bin_crate,
@@ -42,7 +39,7 @@ pub enum crate_type {
 }
 
 pub struct config {
-    os: Os,
+    os: abi::Os,
     arch: abi::Architecture,
     target_strs: target_strs::t,
     int_type: int_ty,
@@ -410,15 +407,15 @@ pub fn building_library(req_crate_type: crate_type,
     }
 }
 
-pub fn sess_os_to_meta_os(os: Os) -> metadata::loader::Os {
+pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
     use metadata::loader;
 
     match os {
-        OsWin32 => loader::OsWin32,
-        OsLinux => loader::OsLinux,
-        OsAndroid => loader::OsAndroid,
-        OsMacos => loader::OsMacos,
-        OsFreebsd => loader::OsFreebsd
+        abi::OsWin32 => loader::OsWin32,
+        abi::OsLinux => loader::OsLinux,
+        abi::OsAndroid => loader::OsAndroid,
+        abi::OsMacos => loader::OsMacos,
+        abi::OsFreebsd => loader::OsFreebsd
     }
 }
 
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 2ebb6e6926e..20b630e3063 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -11,6 +11,7 @@
 
 use driver::session;
 use driver::session::Session;
+use syntax::abi;
 use syntax::ast::{Crate, NodeId, item, item_fn};
 use syntax::ast_map;
 use syntax::attr;
@@ -48,7 +49,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
 
     // FIXME #4404 android JNI hacks
     if *session.building_library &&
-        session.targ_cfg.os != session::OsAndroid {
+        session.targ_cfg.os != abi::OsAndroid {
         // No need to find a main function
         return;
     }
@@ -151,7 +152,7 @@ fn configure_main(this: &mut EntryContext) {
         } else {
             // If we *are* building a library, then we're on android where we still might
             // optionally want to translate main $4404
-            assert_eq!(this.session.targ_cfg.os, session::OsAndroid);
+            assert_eq!(this.session.targ_cfg.os, abi::OsAndroid);
         }
     }
 }
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 37e4d4e82be..8c9cc3b8e13 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -85,7 +85,7 @@ use syntax::parse::token;
 use syntax::parse::token::{special_idents};
 use syntax::print::pprust::stmt_to_str;
 use syntax::{ast, ast_util, codemap, ast_map};
-use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
+use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic, OsWin32, OsAndroid};
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -853,7 +853,8 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) ->
     let name = csearch::get_symbol(ccx.sess.cstore, did);
     match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+            match fn_ty.abis.for_target(ccx.sess.targ_cfg.os,
+                                        ccx.sess.targ_cfg.arch) {
                 Some(Rust) | Some(RustIntrinsic) => {
                     get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name, did)
                 }
@@ -2312,7 +2313,7 @@ fn finish_register_fn(ccx: @mut CrateContext, sp: Span, sym: ~str, node_id: ast:
     // FIXME #4404 android JNI hacks
     let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
                       (*ccx.sess.building_library &&
-                       ccx.sess.targ_cfg.os == session::OsAndroid));
+                       ccx.sess.targ_cfg.os == OsAndroid));
     if is_entry {
         create_entry_wrapper(ccx, sp, llfn);
     }
@@ -2981,7 +2982,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
     };
     // On windows we'd like to export the toplevel cratemap
     // such that we can find it from libstd.
-    if targ_cfg.os == session::OsWin32 && "toplevel" == mapname {
+    if targ_cfg.os == OsWin32 && "toplevel" == mapname {
         lib::llvm::SetLinkage(map, lib::llvm::DLLExportLinkage);
     } else {
         lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
@@ -3157,7 +3158,7 @@ pub fn trans_crate(sess: session::Session,
     // __rust_crate_map_toplevel symbol (extra underscore) which it will
     // subsequently fail to find. So to mitigate that we just introduce
     // an alias from the symbol it expects to the one that actually exists.
-    if ccx.sess.targ_cfg.os == session::OsWin32 &&
+    if ccx.sess.targ_cfg.os == OsWin32 &&
        !*ccx.sess.building_library {
 
         let maptype = val_ty(ccx.crate_map).to_ref();
diff --git a/src/librustc/middle/trans/cabi_x86.rs b/src/librustc/middle/trans/cabi_x86.rs
index 244087f814c..f8cc246f682 100644
--- a/src/librustc/middle/trans/cabi_x86.rs
+++ b/src/librustc/middle/trans/cabi_x86.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-use driver::session::{OsWin32, OsMacos};
+use syntax::abi::{OsWin32, OsMacos};
 use lib::llvm::*;
 use super::cabi::*;
 use super::common::*;
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index ef843b56f4b..7da80507df0 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -32,7 +32,7 @@ use syntax::codemap::Span;
 use syntax::{ast};
 use syntax::{attr, ast_map};
 use syntax::parse::token::special_idents;
-use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
+use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System,
                   Cdecl, Aapcs, C, AbiSet};
 use util::ppaux::{Repr, UserString};
 use middle::trans::type_::Type;
@@ -75,8 +75,9 @@ struct LlvmSignature {
 
 pub fn llvm_calling_convention(ccx: &mut CrateContext,
                                abis: AbiSet) -> Option<CallConv> {
+    let os = ccx.sess.targ_cfg.os;
     let arch = ccx.sess.targ_cfg.arch;
-    abis.for_arch(arch).map(|abi| {
+    abis.for_target(os, arch).map(|abi| {
         match abi {
             RustIntrinsic => {
                 // Intrinsics are emitted by monomorphic fn
@@ -89,6 +90,9 @@ pub fn llvm_calling_convention(ccx: &mut CrateContext,
                     format!("Foreign functions with Rust ABI"));
             }
 
+            // It's the ABI's job to select this, not us.
+            System => ccx.sess.bug("System abi should be selected elsewhere"),
+
             Stdcall => lib::llvm::X86StdcallCallConv,
             Fastcall => lib::llvm::X86FastcallCallConv,
             C => lib::llvm::CCallConv,
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index ed20b160eb4..972d2f43e73 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -11,6 +11,9 @@
 use std::to_bytes;
 
 #[deriving(Eq)]
+pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
+
+#[deriving(Eq)]
 pub enum Abi {
     // NB: This ordering MUST match the AbiDatas array below.
     // (This is ensured by the test indices_are_correct().)
@@ -24,6 +27,7 @@ pub enum Abi {
     // Multiplatform ABIs second
     Rust,
     C,
+    System,
     RustIntrinsic,
 }
 
@@ -76,6 +80,7 @@ static AbiDatas: &'static [AbiData] = &[
     // adjusting the indices below.
     AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
     AbiData {abi: C, name: "C", abi_arch: AllArch},
+    AbiData {abi: System, name: "system", abi_arch: AllArch},
     AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
 ];
 
@@ -125,6 +130,14 @@ impl Abi {
     pub fn name(&self) -> &'static str {
         self.data().name
     }
+
+    pub fn for_target(&self, os: Os, arch: Architecture) -> Abi {
+        match (*self, os, arch) {
+            (System, OsWin32, X86) => Stdcall,
+            (System, _, _) => C,
+            (me, _, _) => me,
+        }
+    }
 }
 
 impl Architecture {
@@ -196,7 +209,7 @@ impl AbiSet {
         self.bits == 0
     }
 
-    pub fn for_arch(&self, arch: Architecture) -> Option<Abi> {
+    pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
         // NB---Single platform ABIs come first
 
         let mut res = None;
@@ -210,7 +223,7 @@ impl AbiSet {
             }
         };
 
-        res
+        res.map(|r| r.for_target(os, arch))
     }
 
     pub fn check_valid(&self) -> Option<(Abi, Abi)> {
@@ -345,6 +358,11 @@ fn cannot_combine_rust_intrinsic_and_cdecl() {
 }
 
 #[test]
+fn can_combine_system_and_cdecl() {
+    can_combine(System, Cdecl);
+}
+
+#[test]
 fn can_combine_c_and_stdcall() {
     can_combine(C, Stdcall);
 }
@@ -382,36 +400,41 @@ fn abi_to_str_rust() {
 #[test]
 fn indices_are_correct() {
     for (i, abi_data) in AbiDatas.iter().enumerate() {
-        assert!(i == abi_data.abi.index());
+        assert_eq!(i, abi_data.abi.index());
     }
 
     let bits = 1 << (X86 as u32);
     let bits = bits | 1 << (X86_64 as u32);
-    assert!(IntelBits == bits);
+    assert_eq!(IntelBits, bits);
 
     let bits = 1 << (Arm as u32);
-    assert!(ArmBits == bits);
+    assert_eq!(ArmBits, bits);
 }
 
 #[cfg(test)]
-fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
+fn get_arch(abis: &[Abi], os: Os, arch: Architecture) -> Option<Abi> {
     let mut set = AbiSet::empty();
     for &abi in abis.iter() {
         set.add(abi);
     }
-    let r = set.for_arch(arch);
-    assert!(r == expect);
+    set.for_target(os, arch)
 }
 
 #[test]
 fn pick_multiplatform() {
-    check_arch([C, Cdecl], X86, Some(Cdecl));
-    check_arch([C, Cdecl], X86_64, Some(Cdecl));
-    check_arch([C, Cdecl], Arm, Some(C));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, X86), Some(Cdecl));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, X86_64), Some(Cdecl));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, Arm), Some(C));
 }
 
 #[test]
 fn pick_uniplatform() {
-    check_arch([Stdcall], X86, Some(Stdcall));
-    check_arch([Stdcall], Arm, None);
+    assert_eq!(get_arch([Stdcall], OsLinux, X86), Some(Stdcall));
+    assert_eq!(get_arch([Stdcall], OsLinux, Arm), None);
+    assert_eq!(get_arch([System], OsLinux, X86), Some(C));
+    assert_eq!(get_arch([System], OsWin32, X86), Some(Stdcall));
+    assert_eq!(get_arch([System], OsWin32, X86_64), Some(C));
+    assert_eq!(get_arch([System], OsWin32, Arm), Some(C));
+    assert_eq!(get_arch([Stdcall], OsWin32, X86), Some(Stdcall));
+    assert_eq!(get_arch([Stdcall], OsWin32, X86_64), Some(Stdcall));
 }