diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 42ba40692b75c..cc82a4c9e8e74 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -6,6 +6,7 @@ use smallvec::{SmallVec, smallvec};
 
 fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     target_features::retpoline_features_by_flags(sess, features);
+    target_features::sls_features_by_flags(sess, features);
     // FIXME: LLVM also sets +reserve-x18 here under some conditions.
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 0fb987bdf82ed..d120951382784 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -633,6 +633,7 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
 /// The target features for compiler flags other than `-Ctarget-features`.
 fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     target_features::retpoline_features_by_flags(sess, features);
+    target_features::sls_features_by_flags(sess, features);
 
     // -Zfixed-x18
     if sess.opts.unstable_opts.fixed_x18 {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 53df99993f06b..4dec403306d6f 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -7,6 +7,7 @@ use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_session::config::HardenSls;
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
@@ -400,6 +401,18 @@ pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
     }
 }
 
+pub fn sls_features_by_flags(sess: &Session, features: &mut Vec<String>) {
+    match &sess.opts.unstable_opts.harden_sls {
+        HardenSls::None => (),
+        HardenSls::All => {
+            features.push("+harden-sls-ijmp".into());
+            features.push("+harden-sls-ret".into());
+        }
+        HardenSls::Return => features.push("+harden-sls-ret".into()),
+        HardenSls::IndirectJmp => features.push("+harden-sls-ijmp".into()),
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index a91e2140fd44e..3d79c2a97496f 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3172,11 +3172,11 @@ pub(crate) mod dep_tracking {
     use super::{
         AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
         CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
-        InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
-        LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName,
-        OutputType, OutputTypes, PatchableFunctionEntry, Polonius, RemapPathScopeComponents,
-        ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath,
-        SymbolManglingVersion, WasiExecModel,
+        HardenSls, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto,
+        LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel,
+        OutFileName, OutputType, OutputTypes, PatchableFunctionEntry, Polonius,
+        RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
+        SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
     };
     use crate::lint;
     use crate::utils::NativeLib;
@@ -3278,6 +3278,7 @@ pub(crate) mod dep_tracking {
         Polonius,
         InliningThreshold,
         FunctionReturn,
+        HardenSls,
         Align,
     );
 
@@ -3532,6 +3533,16 @@ pub enum FunctionReturn {
     ThunkExtern,
 }
 
+/// The different settings that the `-Zharden-sls` flag can have.
+#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
+pub enum HardenSls {
+    #[default]
+    None,
+    All,
+    Return,
+    IndirectJmp,
+}
+
 /// Whether extra span comments are included when dumping MIR, via the `-Z mir-include-spans` flag.
 /// By default, only enabled in the NLL MIR dumps, and disabled in all other passes.
 #[derive(Clone, Copy, Default, PartialEq, Debug)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 626262c844257..0bbc2291d6522 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -808,6 +808,7 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
     pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
     pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
+    pub(crate) const parse_harden_sls: &str = "`none`, `all`, `return` or `indirect-jmp`";
     pub(crate) const parse_wasm_c_abi: &str = "`spec`";
     pub(crate) const parse_mir_include_spans: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
@@ -1917,6 +1918,17 @@ pub mod parse {
         true
     }
 
+    pub(crate) fn parse_harden_sls(slot: &mut HardenSls, v: Option<&str>) -> bool {
+        match v {
+            Some("none") => *slot = HardenSls::None,
+            Some("all") => *slot = HardenSls::All,
+            Some("return") => *slot = HardenSls::Return,
+            Some("indirect-jmp") => *slot = HardenSls::IndirectJmp,
+            _ => return false,
+        }
+        true
+    }
+
     pub(crate) fn parse_wasm_c_abi(_slot: &mut (), v: Option<&str>) -> bool {
         v == Some("spec")
     }
@@ -2254,6 +2266,9 @@ options! {
     graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
         "use the given `fontname` in graphviz output; can be overridden by setting \
         environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
+    harden_sls: HardenSls = (HardenSls::None, parse_harden_sls, [TRACKED TARGET_MODIFIER],
+        "flag to mitigate against straight line speculation (SLS) [none|all|return|indirect-jmp] \
+        (default: none)"),
     has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "explicitly enable the `cfg(target_thread_local)` directive"),
     hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index b2af99228fe6d..fdf35bd001ccd 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -433,6 +433,16 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("fma", Stable, &["avx"]),
     ("fxsr", Stable, &[]),
     ("gfni", Stable, &["sse2"]),
+    (
+        "harden-sls-ijmp",
+        Stability::Forbidden { reason: "use `harden-sls` compiler flag instead" },
+        &[],
+    ),
+    (
+        "harden-sls-ret",
+        Stability::Forbidden { reason: "use `harden-sls` compiler flag instead" },
+        &[],
+    ),
     ("kl", Stable, &["sse2"]),
     ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
     ("lzcnt", Stable, &[]),
diff --git a/tests/codegen/harden-sls.rs b/tests/codegen/harden-sls.rs
new file mode 100644
index 0000000000000..76ca2ab702af5
--- /dev/null
+++ b/tests/codegen/harden-sls.rs
@@ -0,0 +1,35 @@
+// ignore-tidy-linelength
+// Test that the `harden-sls-ijmp`, `harden-sls-ret` target features is (not) emitted when
+// the `harden-sls=[none|all|return|indirect-jmp]` flag is (not) set.
+
+//@ add-core-stubs
+//@ revisions: none all return indirect_jmp
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [none] compile-flags: -Zharden-sls=none
+//@ [all] compile-flags: -Zharden-sls=all
+//@ [return] compile-flags: -Zharden-sls=return
+//@ [indirect_jmp] compile-flags: -Zharden-sls=indirect-jmp
+
+#![crate_type = "lib"]
+#![feature(no_core)]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // none-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
+    // none-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
+
+    // all: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp,+harden-sls-ret{{.*}} }
+
+    // return-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
+    // return: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
+
+    // indirect_jmp-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ret{{.*}} }
+    // indirect_jmp: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+harden-sls-ijmp{{.*}} }
+}
diff --git a/tests/ui/target-feature/harden-sls-target-feature-flag.by_feature.stderr b/tests/ui/target-feature/harden-sls-target-feature-flag.by_feature.stderr
new file mode 100644
index 0000000000000..71a23f8fc6af8
--- /dev/null
+++ b/tests/ui/target-feature/harden-sls-target-feature-flag.by_feature.stderr
@@ -0,0 +1,12 @@
+warning: target feature `harden-sls-ijmp` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
+   |
+   = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: target feature `harden-sls-ret` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
+   |
+   = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/target-feature/harden-sls-target-feature-flag.rs b/tests/ui/target-feature/harden-sls-target-feature-flag.rs
new file mode 100644
index 0000000000000..d8f855317323f
--- /dev/null
+++ b/tests/ui/target-feature/harden-sls-target-feature-flag.rs
@@ -0,0 +1,15 @@
+//@ add-core-stubs
+//@ revisions: by_flag by_feature
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
+//@ needs-llvm-components: x86
+//@ [by_flag]compile-flags: -Zharden-sls=all
+//@ [by_feature]compile-flags: -Ctarget-feature=+harden-sls-ijmp,+harden-sls-ret
+//@ [by_flag]build-pass
+// For now this is just a warning.
+//@ [by_feature]build-pass
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+
+//[by_feature]~? WARN target feature `harden-sls-ijmp` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead
+//[by_feature]~? WARN target feature `harden-sls-ret` cannot be enabled with `-Ctarget-feature`: use `harden-sls` compiler flag instead