diff --git a/bin/system-info.c b/bin/system-info.c
index 0a4e8510f7c10ca72c7e8cc94505dcb54214d708..346c0fde7cdfd29bc883375bbf6fea48a933c74c 100644
--- a/bin/system-info.c
+++ b/bin/system-info.c
@@ -1079,6 +1079,7 @@ main (int argc,
       GList *va_api_list = NULL;
       GList *vdpau_list = NULL;
       GList *glx_list = NULL;
+      const char *ld_so;
 
       json_builder_set_member_name (builder, multiarch_tuples[i]);
       json_builder_begin_object (builder);
@@ -1086,6 +1087,34 @@ main (int argc,
       can_run = srt_system_info_can_run (info, multiarch_tuples[i]);
       json_builder_add_boolean_value (builder, can_run);
 
+      ld_so = srt_architecture_get_expected_runtime_linker (multiarch_tuples[i]);
+
+      if (ld_so != NULL)
+        {
+          json_builder_set_member_name (builder, "runtime-linker");
+          json_builder_begin_object (builder);
+            {
+              g_autoptr(GError) local_error = NULL;
+              g_autofree gchar *real = NULL;
+
+              json_builder_set_member_name (builder, "path");
+              json_builder_add_string_value (builder, ld_so);
+
+              if (srt_system_info_check_runtime_linker (info,
+                                                        multiarch_tuples[i],
+                                                        &real, &local_error))
+                {
+                  json_builder_set_member_name (builder, "resolved");
+                  json_builder_add_string_value (builder, real);
+                }
+              else
+                {
+                  _srt_json_builder_add_error_members (builder, local_error);
+                }
+            }
+          json_builder_end_object (builder);
+        }
+
       if (can_run)
         {
           json_builder_set_member_name (builder, "library-issues-summary");
diff --git a/bin/system-info.md b/bin/system-info.md
index 327abf05ad77185facb381226a29b18aa1ca62ab..94e04b7faa8867e3f542e8268bd7a93c60e297f5 100644
--- a/bin/system-info.md
+++ b/bin/system-info.md
@@ -354,6 +354,32 @@ keys:
     :   A boolean value indicating whether a simple executable for this
         architecture was run successfully.
 
+    **runtime-linker**
+    :   If the multiarch tuple is a known one, an object with the
+        following keys and values describing the runtime linker **ld.so**(8):
+
+        **path**
+        :   The path required to run Steam binaries on this architecture,
+            for example `/lib64/ld-linux-x86-64.so.2` on x86_64
+
+        **resolved**
+        :   The result of resolving symbolic links in **path** if possible,
+            for example `/lib/x86_64-linux-gnu/ld-2.28.so` on
+            Debian 10 x86_64
+
+        If the runtime linker is detected to be missing or unusable,
+        details of the error appear here:
+
+        **error-domain**
+        :   A machine-readable string indicating a category of errors.
+
+        **error-code**
+        :   A small integer indicating a specific error. Its meaning depends
+            on the **error-domain**.
+
+        **error**
+        :   A human-readable error message.
+
     **library-issues-summary**
     :   A summary of issues found when loading the expected libraries,
         as an array of strings. If empty, no problems were found.
diff --git a/steam-runtime-tools/architecture-internal.h b/steam-runtime-tools/architecture-internal.h
index 8461ab92408f1553e60ebeee3f27f06e1068f741..e1fb688cbe51c74be76b90c8a1e1aef2d41ae86f 100644
--- a/steam-runtime-tools/architecture-internal.h
+++ b/steam-runtime-tools/architecture-internal.h
@@ -29,6 +29,14 @@
 #include <glib.h>
 #include <json-glib/json-glib.h>
 
+typedef struct
+{
+  const char *multiarch_tuple;
+  const char *interoperable_runtime_linker;
+} SrtKnownArchitecture;
+
+G_GNUC_INTERNAL const SrtKnownArchitecture *_srt_architecture_get_known (void);
+
 G_GNUC_INTERNAL gboolean _srt_architecture_can_run (gchar **envp,
                                                     const char *helpers_path,
                                                     const char *multiarch);
diff --git a/steam-runtime-tools/architecture.c b/steam-runtime-tools/architecture.c
index 5f278b147c09aa49f24887fe5e2a9c0534db3c38..e4a00292fc0a976fd117ae9e02e301100f7fc589 100644
--- a/steam-runtime-tools/architecture.c
+++ b/steam-runtime-tools/architecture.c
@@ -44,6 +44,38 @@
  * operating system.
  */
 
+G_DEFINE_QUARK (srt-architecture-error-quark, srt_architecture_error)
+
+static const SrtKnownArchitecture known_architectures[] =
+{
+    {
+      .multiarch_tuple = SRT_ABI_X86_64,
+      .interoperable_runtime_linker = "/lib64/ld-linux-x86-64.so.2",
+    },
+
+    {
+      .multiarch_tuple = SRT_ABI_I386,
+      .interoperable_runtime_linker = "/lib/ld-linux.so.2",
+    },
+
+    {
+      .multiarch_tuple = "x86_64-linux-gnux32",
+      .interoperable_runtime_linker = "/libx32/ld-linux-x32.so.2",
+    },
+
+    { NULL }
+};
+
+/*
+ * Returns: A table of known architectures, terminated by one
+ *  with @multiarch_tuple set to %NULL.
+ */
+const SrtKnownArchitecture *
+_srt_architecture_get_known (void)
+{
+  return &known_architectures[0];
+}
+
 gboolean
 _srt_architecture_can_run (gchar **envp,
                            const char *helpers_path,
@@ -164,6 +196,35 @@ srt_architecture_can_run_x86_64 (void)
                                     NULL, SRT_ABI_X86_64);
 }
 
+/**
+ * srt_architecture_get_expected_runtime_linker:
+ * @multiarch_tuple: A multiarch tuple defining an ABI, as printed
+ *  by `gcc -print-multiarch` in the Steam Runtime
+ *
+ * Return the interoperable path to the runtime linker `ld.so(8)`,
+ * if known. For example, for x86_64, this returns
+ * `/lib64/ld-linux-x86-64.so.2`.
+ *
+ * Returns: (type filename) (transfer none): An absolute path,
+ *  or %NULL if not known
+ */
+const char *
+srt_architecture_get_expected_runtime_linker (const char *multiarch_tuple)
+{
+  gsize i;
+
+  g_return_val_if_fail (multiarch_tuple != NULL, NULL);
+
+  for (i = 0; known_architectures[i].multiarch_tuple != NULL; i++)
+    {
+      if (strcmp (multiarch_tuple,
+                  known_architectures[i].multiarch_tuple) == 0)
+        return known_architectures[i].interoperable_runtime_linker;
+    }
+
+  return NULL;
+}
+
 /**
  * _srt_architecture_can_run_from_report:
  * @json_obj: (not nullable): A JSON Object used to search for "can-run"
diff --git a/steam-runtime-tools/architecture.h b/steam-runtime-tools/architecture.h
index 178d3567f11693f13bb1c6f835dfe28e97951351..5e6bfa87aad831f1b58776c31d9806176820c81b 100644
--- a/steam-runtime-tools/architecture.h
+++ b/steam-runtime-tools/architecture.h
@@ -53,3 +53,34 @@ _SRT_PUBLIC
 gboolean srt_architecture_can_run_i386 (void);
 _SRT_PUBLIC
 gboolean srt_architecture_can_run_x86_64 (void);
+
+/**
+ * SrtArchitectureError:
+ * @SRT_ARCHITECTURE_ERROR_FAILED: Generic error
+ * @SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR: An internal error occurred
+ * @SRT_ARCHITECTURE_ERROR_NO_INFORMATION: It is unknown whether the
+ *  given architecture, ld.so, etc. is available or not, for example
+ *  because the interoperable ld.so path for the architecture is unknown,
+ *  or because SrtSystemInfo is reading a JSON report that does not
+ *  contain this information
+ *
+ * Errors raised when checking facts about an architecture.
+ *
+ * Errors in the #GIOErrorEnum domain can also be raised: for example,
+ * if srt_system_info_check_runtime_linker() raises %G_IO_ERROR_NOT_FOUND,
+ * it means the interoperable path for ld.so does not exist.
+ */
+typedef enum
+{
+  SRT_ARCHITECTURE_ERROR_FAILED = 0,
+  SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+  SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+} SrtArchitectureError;
+
+_SRT_PUBLIC
+GQuark srt_architecture_error_quark (void);
+
+#define SRT_ARCHITECTURE_ERROR (srt_architecture_error_quark ())
+
+_SRT_PUBLIC
+const char *srt_architecture_get_expected_runtime_linker (const char *multiarch_tuple);
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index c966f37b5862b24f08328fa438469b47fdcec907..a90d0294487f8e862411d1e0c0c4de9658718cd4 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -251,6 +251,9 @@ typedef struct
 typedef struct
 {
   GQuark multiarch_tuple;
+  const SrtKnownArchitecture *known_architecture;
+  gchar *runtime_linker_resolved;
+  GError *runtime_linker_error;
   Tristate can_run;
   GHashTable *cached_results;
   SrtLibraryIssues cached_combined_issues;
@@ -267,6 +270,7 @@ static Abi *
 ensure_abi_unless_immutable (SrtSystemInfo *self,
                              const char *multiarch_tuple)
 {
+  const SrtKnownArchitecture *iter;
   GQuark quark;
   guint i;
   Abi *abi = NULL;
@@ -286,6 +290,18 @@ ensure_abi_unless_immutable (SrtSystemInfo *self,
 
   abi = g_slice_new0 (Abi);
   abi->multiarch_tuple = quark;
+
+  for (iter = _srt_architecture_get_known ();
+       iter->multiarch_tuple != NULL;
+       iter++)
+    {
+      if (strcmp (iter->multiarch_tuple, multiarch_tuple) == 0)
+        {
+          abi->known_architecture = iter;
+          break;
+        }
+    }
+
   abi->can_run = TRI_MAYBE;
   abi->cached_results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
   abi->cached_combined_issues = SRT_LIBRARY_ISSUES_NONE;
@@ -319,6 +335,8 @@ abi_free (gpointer self)
   for (i = 0; i < G_N_ELEMENTS (abi->graphics_modules); i++)
     g_list_free_full (abi->graphics_modules[i].modules, g_object_unref);
 
+  g_free (abi->runtime_linker_resolved);
+  g_clear_error (&abi->runtime_linker_error);
   g_slice_free (Abi, self);
 }
 
@@ -595,6 +613,79 @@ static gchar ** _srt_system_info_get_pinned_libs_from_report (JsonObject *json_o
                                                               const gchar *which,
                                                               gchar ***messages);
 
+static void
+get_runtime_linker_from_report (SrtSystemInfo *self,
+                                Abi *abi,
+                                JsonObject *json_arch_obj)
+{
+  JsonObject *runtime_linker_obj;
+  const char *path;
+  const char *resolved;
+
+  g_return_if_fail (abi->runtime_linker_resolved == NULL);
+  g_return_if_fail (abi->runtime_linker_error == NULL);
+
+  if (abi->known_architecture == NULL)
+    return;
+
+  if (abi->known_architecture->interoperable_runtime_linker == NULL)
+    return;
+
+  if (!json_object_has_member (json_arch_obj, "runtime-linker"))
+    return;
+
+  runtime_linker_obj = json_object_get_object_member (json_arch_obj, "runtime-linker");
+
+  path = json_object_get_string_member_with_default (runtime_linker_obj,
+                                                     "path", NULL);
+  resolved = json_object_get_string_member_with_default (runtime_linker_obj,
+                                                         "resolved", NULL);
+
+  if (json_object_has_member (runtime_linker_obj, "error"))
+    {
+      GQuark error_domain;
+      int error_code;
+      const char *error_message;
+
+      error_domain = g_quark_from_string (json_object_get_string_member_with_default (runtime_linker_obj, "error-domain", NULL));
+      error_code = json_object_get_int_member_with_default (runtime_linker_obj,
+                                                            "error-code",
+                                                            -1);
+      error_message = json_object_get_string_member_with_default (runtime_linker_obj,
+                                                                  "error",
+                                                                  NULL);
+
+      if (error_domain == 0)
+        {
+          error_domain = SRT_ARCHITECTURE_ERROR;
+          error_code = SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR;
+        }
+
+      if (error_message == NULL)
+        error_message = "Unknown error";
+
+      g_set_error_literal (&abi->runtime_linker_error, error_domain, error_code,
+                           error_message);
+    }
+  else if (path == NULL)
+    {
+      /* no information */
+      return;
+    }
+  else if (g_strcmp0 (path, abi->known_architecture->interoperable_runtime_linker) != 0)
+    {
+      g_set_error (&abi->runtime_linker_error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+                   "Expected \"%s\" in report, but got \"%s\"",
+                   abi->known_architecture->interoperable_runtime_linker,
+                   path);
+    }
+  else
+    {
+      abi->runtime_linker_resolved = g_strdup (resolved);
+    }
+}
+
 /**
  * srt_system_info_new_from_json:
  * @path: (not nullable) (type filename): Path to a JSON report
@@ -706,6 +797,8 @@ srt_system_info_new_from_json (const char *path,
           abi->libraries_cache_available = TRUE;
           abi->cached_combined_issues = _srt_library_get_issues_from_report (json_arch_obj);
 
+          get_runtime_linker_from_report (info, abi, json_arch_obj);
+
           _srt_graphics_get_from_report (json_arch_obj,
                                          l->data,
                                          &abi->cached_graphics_results);
@@ -3833,3 +3926,137 @@ srt_system_info_get_xdg_portal_issues (SrtSystemInfo *self,
 
   return srt_xdg_portal_get_issues (self->xdg_portal_data);
 }
+
+static void
+ensure_runtime_linker (SrtSystemInfo *self,
+                       Abi *abi)
+{
+  g_autofree gchar *tmp = NULL;
+  int fd;
+
+  if (abi->runtime_linker_resolved != NULL)
+    return;
+
+  if (abi->runtime_linker_error != NULL)
+    return;
+
+  if (abi->known_architecture == NULL)
+    return;
+
+  if (abi->known_architecture->interoperable_runtime_linker == NULL)
+    {
+      g_set_error (&abi->runtime_linker_error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+                   "Interoperable runtime_linker for \"%s\" not known",
+                   abi->known_architecture->multiarch_tuple);
+      return;
+    }
+
+  if (self->sysroot_fd < 0)
+    {
+      g_set_error (&abi->runtime_linker_error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+                   "Unable to open sysroot");
+      return;
+    }
+
+  fd = _srt_resolve_in_sysroot (self->sysroot_fd,
+                                abi->known_architecture->interoperable_runtime_linker,
+                                SRT_RESOLVE_FLAGS_READABLE,
+                                &tmp,
+                                &abi->runtime_linker_error);
+
+  if (fd >= 0)
+    {
+      abi->runtime_linker_resolved = g_strconcat ("/", tmp, NULL);
+      close (fd);
+    }
+}
+
+/**
+ * srt_system_info_check_runtime_linker:
+ * @self: The #SrtSystemInfo object
+ * @multiarch_tuple: A multiarch tuple defining an ABI, as printed
+ *  by `gcc -print-multiarch` in the Steam Runtime
+ * @resolved: (out) (type filename) (transfer full) (optional): Used
+ *  to return the path to the runtime linker after resolving all
+ *  symbolic links. Free with g_free(); may be %NULL to ignore.
+ * @error: Used to raise an error on failure.
+ *
+ * Check whether the runtime linker `ld.so(8)` for the ABI described
+ * by @multiarch_tuple, as returned by
+ * srt_architecture_get_expected_runtime_linker(), is available.
+ *
+ * If `ld.so` is unavailable, return %FALSE with @error set.
+ *
+ * If not enough information is available to determine whether `ld.so`
+ * is available, raise %SRT_ARCHITECTURE_ERROR_NO_INFORMATION.
+ *
+ * Returns: %TRUE if `ld.so(8)` is available at the interoperable path
+ *  for the given architecture
+ */
+gboolean
+srt_system_info_check_runtime_linker (SrtSystemInfo *self,
+                                      const char *multiarch_tuple,
+                                      gchar **resolved,
+                                      GError **error)
+{
+  Abi *abi;
+
+  g_return_val_if_fail (SRT_IS_SYSTEM_INFO (self), FALSE);
+  g_return_val_if_fail (multiarch_tuple != NULL, FALSE);
+
+  abi = ensure_abi_unless_immutable (self, multiarch_tuple);
+
+  if (abi == NULL)
+    {
+      g_set_error (error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+                   "ABI \"%s\" not included in report",
+                   multiarch_tuple);
+      return FALSE;
+    }
+
+  if (!self->immutable_values)
+    ensure_runtime_linker (self, abi);
+
+  if (abi->known_architecture == NULL)
+    {
+      g_set_error (error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+                   "Interoperable runtime linker for \"%s\" not known",
+                   multiarch_tuple);
+      return FALSE;
+    }
+  else if (abi->runtime_linker_resolved != NULL)
+    {
+      if (resolved != NULL)
+        *resolved = g_strdup (abi->runtime_linker_resolved);
+
+      return TRUE;
+    }
+  else if (abi->runtime_linker_error != NULL)
+    {
+      if (error != NULL)
+        *error = g_error_copy (abi->runtime_linker_error);
+
+      return FALSE;
+    }
+  else if (self->immutable_values)
+    {
+      g_set_error (error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+                   "Runtime linker for \"%s\" not included in report",
+                   multiarch_tuple);
+      return FALSE;
+    }
+  else
+    {
+      /* We shouldn't be able to get here */
+      g_set_error (error, SRT_ARCHITECTURE_ERROR,
+                   SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+                   "Runtime linker for \"%s\" not checked",
+                   multiarch_tuple);
+      g_return_val_if_reached (FALSE);
+    }
+}
diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h
index 3ce01a9b38b6aeb75041e1f0582f0ad51145cf6c..63f1b800899132d022f8cf5d5144e25d30e4896a 100644
--- a/steam-runtime-tools/system-info.h
+++ b/steam-runtime-tools/system-info.h
@@ -275,6 +275,12 @@ _SRT_PUBLIC
 SrtXdgPortalIssues srt_system_info_get_xdg_portal_issues (SrtSystemInfo *self,
                                                           gchar **messages);
 
+_SRT_PUBLIC
+gboolean srt_system_info_check_runtime_linker (SrtSystemInfo *self,
+                                               const char *multiarch_tuple,
+                                               gchar **real_path,
+                                               GError **error);
+
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (SrtSystemInfo, g_object_unref)
 #endif
diff --git a/tests/architecture.c b/tests/architecture.c
index 595ac8dd2f1f75ac2d3696f5effd2f857f9dc396..6aa76b490b281fa45a6999faa573b610a1ed48d2 100644
--- a/tests/architecture.c
+++ b/tests/architecture.c
@@ -67,6 +67,13 @@ test_architecture (Fixture *f,
 #if defined(__i386__)
   g_assert_true (srt_architecture_can_run_i386 ());
 #endif
+
+  g_assert_cmpstr (srt_architecture_get_expected_runtime_linker (SRT_ABI_X86_64),
+                   ==, "/lib64/ld-linux-x86-64.so.2");
+  g_assert_cmpstr (srt_architecture_get_expected_runtime_linker (SRT_ABI_I386),
+                   ==, "/lib/ld-linux.so.2");
+  g_assert_cmpstr (srt_architecture_get_expected_runtime_linker ("potato-glados"),
+                   ==, NULL);
 }
 
 int
diff --git a/tests/generate-sysroots.py b/tests/generate-sysroots.py
index c6937dcc1020ed44bd23d33d8b034b6ff9025d87..e143ab620f3ee84bc810f341d41b4b4dff329d5c 100755
--- a/tests/generate-sysroots.py
+++ b/tests/generate-sysroots.py
@@ -107,6 +107,7 @@ ubuntu16/usr/lib/mock-ubuntu-64-bit/vdpau
     os.makedirs(name, mode=0o755, exist_ok=True)
 
 for name in '''
+debian10/usr/lib/i386-linux-gnu/ld.so
 debian10/usr/lib/i386-linux-gnu/dri/i965_dri.so
 debian10/usr/lib/i386-linux-gnu/dri/r300_dri.so
 debian10/usr/lib/i386-linux-gnu/dri/r600_drv_video.so
@@ -116,6 +117,7 @@ debian10/usr/lib/i386-linux-gnu/libva.so.2
 debian10/usr/lib/i386-linux-gnu/libvdpau.so.1
 debian10/usr/lib/i386-linux-gnu/vdpau/libvdpau_r600.so
 debian10/usr/lib/i386-linux-gnu/vdpau/libvdpau_radeonsi.so.1.0.0
+debian10/usr/lib/x86_64-linux-gnu/ld.so
 debian10/usr/lib/x86_64-linux-gnu/dri/i965_dri.so
 debian10/usr/lib/x86_64-linux-gnu/dri/r600_dri.so
 debian10/usr/lib/x86_64-linux-gnu/dri/r600_drv_video.so
@@ -188,6 +190,7 @@ steamrt/overrides/lib/i386-linux-gnu/libGLX_nvidia.so.0
 steamrt/run/pressure-vessel/.exists
 steamrt-overrides-issues/overrides/bin/.keep
 steamrt-overrides-issues/overrides/lib/i386-linux-gnu/.keep
+ubuntu16/lib64/ld-linux-x86-64.so.2
 ubuntu16/usr/lib/dri/radeonsi_dri.so
 ubuntu16/usr/lib/mock-ubuntu-64-bit/dri/i965_dri.so
 ubuntu16/usr/lib/mock-ubuntu-64-bit/dri/radeon_dri.so
@@ -201,6 +204,10 @@ ubuntu16/usr/lib/mock-ubuntu-64-bit/vdpau/libvdpau_radeonsi.so.1.0.0
     open(name, 'w').close()
 
 for name, target in {
+    'debian10/lib/ld-linux.so.2':
+        '/usr/lib/i386-linux-gnu/ld.so',
+    'debian10/lib64/ld-linux-x86-64.so.2':
+        '../usr/lib/x86_64-linux-gnu/ld.so',
     'debian10/usr/lib/i386-linux-gnu/vdpau/libvdpau_radeonsi.so':
         'libvdpau_radeonsi.so.1.0.0',
     'debian10/usr/lib/i386-linux-gnu/vdpau/libvdpau_radeonsi.so.1':
diff --git a/tests/json-report/full-good-report.json b/tests/json-report/full-good-report.json
index 371ac3c4be5aa9c4cb2e9334bb7f5af28ae637ef..d926f4b07f7010e7a60a1a95699645f2d3745360 100644
--- a/tests/json-report/full-good-report.json
+++ b/tests/json-report/full-good-report.json
@@ -53,6 +53,12 @@
   "architectures" : {
     "i386-linux-gnu" : {
       "can-run" : false,
+      "runtime-linker": {
+        "path" : "/lib/ld-linux.so.2",
+        "error-domain" : "g-io-error-quark",
+        "error-code" : 1,
+        "error" : "No such file or directory"
+      },
       "graphics-details" : {
         "x11/vulkan" : {
           "messages" : "ERROR: [Loader Message] Code 0 : /usr/lib/amdvlk64.so: wrong ELF class: ELFCLASS64\nCannot create Vulkan instance.\n",
@@ -120,6 +126,10 @@
     },
     "x86_64-linux-gnu" : {
       "can-run" : true,
+      "runtime-linker": {
+        "path" : "/lib64/ld-linux-x86-64.so.2",
+        "resolved" : "/lib/x86_64-linux-gnu/ld-2.31.so"
+      },
       "library-issues-summary" : [
       ],
       "graphics-details" : {
diff --git a/tests/json-report/partial-report-2.json b/tests/json-report/partial-report-2.json
index b882cd97c2088f6dbba002e746690ca8e72da185..20a77f242596442bde0588d948ba5be873585600 100644
--- a/tests/json-report/partial-report-2.json
+++ b/tests/json-report/partial-report-2.json
@@ -24,6 +24,10 @@
   "architectures" : {
     "x86_64-linux-gnu" : {
       "can-run" : true,
+      "runtime-linker": {
+        "path": "/foobar",
+        "resolved": "/foo/bar"
+      },
       "graphics-details" : {
         "x11/vulkan" : {
         }
diff --git a/tests/json-report/partial-report.json b/tests/json-report/partial-report.json
index e769bee394473946fd79ed54a3d9acf6f1d24846..d843f8237787346bd7a777c93c926c8935d11604 100644
--- a/tests/json-report/partial-report.json
+++ b/tests/json-report/partial-report.json
@@ -13,6 +13,9 @@
   "architectures" : {
     "i386-linux-gnu" : {
       "can-run" : false,
+      "runtime-linker": {
+        "error": "We just don't know"
+      },
       "graphics-details" : {
         "x11/vdpau" : {
           "renderer" : "G3DVL VDPAU Driver Shared Library version 1.0\n",
diff --git a/tests/system-info.c b/tests/system-info.c
index 68fc9cf9d622592f3fd0f720c16397452ee9fbd4..63597d177eb4b2fb898b0237996ac073d46d9d67 100644
--- a/tests/system-info.c
+++ b/tests/system-info.c
@@ -2408,10 +2408,20 @@ typedef struct
   gboolean is_available;
 } GraphicsTest;
 
+typedef struct
+{
+  const char *path;
+  const char *resolved;
+  const char *error_domain;
+  int error_code;
+  const char *error_message;
+} RuntimeLinkerTest;
+
 typedef struct
 {
   gboolean can_run;
   SrtLibraryIssues issues;
+  RuntimeLinkerTest runtime_linker;
   DriverTest dri_drivers[5];
   DriverTest va_api_drivers[5];
   DriverTest vdpau_drivers[5];
@@ -2556,6 +2566,13 @@ static const JsonTest json_test[] =
     {
       {
         .can_run = FALSE,
+        .runtime_linker =
+        {
+          .path = "/lib/ld-linux.so.2",
+          .error_domain = "g-io-error-quark",
+          .error_code = G_IO_ERROR_NOT_FOUND,
+          .error_message = "No such file or directory",
+        },
         .issues = SRT_LIBRARY_ISSUES_UNKNOWN,
         .graphics =
         {
@@ -2641,6 +2658,11 @@ static const JsonTest json_test[] =
 
       {
         .can_run = TRUE,
+        .runtime_linker =
+        {
+          .path = "/lib64/ld-linux-x86-64.so.2",
+          .resolved = "/lib/x86_64-linux-gnu/ld-2.31.so",
+        },
         .graphics =
         {
           {
@@ -2874,6 +2896,15 @@ static const JsonTest json_test[] =
     {
       {
         .can_run = FALSE,
+        .runtime_linker =
+        {
+          .path = "/lib/ld-linux.so.2",
+          /* Error domain and code are missing from the report, so we
+           * make something up */
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+          .error_message = "We just don't know",
+        },
         .issues = SRT_LIBRARY_ISSUES_UNKNOWN,
         .graphics =
         {
@@ -2888,6 +2919,13 @@ static const JsonTest json_test[] =
       {
         .can_run = TRUE,
         .issues = SRT_LIBRARY_ISSUES_UNKNOWN,
+        .runtime_linker =
+        {
+          .path = "/lib64/ld-linux-x86-64.so.2",
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+          .error_message = "Runtime linker for \"x86_64-linux-gnu\" not included in report",
+        },
       },
     },
     .locale_issues = SRT_LOCALE_ISSUES_UNKNOWN,
@@ -2958,10 +2996,26 @@ static const JsonTest json_test[] =
       {
         /* i386 */
         .issues = SRT_LIBRARY_ISSUES_CANNOT_LOAD,
+        .runtime_linker =
+        {
+          .path = "/lib/ld-linux.so.2",
+          /* i386 is completely missing from this report */
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+          .error_message = "ABI \"i386-linux-gnu\" not included in report",
+        },
       },
       {
         .can_run = TRUE,
         .issues = SRT_LIBRARY_ISSUES_UNKNOWN,
+        .runtime_linker =
+        {
+          .path = "/lib64/ld-linux-x86-64.so.2",
+          /* We don't have the expected ld.so in the report */
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_INTERNAL_ERROR,
+          .error_message = "Expected \"/lib64/ld-linux-x86-64.so.2\" in report, but got \"/foobar\"",
+        },
       },
     },
     .locale_issues = SRT_LOCALE_ISSUES_UNKNOWN,
@@ -3001,9 +3055,23 @@ static const JsonTest json_test[] =
     .architecture =
     {
       {
+        .runtime_linker =
+        {
+          .path = "/lib/ld-linux.so.2",
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+          .error_message = "ABI \"i386-linux-gnu\" not included in report",
+        },
         .issues = SRT_LIBRARY_ISSUES_CANNOT_LOAD,
       },
       {
+        .runtime_linker =
+        {
+          .path = "/lib64/ld-linux-x86-64.so.2",
+          .error_domain = "srt-architecture-error-quark",
+          .error_code = SRT_ARCHITECTURE_ERROR_NO_INFORMATION,
+          .error_message = "ABI \"x86_64-linux-gnu\" not included in report",
+        },
         .issues = SRT_LIBRARY_ISSUES_CANNOT_LOAD,
       },
     },
@@ -3063,6 +3131,49 @@ static const JsonTest json_test[] =
   }, /* End Newer JSON report */
 };
 
+static void
+assert_expected_runtime_linker (SrtSystemInfo *info,
+                                const char *multiarch_tuple,
+                                const RuntimeLinkerTest *rtld)
+{
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *resolved = NULL;
+  const char *expected;
+  gboolean ok;
+
+  /* shorthand notation for having no expectations */
+  if (rtld->path == NULL)
+    return;
+
+  expected = srt_architecture_get_expected_runtime_linker (multiarch_tuple);
+  ok = srt_system_info_check_runtime_linker (info, multiarch_tuple,
+                                             &resolved, &error);
+
+  g_assert_cmpstr (rtld->path, ==, expected);
+
+  if (rtld->resolved != NULL)
+    {
+      g_assert (rtld->error_domain == NULL);
+      g_assert (rtld->error_code == 0);
+      g_assert (rtld->error_message == NULL);
+
+      g_assert_no_error (error);
+      g_assert_true (ok);
+      g_assert_cmpstr (resolved, ==, rtld->resolved);
+    }
+  else
+    {
+      g_assert (rtld->error_domain != NULL);
+      g_assert (rtld->error_message != NULL);
+
+      g_assert_error (error, g_quark_from_string (rtld->error_domain),
+                      rtld->error_code);
+      g_assert_cmpstr (error->message, ==, rtld->error_message);
+      g_assert_false (ok);
+      g_assert_cmpstr (resolved, ==, NULL);
+    }
+}
+
 static void
 json_parsing (Fixture *f,
               gconstpointer context)
@@ -3171,6 +3282,10 @@ json_parsing (Fixture *f,
           g_assert_cmpint (this_arch.issues, ==,
                            srt_system_info_check_libraries (info, multiarch_tuples[j], NULL));
 
+          assert_expected_runtime_linker (info,
+                                          multiarch_tuples[j],
+                                          &this_arch.runtime_linker);
+
           for (jj = 0; this_arch.graphics[jj].is_available; jj++)
             {
               SrtGraphics *graphics = NULL;
@@ -3442,6 +3557,112 @@ json_parsing (Fixture *f,
     }
 }
 
+static void
+architecture_symlinks (Fixture *f,
+                       gconstpointer context)
+{
+  g_autoptr(SrtSystemInfo) info;
+  g_autofree gchar *sysroot = NULL;
+  gboolean ret;
+
+  sysroot = g_build_filename (f->sysroots, "debian10", NULL);
+
+  info = srt_system_info_new (NULL);
+  srt_system_info_set_sysroot (info, sysroot);
+
+  /* In the mock Debian 10 sysroot created by tests/generate-sysroots.py,
+   * the well-known linker paths are symbolic links, much like they are
+   * on a real Debian system. */
+
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, SRT_ABI_X86_64,
+                                                  &resolved, &error);
+      g_assert_no_error (error);
+      g_assert_true (ret);
+      g_assert_cmpstr (resolved, ==, "/usr/lib/x86_64-linux-gnu/ld.so");
+    }
+
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, SRT_ABI_I386,
+                                                  &resolved, &error);
+      g_assert_no_error (error);
+      g_assert_true (ret);
+      g_assert_cmpstr (resolved, ==, "/usr/lib/i386-linux-gnu/ld.so");
+    }
+
+  /* The sysroot doesn't include x32 support. */
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, "x86_64-linux-gnux32",
+                                                  &resolved, &error);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+      g_assert_false (ret);
+      g_assert_cmpstr (resolved, ==, NULL);
+    }
+
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, "hal9000-netbsd",
+                                                  &resolved, &error);
+      /* We have no idea what the runtime linker would be, so we have
+       * no way to check for it */
+      g_assert_error (error, SRT_ARCHITECTURE_ERROR,
+                      SRT_ARCHITECTURE_ERROR_NO_INFORMATION);
+      g_assert_false (ret);
+      g_assert_cmpstr (resolved, ==, NULL);
+    }
+}
+
+static void
+architecture_notlinks (Fixture *f,
+                       gconstpointer context)
+{
+  g_autoptr(SrtSystemInfo) info;
+  g_autofree gchar *sysroot = NULL;
+  gboolean ret;
+
+  sysroot = g_build_filename (f->sysroots, "ubuntu16", NULL);
+
+  info = srt_system_info_new (NULL);
+  srt_system_info_set_sysroot (info, sysroot);
+
+  /* In the mock Ubuntu 16.04 sysroot created by tests/generate-sysroots.py,
+   * the well-known runtime linker for x86_64 is a real file (unlike
+   * real Ubuntu systems) and the runtime linker for i386 is missing. */
+
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, "x86_64-linux-gnu",
+                                                  &resolved, &error);
+      g_assert_no_error (error);
+      g_assert_true (ret);
+      g_assert_cmpstr (resolved, ==, "/lib64/ld-linux-x86-64.so.2");
+    }
+
+    {
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *resolved = NULL;
+
+      ret = srt_system_info_check_runtime_linker (info, "i386-linux-gnu",
+                                                  &resolved, &error);
+      g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+      g_assert_false (ret);
+      g_assert_cmpstr (resolved, ==, NULL);
+    }
+}
+
 int
 main (int argc,
       char **argv)
@@ -3531,6 +3752,11 @@ main (int argc,
   g_test_add ("/system-info/json_parsing", Fixture, NULL,
               setup, json_parsing, teardown);
 
+  g_test_add ("/system-info/architecture/symlinks", Fixture, NULL,
+              setup, architecture_symlinks, teardown);
+  g_test_add ("/system-info/architecture/notlinks", Fixture, NULL,
+              setup, architecture_notlinks, teardown);
+
   status = g_test_run ();
 
   if (!_srt_global_teardown_private_xdg_dirs ())