diff --git a/Cargo.toml b/Cargo.toml
index f3b9e843788..0da280f24e2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,9 @@ edition = "2018"
 [lib]
 crate-type = ["dylib"]
 
+[features]
+backend_object = ["object/write"]
+
 [dependencies]
 # These have to be in sync with each other
 cranelift = { git = "https://github.com/CraneStation/cranelift.git" }
@@ -29,7 +32,7 @@ libloading = "0.5.1"
 [dependencies.object]
 version = "0.14.0"
 default-features = false
-features = ["compression", "read", "std", "write"] # We don't need WASM support
+features = ["compression", "read", "std"] # We don't need WASM support
 
 # Uncomment to use local checkout of cranelift
 #[patch."https://github.com/CraneStation/cranelift.git"]
diff --git a/src/backend.rs b/src/backend.rs
index 429c48ba0e3..449e2a5cc26 100644
--- a/src/backend.rs
+++ b/src/backend.rs
@@ -1,10 +1,13 @@
 use std::collections::HashMap;
 
-use cranelift_module::FuncId;
+use rustc::session::Session;
+
+use cranelift_module::{FuncId, Module};
 
 use faerie::*;
 use object::{SectionKind, RelocationKind, RelocationEncoding};
 use object::write::*;
+use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
 use cranelift_object::*;
 
 use gimli::SectionId;
@@ -73,11 +76,11 @@ pub trait WriteDebugInfo {
     );
 }
 
-impl WriteDebugInfo for Artifact {
+impl WriteDebugInfo for FaerieProduct {
     type SectionId = SectionId;
 
     fn add_debug_section(&mut self, id: SectionId, data: Vec<u8>) -> SectionId {
-        self.declare_with(id.name(), Decl::section(faerie::SectionKind::Debug), data).unwrap();
+        self.artifact.declare_with(id.name(), Decl::section(faerie::SectionKind::Debug), data).unwrap();
         id
     }
 
@@ -89,6 +92,7 @@ impl WriteDebugInfo for Artifact {
         reloc: &DebugReloc,
     ) {
         self
+            .artifact
             .link_with(
                 faerie::Link {
                     from: from.name(),
@@ -147,3 +151,69 @@ impl WriteDebugInfo for ObjectProduct {
         }).unwrap();
     }
 }
+
+pub trait Emit {
+    fn emit(self) -> Vec<u8>;
+}
+
+impl Emit for FaerieProduct {
+    fn emit(self) -> Vec<u8> {
+        self.artifact.emit().unwrap()
+    }
+}
+
+impl Emit for ObjectProduct {
+    fn emit(self) -> Vec<u8> {
+        self.object.write().unwrap()
+    }
+}
+
+#[cfg(not(feature = "backend_object"))]
+pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Artifact)) -> Vec<u8> {
+    let mut metadata_artifact = faerie::Artifact::new(
+        crate::build_isa(sess, true).triple().clone(),
+        name.to_string(),
+    );
+    f(&mut metadata_artifact);
+    metadata_artifact.emit().unwrap()
+}
+
+#[cfg(feature = "backend_object")]
+pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
+    let triple = crate::build_isa(sess, true).triple().clone();
+    let mut metadata_object =
+        object::write::Object::new(triple.binary_format, triple.architecture);
+    metadata_object.add_file_symbol(name.as_bytes().to_vec());
+    f(&mut metadata_object);
+    metadata_object.write().unwrap()
+}
+
+pub type Backend = impl cranelift_module::Backend<Product: Emit + WriteDebugInfo>;
+
+#[cfg(not(feature = "backend_object"))]
+pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
+    let module: Module<FaerieBackend> = Module::new(
+        FaerieBuilder::new(
+            crate::build_isa(sess, true),
+            name + ".o",
+            FaerieTrapCollection::Disabled,
+            cranelift_module::default_libcall_names(),
+        )
+        .unwrap(),
+    );
+    module
+}
+
+#[cfg(feature = "backend_object")]
+pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
+    let module: Module<ObjectBackend> = Module::new(
+        ObjectBuilder::new(
+            crate::build_isa(sess, true),
+            name + ".o",
+            ObjectTrapCollection::Disabled,
+            cranelift_module::default_libcall_names(),
+        )
+        .unwrap(),
+    );
+    module
+}
diff --git a/src/driver.rs b/src/driver.rs
index 19f53ebda13..b26da23da90 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -8,10 +8,10 @@ use rustc::session::config::{DebugInfo, OutputType};
 use rustc_codegen_ssa::back::linker::LinkerInfo;
 use rustc_codegen_ssa::CrateInfo;
 
-use cranelift_faerie::*;
-
 use crate::prelude::*;
 
+use crate::backend::{Emit, WriteDebugInfo};
+
 pub fn codegen_crate(
     tcx: TyCtxt<'_>,
     metadata: EncodedMetadata,
@@ -147,36 +147,34 @@ fn run_aot(
     need_metadata_module: bool,
 ) -> Box<CodegenResults> {
     let new_module = |name: String| {
-        let module: Module<FaerieBackend> = Module::new(
-            FaerieBuilder::new(
-                crate::build_isa(tcx.sess, true),
-                name + ".o",
-                FaerieTrapCollection::Disabled,
-                cranelift_module::default_libcall_names(),
-            )
-            .unwrap(),
-        );
+        let module = crate::backend::make_module(tcx.sess, name);
         assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
         module
     };
 
-    let emit_module = |kind: ModuleKind,
-                       mut module: Module<FaerieBackend>,
-                       debug: Option<DebugContext>| {
+    fn emit_module<B: Backend>(
+        tcx: TyCtxt<'_>,
+        name: String,
+        kind: ModuleKind,
+        mut module: Module<B>,
+        debug: Option<DebugContext>,
+    ) -> CompiledModule
+        where B::Product: Emit + WriteDebugInfo,
+    {
             module.finalize_definitions();
-            let mut artifact = module.finish().artifact;
+            let mut product = module.finish();
 
             if let Some(mut debug) = debug {
-                debug.emit(&mut artifact);
+                debug.emit(&mut product);
             }
 
             let tmp_file = tcx
                 .output_filenames(LOCAL_CRATE)
-                .temp_path(OutputType::Object, Some(&artifact.name));
-            let obj = artifact.emit().unwrap();
+                .temp_path(OutputType::Object, Some(&name));
+            let obj = product.emit();
             std::fs::write(&tmp_file, obj).unwrap();
             CompiledModule {
-                name: artifact.name,
+                name: name,
                 kind,
                 object: Some(tmp_file),
                 bytecode: None,
@@ -184,7 +182,7 @@ fn run_aot(
             }
         };
 
-    let mut faerie_module = new_module("some_file".to_string());
+    let mut module = new_module("some_file".to_string());
 
     let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None
         // macOS debuginfo doesn't work yet (see #303)
@@ -192,14 +190,14 @@ fn run_aot(
     {
         let debug = DebugContext::new(
             tcx,
-            faerie_module.target_config().pointer_type().bytes() as u8,
+            module.target_config().pointer_type().bytes() as u8,
         );
         Some(debug)
     } else {
         None
     };
 
-    codegen_cgus(tcx, &mut faerie_module, &mut debug);
+    codegen_cgus(tcx, &mut module, &mut debug);
 
     tcx.sess.abort_if_errors();
 
@@ -221,17 +219,14 @@ fn run_aot(
                 .as_str()
                 .to_string();
 
-            let mut metadata_artifact = faerie::Artifact::new(
-                crate::build_isa(tcx.sess, true).triple().clone(),
-                metadata_cgu_name.clone(),
-            );
-            crate::metadata::write_metadata(tcx, &mut metadata_artifact);
-
             let tmp_file = tcx
                 .output_filenames(LOCAL_CRATE)
                 .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
 
-            let obj = metadata_artifact.emit().unwrap();
+            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
+                crate::metadata::write_metadata(tcx, object);
+            });
+
             std::fs::write(&tmp_file, obj).unwrap();
 
             (metadata_cgu_name, tmp_file)
@@ -251,12 +246,16 @@ fn run_aot(
     Box::new(CodegenResults {
         crate_name: tcx.crate_name(LOCAL_CRATE),
         modules: vec![emit_module(
+            tcx,
+            "some_file".to_string(),
             ModuleKind::Regular,
-            faerie_module,
+            module,
             debug,
         )],
         allocator_module: if created_alloc_shim {
             Some(emit_module(
+                tcx,
+                "allocator_shim".to_string(),
                 ModuleKind::Allocator,
                 allocator_module,
                 None,
diff --git a/src/lib.rs b/src/lib.rs
index 7e68f10ede0..169397f14a5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_private, never_type, decl_macro)]
+#![feature(rustc_private, never_type, decl_macro, type_alias_impl_trait, associated_type_bounds)]
 #![allow(intra_doc_link_resolution_failure)]
 
 extern crate flate2;