diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 4d19425255faf..e8143b9a5f38f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
 use std::ffi::OsString;
 use std::fs::{read, File, OpenOptions};
 use std::io::{BufWriter, Write};
-use std::ops::Deref;
+use std::ops::{ControlFlow, Deref};
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{env, fmt, fs, io, mem, str};
@@ -18,8 +18,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_metadata::find_native_static_library;
 use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
+use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
 use rustc_middle::bug;
 use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::dependency_format::Linkage;
@@ -2110,50 +2110,19 @@ fn add_library_search_dirs(
         return;
     }
 
-    // Library search paths explicitly supplied by user (`-L` on the command line).
-    for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
-        cmd.include_path(&fix_windows_verbatim_for_gcc(&search_path.dir));
-    }
-    for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
-        // Contrary to the `-L` docs only framework-specific paths are considered here.
-        if search_path.kind != PathKind::All {
-            cmd.framework_path(&search_path.dir);
-        }
-    }
-
-    // The toolchain ships some native library components and self-contained linking was enabled.
-    // Add the self-contained library directory to search paths.
-    if self_contained_components.intersects(
-        LinkSelfContainedComponents::LIBC
-            | LinkSelfContainedComponents::UNWIND
-            | LinkSelfContainedComponents::MINGW,
-    ) {
-        let lib_path = sess.target_tlib_path.dir.join("self-contained");
-        cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
-    }
-
-    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
-    // library directory instead of the self-contained directories.
-    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
-    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
-    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
-    // and sanitizers to self-contained directory, and stop adding this search path.
-    if sess.target.vendor == "fortanix"
-        || sess.target.os == "linux"
-        || sess.target.os == "fuchsia"
-        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
-    {
-        cmd.include_path(&fix_windows_verbatim_for_gcc(&sess.target_tlib_path.dir));
-    }
-
-    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
-    // we must have the support library stubs in the library search path (#121430).
-    if let Some(sdk_root) = apple_sdk_root
-        && sess.target.llvm_target.contains("macabi")
-    {
-        cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib"));
-        cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"));
-    }
+    walk_native_lib_search_dirs(
+        sess,
+        self_contained_components,
+        apple_sdk_root,
+        |dir, is_framework| {
+            if is_framework {
+                cmd.framework_path(dir);
+            } else {
+                cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
+            }
+            ControlFlow::<()>::Continue(())
+        },
+    );
 }
 
 /// Add options making relocation sections in the produced ELF files read-only
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index fbab988a32b08..cb266247e0dde 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -7,7 +7,7 @@ use std::{env, iter, mem, str};
 
 use cc::windows_registry;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_metadata::find_native_static_library;
+use rustc_metadata::{find_native_static_library, try_find_native_static_library};
 use rustc_middle::bug;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols;
@@ -891,9 +891,15 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) {
-        let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
-        let suffix = if verbatim { "" } else { ".lib" };
-        self.link_arg(format!("{prefix}{name}{suffix}"));
+        // On MSVC-like targets rustc supports static libraries using alternative naming
+        // scheme (`libfoo.a`) unsupported by linker, search for such libraries manually.
+        if let Some(path) = try_find_native_static_library(self.sess, name, verbatim) {
+            self.link_staticlib_by_path(&path, whole_archive);
+        } else {
+            let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
+            let suffix = if verbatim { "" } else { ".lib" };
+            self.link_arg(format!("{prefix}{name}{suffix}"));
+        }
     }
 
     fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index acaf9fb0fc32a..d530a7cd9d4bc 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -3,6 +3,7 @@
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(control_flow_enum)]
 #![feature(coroutines)]
 #![feature(decl_macro)]
 #![feature(error_iter)]
@@ -34,7 +35,9 @@ pub mod locator;
 
 pub use creader::{load_symbol_from_dylib, DylibError};
 pub use fs::{emit_wrapper_file, METADATA_FILENAME};
-pub use native_libs::find_native_static_library;
+pub use native_libs::{
+    find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs,
+};
 pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 34497f5ac53f8..a6ad449cb53e8 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,4 +1,5 @@
-use std::path::PathBuf;
+use std::ops::ControlFlow;
+use std::path::{Path, PathBuf};
 
 use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
@@ -16,10 +17,68 @@ use rustc_session::Session;
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
+use rustc_target::spec::LinkSelfContainedComponents;
 
 use crate::{errors, fluent_generated};
 
-pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
+pub fn walk_native_lib_search_dirs<R>(
+    sess: &Session,
+    self_contained_components: LinkSelfContainedComponents,
+    apple_sdk_root: Option<&Path>,
+    mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
+) -> ControlFlow<R> {
+    // Library search paths explicitly supplied by user (`-L` on the command line).
+    for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
+        f(&search_path.dir, false)?;
+    }
+    for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
+        // Frameworks are looked up strictly in framework-specific paths.
+        if search_path.kind != PathKind::All {
+            f(&search_path.dir, true)?;
+        }
+    }
+
+    // The toolchain ships some native library components and self-contained linking was enabled.
+    // Add the self-contained library directory to search paths.
+    if self_contained_components.intersects(
+        LinkSelfContainedComponents::LIBC
+            | LinkSelfContainedComponents::UNWIND
+            | LinkSelfContainedComponents::MINGW,
+    ) {
+        f(&sess.target_tlib_path.dir.join("self-contained"), false)?;
+    }
+
+    // Toolchains for some targets may ship `libunwind.a`, but place it into the main sysroot
+    // library directory instead of the self-contained directories.
+    // Sanitizer libraries have the same issue and are also linked by name on Apple targets.
+    // The targets here should be in sync with `copy_third_party_objects` in bootstrap.
+    // FIXME: implement `-Clink-self-contained=+/-unwind,+/-sanitizers`, move the shipped libunwind
+    // and sanitizers to self-contained directory, and stop adding this search path.
+    if sess.target.vendor == "fortanix"
+        || sess.target.os == "linux"
+        || sess.target.os == "fuchsia"
+        || sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
+    {
+        f(&sess.target_tlib_path.dir, false)?;
+    }
+
+    // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
+    // we must have the support library stubs in the library search path (#121430).
+    if let Some(sdk_root) = apple_sdk_root
+        && sess.target.llvm_target.contains("macabi")
+    {
+        f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
+        f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
+    }
+
+    ControlFlow::Continue(())
+}
+
+pub fn try_find_native_static_library(
+    sess: &Session,
+    name: &str,
+    verbatim: bool,
+) -> Option<PathBuf> {
     let formats = if verbatim {
         vec![("".into(), "".into())]
     } else {
@@ -30,16 +89,29 @@ pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) ->
         if os == unix { vec![os] } else { vec![os, unix] }
     };
 
-    for path in sess.target_filesearch(PathKind::Native).search_paths() {
-        for (prefix, suffix) in &formats {
-            let test = path.dir.join(format!("{prefix}{name}{suffix}"));
-            if test.exists() {
-                return test;
+    // FIXME: Account for self-contained linking settings and Apple SDK.
+    walk_native_lib_search_dirs(
+        sess,
+        LinkSelfContainedComponents::empty(),
+        None,
+        |dir, is_framework| {
+            if !is_framework {
+                for (prefix, suffix) in &formats {
+                    let test = dir.join(format!("{prefix}{name}{suffix}"));
+                    if test.exists() {
+                        return ControlFlow::Break(test);
+                    }
+                }
             }
-        }
-    }
+            ControlFlow::Continue(())
+        },
+    )
+    .break_value()
+}
 
-    sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
+pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf {
+    try_find_native_static_library(sess, name, verbatim)
+        .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim)))
 }
 
 fn find_bundled_library(
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index fa23e3e414d90..e5631ba42741a 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -47,7 +47,7 @@ KIND=PATH` where `KIND` may be one of:
   directory.
 - `native` — Only search for native libraries in this directory.
 - `framework` — Only search for macOS frameworks in this directory.
-- `all` — Search for all library kinds in this directory. This is the default
+- `all` — Search for all library kinds in this directory, except frameworks. This is the default
   if `KIND` is not specified.
 
 <a id="option-l-link-lib"></a>
diff --git a/tests/run-make/native-lib-alt-naming/native.rs b/tests/run-make/native-lib-alt-naming/native.rs
new file mode 100644
index 0000000000000..6c869e74cd269
--- /dev/null
+++ b/tests/run-make/native-lib-alt-naming/native.rs
@@ -0,0 +1,2 @@
+#[no_mangle]
+pub extern "C" fn native_lib_alt_naming() {}
diff --git a/tests/run-make/native-lib-alt-naming/rmake.rs b/tests/run-make/native-lib-alt-naming/rmake.rs
new file mode 100644
index 0000000000000..d1ea0fc868767
--- /dev/null
+++ b/tests/run-make/native-lib-alt-naming/rmake.rs
@@ -0,0 +1,15 @@
+// On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
+// to the default format (`foo.lib`).
+
+//REMOVE@ only-msvc
+
+use run_make_support::rustc;
+
+fn main() {
+    // Prepare the native library.
+    rustc().input("native.rs").crate_type("staticlib").output("libnative.a").run();
+
+    // Try to link to it from both a rlib and a bin.
+    rustc().input("rust.rs").crate_type("rlib").arg("-lstatic=native").run();
+    rustc().input("rust.rs").crate_type("bin").arg("-lstatic=native").run();
+}
diff --git a/tests/run-make/native-lib-alt-naming/rust.rs b/tests/run-make/native-lib-alt-naming/rust.rs
new file mode 100644
index 0000000000000..da0f5d925d107
--- /dev/null
+++ b/tests/run-make/native-lib-alt-naming/rust.rs
@@ -0,0 +1 @@
+pub fn main() {}