diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 3522ea0115334..90520f77e3c04 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -15,6 +15,7 @@ use rustc_session::{
 };
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::Target;
 
 pub use rustc_data_structures::sync::MetadataRef;
 
@@ -54,6 +55,12 @@ pub trait CodegenBackend {
     fn print_passes(&self) {}
     fn print_version(&self) {}
 
+    /// If this plugin provides additional builtin targets, provide the one enabled by the options here.
+    /// Be careful: this is called *before* init() is called.
+    fn target_override(&self, _opts: &config::Options) -> Option<Target> {
+        None
+    }
+
     fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
     fn provide(&self, _providers: &mut Providers);
     fn provide_extern(&self, _providers: &mut Providers);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index dc4fa807f7868..72e10bc4304d0 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
         DiagnosticOutput::Default,
         Default::default(),
         None,
+        None,
     );
     (sess, cfg)
 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f15eb413833ae..0eed6938c3169 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -65,6 +65,10 @@ pub fn create_session(
     lint_caps: FxHashMap<lint::LintId, lint::Level>,
     descriptions: Registry,
 ) -> (Lrc<Session>, Lrc<Box<dyn CodegenBackend>>) {
+    let codegen_backend = get_codegen_backend(&sopts);
+    // target_override is documented to be called before init(), so this is okay
+    let target_override = codegen_backend.target_override(&sopts);
+
     let mut sess = session::build_session(
         sopts,
         input_path,
@@ -72,9 +76,10 @@ pub fn create_session(
         diagnostic_output,
         lint_caps,
         file_loader,
+        target_override,
     );
 
-    let codegen_backend = get_codegen_backend(&sess);
+    codegen_backend.init(&sess);
 
     let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
     add_configuration(&mut cfg, &mut sess, &*codegen_backend);
@@ -219,13 +224,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
     }
 }
 
-pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
+pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
     static INIT: Once = Once::new();
 
     static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
 
     INIT.call_once(|| {
-        let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
+        let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
         let backend = match codegen_name {
             filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
             codegen_name => get_builtin_codegen_backend(codegen_name),
@@ -235,9 +240,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
             LOAD = backend;
         }
     });
-    let backend = unsafe { LOAD() };
-    backend.init(sess);
-    backend
+    unsafe { LOAD() }
 }
 
 // This is used for rustdoc, but it uses similar machinery to codegen backend
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 3f12596a236ab..8d004675d7f4d 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -818,10 +818,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
     user_cfg
 }
 
-pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
-    let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
+pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config {
+    let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
+    let target = target_result.unwrap_or_else(|e| {
         early_error(
-            error_format,
+            opts.error_format,
             &format!(
                 "Error loading target specification: {}. \
             Use `--print target-list` for a list of built-in targets",
@@ -835,7 +836,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con
         "32" => 32,
         "64" => 64,
         w => early_error(
-            error_format,
+            opts.error_format,
             &format!(
                 "target specification was invalid: \
              unrecognized target-pointer-width {}",
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 974f4c31bb6a4..ff67d3cb107d9 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1234,6 +1234,7 @@ pub fn build_session(
     diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
+    target_override: Option<Target>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
     // normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -1253,7 +1254,7 @@ pub fn build_session(
         DiagnosticOutput::Raw(write) => Some(write),
     };
 
-    let target_cfg = config::build_target_config(&sopts, sopts.error_format);
+    let target_cfg = config::build_target_config(&sopts, target_override);
     let host_triple = TargetTriple::from_triple(config::host_triple());
     let host = Target::search(&host_triple).unwrap_or_else(|e| {
         early_error(sopts.error_format, &format!("Error loading host specification: {}", e))