diff a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java
@@ -1,7 +1,8 @@
 /*
  * Copyright (c) 2024, Red Hat, Inc.
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
@@ -30,11 +31,10 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.MessageDigest;
@@ -49,10 +49,12 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import jdk.internal.jimage.ResourceEntries;
+import jdk.internal.jimage.SystemImageReader;
 import jdk.internal.util.OperatingSystem;
 import jdk.tools.jlink.internal.Archive.Entry.EntryType;
 import jdk.tools.jlink.internal.runtimelink.ResourceDiff;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
 import jdk.tools.jlink.plugin.ResourcePoolEntry.Type;
@@ -61,14 +63,13 @@
  * An archive implementation based on the JDK's run-time image. That is, classes
  * and resources from the modules image (lib/modules, or jimage) and other
  * associated files from the filesystem of the JDK installation.
  */
 public class JRTArchive implements Archive {
-
     private final String module;
     private final Path path;
-    private final ModuleReference ref;
+    private final ResourceEntries imageResources;
     // The collection of files of this module
     private final List<JRTFile> files = new ArrayList<>();
     // Files not part of the lib/modules image of the JDK install.
     // Thus, native libraries, binaries, legal files, etc.
     private final List<String> otherRes;
@@ -97,16 +98,15 @@
                List<ResourceDiff> perModDiff,
                TaskHelper taskHelper,
                Set<String> upgradeableFiles) {
         this.module = module;
         this.path = path;
-        this.ref = ModuleFinder.ofSystem()
-                               .find(module)
-                               .orElseThrow(() ->
-                                    new IllegalArgumentException(
-                                            "Module " + module +
-                                            " not part of the JDK install"));
+        ModuleFinder.ofSystem()
+                .find(module)
+                .orElseThrow(() -> new IllegalArgumentException(
+                        "Module " + module + " not part of the JDK install"));
+        this.imageResources = SystemImageReader.getResourceEntries();
         this.errorOnModifiedFile = errorOnModifiedFile;
         this.otherRes = readModuleResourceFile(module);
         this.resDiff = Objects.requireNonNull(perModDiff).stream()
                             .collect(Collectors.toMap(ResourceDiff::getName, Function.identity()));
         this.taskHelper = taskHelper;
@@ -157,56 +157,39 @@
         return (obj instanceof JRTArchive other &&
                    Objects.equals(module, other.module) &&
                    Objects.equals(path, other.path));
     }
 
+    private boolean isNormalOrModifiedDiff(String name) {
+        ResourceDiff rd = resDiff.get(name);
+        // Filter all resources with a resource diff of kind MODIFIED.
+        // Note that REMOVED won't happen since in that case the module listing
+        // won't have the resource anyway.
+        // Note as well that filter removes files of kind ADDED. Those files are
+        // not in the packaged modules, so ought not to get returned from the
+        // pipeline.
+        return (rd == null || rd.getKind() == ResourceDiff.Kind.MODIFIED);
+    }
+
     private void collectFiles() throws IOException {
         if (files.isEmpty()) {
             addNonClassResources();
+
             // Add classes/resources from the run-time image,
             // patched with the run-time image diff
-            files.addAll(ref.open().list()
-                                   .filter(i -> {
-                                           String lookupKey = String.format("/%s/%s", module, i);
-                                           ResourceDiff rd = resDiff.get(lookupKey);
-                                           // Filter all resources with a resource diff
-                                           // that are of kind MODIFIED.
-                                           // Note that REMOVED won't happen since in
-                                           // that case the module listing won't have
-                                           // the resource anyway.
-                                           // Note as well that filter removes files
-                                           // of kind ADDED. Those files are not in
-                                           // the packaged modules, so ought not to
-                                           // get returned from the pipeline.
-                                           return (rd == null ||
-                                                   rd.getKind() == ResourceDiff.Kind.MODIFIED);
-                                   })
-                                   .map(s -> {
-                                           String lookupKey = String.format("/%s/%s", module, s);
-                                           return new JRTArchiveFile(JRTArchive.this, s,
-                                                           EntryType.CLASS_OR_RESOURCE,
-                                                           null /* hashOrTarget */,
-                                                           false /* symlink */,
-                                                           resDiff.get(lookupKey));
-                                   })
-                                   .toList());
+            imageResources.getEntryNames(module)
+                    .filter(this::isNormalOrModifiedDiff)
+                    .sorted()
+                    .map(name -> new JrtModuleFile(this, name, resDiff.get(name)))
+                    .forEach(files::add);
+
             // Finally add all files only present in the resource diff
             // That is, removed items in the run-time image.
             files.addAll(resDiff.values().stream()
-                                         .filter(rd -> rd.getKind() == ResourceDiff.Kind.REMOVED)
-                                         .map(s -> {
-                                                 int secondSlash = s.getName().indexOf("/", 1);
-                                                 assert secondSlash != -1;
-                                                 String pathWithoutModule = s.getName().substring(secondSlash + 1);
-                                                 return new JRTArchiveFile(JRTArchive.this,
-                                                         pathWithoutModule,
-                                                         EntryType.CLASS_OR_RESOURCE,
-                                                         null  /* hashOrTarget */,
-                                                         false /* symlink */,
-                                                         s);
-                                         })
-                                         .toList());
+                    .filter(rd -> rd.getKind() == ResourceDiff.Kind.REMOVED)
+                    .map(rd -> new JrtModuleFile(this, rd.getName(), rd))
+                    .toList());
         }
     }
 
     /*
      * no need to keep track of the warning produced since this is eagerly
@@ -232,19 +215,14 @@
                             } else {
                                 taskHelper.warning("err.runtime.link.modified.file", path.toString());
                             }
                         }
 
-                        return new JRTArchiveFile(JRTArchive.this,
-                                                  m.resPath,
-                                                  toEntryType(m.resType),
-                                                  m.hashOrTarget,
-                                                  m.symlink,
-                                                  /* diff only for resources */
-                                                  null);
-                 })
-                 .toList());
+                        return new JrtOtherFile(
+                                this, m.resPath, toEntryType(m.resType), m.hashOrTarget, m.symlink);
+                    })
+                    .toList());
         }
     }
 
     /**
      * Certain files in a module are considered upgradeable. That is,
@@ -321,15 +299,15 @@
                                  symlink ? 1 : 0,
                                  hashOrTarget,
                                  resPath);
         }
 
-        /**
+        /*
          *  line: <int>|<int>|<hashOrTarget>|<path>
          *
-         *  Take the integer before '|' convert it to a Type. The second
-         *  token is an integer representing symlinks (or not). The third token is
+         *  Take the integer before '|' convert it to a Type. The second token
+         *  is an integer representing symlinks (or not). The third token is
          *  a hash sum (sha512) of the file denoted by the fourth token (path).
          */
         static ResourceFileEntry decodeFromString(String line) {
             assert !line.isEmpty();
 
@@ -435,80 +413,88 @@
 
     interface JRTFile {
         Entry toEntry();
     }
 
-    record JRTArchiveFile(Archive archive,
-                          String resPath,
-                          EntryType resType,
-                          String sha,
-                          boolean symlink,
-                          ResourceDiff diff) implements JRTFile {
+    record JrtModuleFile(
+            JRTArchive archive,
+            String resPath,
+            ResourceDiff diff) implements JRTFile {
+        @Override
+        public Entry toEntry() {
+            assert resPath.startsWith("/" + archive.moduleName() + "/");
+            String resName = resPath.substring(archive.moduleName().length() + 2);
+
+            // If the resource has a diff to the packaged modules, use the diff.
+            // Diffs of kind ADDED have been filtered out in collectFiles();
+            if (diff != null) {
+                assert diff.getKind() != ResourceDiff.Kind.ADDED;
+                assert diff.getName().equals(resPath);
+
+                return new Entry(archive, resPath, resName, EntryType.CLASS_OR_RESOURCE) {
+                    @Override
+                    public long size() {
+                        return diff.getResourceBytes().length;
+                    }
+                    @Override
+                    public InputStream stream() {
+                        return new ByteArrayInputStream(diff.getResourceBytes());
+                    }
+                };
+            } else {
+                return new Entry(archive, resPath, resName, EntryType.CLASS_OR_RESOURCE) {
+                    @Override
+                    public long size() {
+                        return archive.imageResources.getSize(resPath);
+                    }
+
+                    @Override
+                    public InputStream stream() {
+                        // Byte content could be cached in the entry if needed.
+                        return new ByteArrayInputStream(archive.imageResources.getBytes(resPath));
+                    }
+                };
+            }
+        }
+    }
+
+    record JrtOtherFile(
+            JRTArchive archive,
+            String resPath,
+            EntryType resType,
+            String sha,
+            boolean symlink) implements JRTFile {
+
+        // Read from the base JDK image, special casing
+        // symlinks, which have the link target in the
+        // hashOrTarget field.
+        Path targetPath() {
+            return BASE.resolve(symlink ? sha : resPath);
+        }
+
         public Entry toEntry() {
-            return new Entry(archive,
-                             String.format("/%s/%s",
-                                           archive.moduleName(),
-                                           resPath),
-                             resPath,
-                             resType) {
+            assert resType != EntryType.CLASS_OR_RESOURCE;
+
+            return new Entry(
+                    archive,
+                    String.format("/%s/%s", archive.moduleName(), resPath),
+                    resPath,
+                    resType) {
+
                 @Override
                 public long size() {
                     try {
-                        if (resType != EntryType.CLASS_OR_RESOURCE) {
-                            // Read from the base JDK image, special casing
-                            // symlinks, which have the link target in the
-                            // hashOrTarget field
-                            if (symlink) {
-                                return Files.size(BASE.resolve(sha));
-                            }
-                            return Files.size(BASE.resolve(resPath));
-                        } else {
-                            if (diff != null) {
-                                // If the resource has a diff to the
-                                // packaged modules, use the diff. Diffs of kind
-                                // ADDED have been filtered out in collectFiles();
-                                assert diff.getKind() != ResourceDiff.Kind.ADDED;
-                                assert diff.getName().equals(String.format("/%s/%s",
-                                                                           archive.moduleName(),
-                                                                           resPath));
-                                return diff.getResourceBytes().length;
-                            }
-                            // Read from the module image. This works, because
-                            // the underlying base path is a JrtPath with the
-                            // JrtFileSystem underneath which is able to handle
-                            // this size query.
-                            return Files.size(archive.getPath().resolve(resPath));
-                        }
+                        return Files.size(targetPath());
                     } catch (IOException e) {
                         throw new UncheckedIOException(e);
                     }
                 }
 
                 @Override
                 public InputStream stream() throws IOException {
-                    if (resType != EntryType.CLASS_OR_RESOURCE) {
-                        // Read from the base JDK image.
-                        Path path = symlink ? BASE.resolve(sha) : BASE.resolve(resPath);
-                        return Files.newInputStream(path);
-                    } else {
-                        // Read from the module image. Use the diff to the
-                        // packaged modules if we have one. Diffs of kind
-                        // ADDED have been filtered out in collectFiles();
-                        if (diff != null) {
-                            assert diff.getKind() != ResourceDiff.Kind.ADDED;
-                            assert diff.getName().equals(String.format("/%s/%s",
-                                                                       archive.moduleName(),
-                                                                       resPath));
-                            return new ByteArrayInputStream(diff.getResourceBytes());
-                        }
-                        String module = archive.moduleName();
-                        ModuleReference mRef = ModuleFinder.ofSystem()
-                                                    .find(module).orElseThrow();
-                        return mRef.open().open(resPath).orElseThrow();
-                    }
+                    return Files.newInputStream(targetPath());
                 }
-
             };
         }
     }
 
     private static List<String> readModuleResourceFile(String modName) {
