diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index d1c2f3104d072..154eb684f1197 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -1,19 +1,28 @@
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ForeignModule;
 
-pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
-    let mut modules = Vec::new();
+pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> FxIndexMap<DefId, ForeignModule> {
+    let mut modules = FxIndexMap::default();
+
+    // We need to collect all the `ForeignMod`, even if they are empty.
     for id in tcx.hir().items() {
         if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
             continue;
         }
+
+        let def_id = id.owner_id.to_def_id();
         let item = tcx.hir().item(id);
-        if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
+
+        if let hir::ItemKind::ForeignMod { abi, items } = item.kind {
             let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
-            modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
+            modules.insert(def_id, ForeignModule { def_id, abi, foreign_items });
         }
     }
+
     modules
 }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 9e0bf81d58dc8..ca5043cc26339 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,15 +1,17 @@
 use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_session::config::CrateType;
-use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
+use rustc_session::cstore::{
+    DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
+};
 use rustc_session::parse::feature_err;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -66,10 +68,12 @@ fn find_bundled_library(
     None
 }
 
-pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
+pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
-    for id in tcx.hir().items() {
-        collector.process_item(id);
+    if tcx.sess.opts.unstable_opts.link_directives {
+        for module in tcx.foreign_modules(LOCAL_CRATE).values() {
+            collector.process_module(module);
+        }
     }
     collector.process_command_line();
     collector.libs
@@ -88,29 +92,20 @@ struct Collector<'tcx> {
 }
 
 impl<'tcx> Collector<'tcx> {
-    fn process_item(&mut self, id: rustc_hir::ItemId) {
-        if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
-            return;
-        }
+    fn process_module(&mut self, module: &ForeignModule) {
+        let ForeignModule { def_id, abi, ref foreign_items } = *module;
+        let def_id = def_id.expect_local();
 
-        let it = self.tcx.hir().item(id);
-        let hir::ItemKind::ForeignMod { abi, items: foreign_mod_items } = it.kind else {
-            return;
-        };
+        let sess = self.tcx.sess;
 
         if matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) {
             return;
         }
 
         // Process all of the #[link(..)]-style arguments
-        let sess = self.tcx.sess;
         let features = self.tcx.features();
 
-        if !sess.opts.unstable_opts.link_directives {
-            return;
-        }
-
-        for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
+        for m in self.tcx.get_attrs(def_id, sym::link) {
             let Some(items) = m.meta_item_list() else {
                 continue;
             };
@@ -340,9 +335,9 @@ impl<'tcx> Collector<'tcx> {
                     if name.as_str().contains('\0') {
                         sess.emit_err(errors::RawDylibNoNul { span: name_span });
                     }
-                    foreign_mod_items
+                    foreign_items
                         .iter()
-                        .map(|child_item| {
+                        .map(|&child_item| {
                             self.build_dll_import(
                                 abi,
                                 import_name_type.map(|(import_name_type, _)| import_name_type),
@@ -352,21 +347,12 @@ impl<'tcx> Collector<'tcx> {
                         .collect()
                 }
                 _ => {
-                    for child_item in foreign_mod_items {
-                        if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
-                            && self
-                                .tcx
-                                .codegen_fn_attrs(child_item.id.owner_id)
-                                .link_ordinal
-                                .is_some()
+                    for &child_item in foreign_items {
+                        if self.tcx.def_kind(child_item).has_codegen_attrs()
+                            && self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
                         {
-                            let link_ordinal_attr = self
-                                .tcx
-                                .hir()
-                                .attrs(child_item.id.owner_id.into())
-                                .iter()
-                                .find(|a| a.has_name(sym::link_ordinal))
-                                .unwrap();
+                            let link_ordinal_attr =
+                                self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
                             sess.emit_err(errors::LinkOrdinalRawDylib {
                                 span: link_ordinal_attr.span,
                             });
@@ -384,7 +370,7 @@ impl<'tcx> Collector<'tcx> {
                 filename,
                 kind,
                 cfg,
-                foreign_module: Some(it.owner_id.to_def_id()),
+                foreign_module: Some(def_id.to_def_id()),
                 verbatim,
                 dll_imports,
             });
@@ -476,10 +462,10 @@ impl<'tcx> Collector<'tcx> {
         }
     }
 
-    fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
+    fn i686_arg_list_size(&self, item: DefId) -> usize {
         let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
             self.tcx
-                .type_of(item.id.owner_id)
+                .type_of(item)
                 .instantiate_identity()
                 .fn_sig(self.tcx)
                 .inputs()
@@ -505,8 +491,10 @@ impl<'tcx> Collector<'tcx> {
         &self,
         abi: Abi,
         import_name_type: Option<PeImportNameType>,
-        item: &hir::ForeignItemRef,
+        item: DefId,
     ) -> DllImport {
+        let span = self.tcx.def_span(item);
+
         let calling_convention = if self.tcx.sess.target.arch == "x86" {
             match abi {
                 Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
@@ -520,29 +508,29 @@ impl<'tcx> Collector<'tcx> {
                     DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
                 }
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span });
                 }
             }
         };
 
-        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
+        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
         let import_name_type = codegen_fn_attrs
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
 
         DllImport {
-            name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name),
+            name: codegen_fn_attrs.link_name.unwrap_or(self.tcx.item_name(item)),
             import_name_type,
             calling_convention,
-            span: item.span,
-            is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
+            span,
+            is_fn: self.tcx.def_kind(item).is_fn_like(),
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 848535fb39521..a8815ee0908d6 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -403,10 +403,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         .contains(&id)
                 })
         },
-        native_libraries: |tcx, LocalCrate| native_libs::collect(tcx),
-        foreign_modules: |tcx, LocalCrate| {
-            foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
-        },
+        native_libraries: native_libs::collect,
+        foreign_modules: foreign_modules::collect,
 
         // Returns a map from a sufficiently visible external item (i.e., an
         // external item that is visible from at least one local module) to a
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 45fa82ba68ad5..a8c0751e1f9f0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1579,7 +1579,7 @@ rustc_queries! {
     }
 
     /// Returns a list of all `extern` blocks of a crate.
-    query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
+    query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> {
         arena_cache
         desc { "looking up the foreign modules of a linked crate" }
         separate_provide_extern
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index dc475e8c6d57c..c53a355b533ea 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -13,6 +13,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 use rustc_target::spec::Target;
 
 use std::any::Any;
@@ -147,6 +148,7 @@ pub enum DllCallingConvention {
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
+    pub abi: Abi,
 }
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
index 5101084054882..dfd24566953fb 100644
--- a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -2,7 +2,7 @@ error: multiple declarations of external function `f` from library `foo.dll` hav
   --> $DIR/multiple-declarations.rs:13:9
    |
 LL |         fn f(x: i32);
-   |         ^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
index f8265ae691948..f69275a01253f 100644
--- a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
+++ b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
@@ -2,7 +2,7 @@ error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
   --> $DIR/unsupported-abi.rs:6:5
    |
 LL |     fn f(x: i32);
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error