diff --git a/pressure-vessel/elf-utils.c b/pressure-vessel/elf-utils.c
deleted file mode 100644
index 466003e5807f0b300f0d72eb5c63b718895f5c16..0000000000000000000000000000000000000000
--- a/pressure-vessel/elf-utils.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright © 2017-2020 Collabora Ltd.
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "elf-utils.h"
-
-#include <glib.h>
-#include <glib/gstdio.h>
-#include <gio/gio.h>
-#include <libelf.h>
-
-#include "libglnx/libglnx.h"
-
-#include "steam-runtime-tools/glib-backports-internal.h"
-
-#define throw_elf_error(error, format, ...) \
-  glnx_null_throw (error, format ": %s", ##__VA_ARGS__, elf_errmsg (elf_errno ()))
-
-/*
- * pv_elf_open_fd:
- * @fd: An open file descriptor
- *
- * Returns: (transfer full): A libelf object representing the library
- */
-Elf *
-pv_elf_open_fd (int fd,
-                GError **error)
-{
-  g_autoptr(Elf) elf = NULL;
-
-  g_return_val_if_fail (fd >= 0, NULL);
-  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
-  if (elf_version (EV_CURRENT) == EV_NONE)
-    return throw_elf_error (error, "elf_version(EV_CURRENT)");
-
-  elf = elf_begin (fd, ELF_C_READ, NULL);
-
-  if (elf == NULL)
-    return throw_elf_error (error, "elf_begin");
-
-  return g_steal_pointer (&elf);
-}
-
-/*
- * pv_elf_get_soname:
- * @elf: A libelf object
- *
- * Return the `DT_SONAME` header, or %NULL on error
- */
-gchar *
-pv_elf_get_soname (Elf *elf,
-                   GError **error)
-{
-  GElf_Ehdr ehdr;
-  size_t phdr_count = 0;
-  size_t i;
-  GElf_Phdr phdr_mem;
-  GElf_Phdr *phdr = NULL;
-  GElf_Dyn *dynamic_header = NULL;
-  GElf_Dyn dynamic_header_mem;
-  Elf_Scn *dynamic_section = NULL;
-  GElf_Shdr dynamic_section_header_mem;
-  GElf_Shdr *dynamic_section_header = NULL;
-  Elf_Scn *string_table_section = NULL;
-  GElf_Shdr string_table_header_mem;
-  GElf_Shdr *string_table_header = NULL;
-  Elf_Data *data = NULL;
-  size_t size_per_dyn;
-  const char *soname = NULL;
-
-  g_return_val_if_fail (elf != NULL, NULL);
-  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
-  if (elf_kind (elf) != ELF_K_ELF)
-    return glnx_null_throw (error, "elf_kind %d, expected ELF_K_ELF=%d",
-                            elf_kind (elf), ELF_K_ELF);
-
-  if (gelf_getehdr (elf, &ehdr) == NULL)
-    return throw_elf_error (error, "elf_getehdr");
-
-  if (ehdr.e_type != ET_DYN)
-    return glnx_null_throw (error, "ehdr.e_type %d, expected ET_DYN=%d",
-                            ehdr.e_type, ET_DYN);
-
-  if (elf_getphdrnum (elf, &phdr_count) != 0)
-    return throw_elf_error (error, "elf_getphdrnum");
-
-  for (i = 0; i < phdr_count; i++)
-    {
-      phdr = gelf_getphdr (elf, i, &phdr_mem);
-
-      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
-        {
-          dynamic_section = gelf_offscn (elf, phdr->p_offset);
-          dynamic_section_header = gelf_getshdr (dynamic_section,
-                                                 &dynamic_section_header_mem);
-          break;
-        }
-    }
-
-  if (dynamic_section == NULL || dynamic_section_header == NULL)
-    return glnx_null_throw (error, "Unable to find dynamic section header");
-
-  string_table_section = elf_getscn (elf, dynamic_section_header->sh_link);
-  string_table_header = gelf_getshdr (string_table_section,
-                                      &string_table_header_mem);
-
-  if (string_table_section == NULL || string_table_header == NULL)
-    return glnx_null_throw (error, "Unable to find linked string table");
-
-  data = elf_getdata (dynamic_section, NULL);
-
-  if (data == NULL)
-    return throw_elf_error (error, "elf_getdata(dynamic_section)");
-
-  size_per_dyn = gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT);
-
-  for (i = 0; i < dynamic_section_header->sh_size / size_per_dyn; i++)
-    {
-      dynamic_header = gelf_getdyn (data, i, &dynamic_header_mem);
-
-      if (dynamic_header == NULL)
-        break;
-
-      if (dynamic_header->d_tag == DT_SONAME)
-        {
-          soname = elf_strptr (elf, dynamic_section_header->sh_link,
-                               dynamic_header->d_un.d_val);
-
-          if (soname == NULL)
-            return glnx_null_throw (error, "Unable to read DT_SONAME");
-
-
-        }
-    }
-
-  if (soname == NULL)
-    return glnx_null_throw (error, "Unable to find DT_SONAME");
-
-  return g_strdup (soname);
-}
-
diff --git a/pressure-vessel/elf-utils.h b/pressure-vessel/elf-utils.h
deleted file mode 100644
index cb0529cf8c6cb50c62d2bffc403496cbf9f3b998..0000000000000000000000000000000000000000
--- a/pressure-vessel/elf-utils.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright © 2020 Collabora Ltd.
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <gelf.h>
-#include <glib.h>
-#include <libelf.h>
-
-#include "libglnx/libglnx.h"
-
-#include "steam-runtime-tools/glib-backports-internal.h"
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (Elf, elf_end);
-
-Elf *pv_elf_open_fd (int fd,
-                     GError **error);
-
-gchar *pv_elf_get_soname (Elf *elf,
-                          GError **error);
diff --git a/pressure-vessel/meson.build b/pressure-vessel/meson.build
index 757e68af49eb98471d9eaf1926a73c2114eb6cd1..d1c8eb37c69714e9cae8c00066a1ab9d0471d503 100644
--- a/pressure-vessel/meson.build
+++ b/pressure-vessel/meson.build
@@ -77,8 +77,6 @@ pressure_vessel_utils = static_library(
   sources : [
     'bwrap-lock.c',
     'bwrap-lock.h',
-    'elf-utils.c',
-    'elf-utils.h',
     'flatpak-bwrap.c',
     'flatpak-bwrap-private.h',
     'flatpak-utils-base.c',
@@ -94,7 +92,6 @@ pressure_vessel_utils = static_library(
   dependencies : [
     threads,
     gio_unix,
-    libelf,
     libglnx_dep,
     libsteamrt_static_dep,
   ],
diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index 645955af74b4c9b06663638a8793dc2aaee45753..8fd008ff4ad2a8a447ca11e4d52e29363522bcf7 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -39,7 +39,6 @@
 
 #include "bwrap.h"
 #include "bwrap-lock.h"
-#include "elf-utils.h"
 #include "enumtypes.h"
 #include "exports.h"
 #include "flatpak-run-private.h"
@@ -2837,18 +2836,17 @@ pv_runtime_remove_overridden_libraries (PvRuntime *self,
 
       while (TRUE)
         {
-          g_autoptr(Elf) elf = NULL;
-          g_autoptr(GError) local_error = NULL;
-          glnx_autofd int libfd = -1;
           g_autofree gchar *path = NULL;
-          g_autofree gchar *soname = NULL;
           g_autofree gchar *target = NULL;
+          const char *target_base;
 
           if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&iters[i], &dent,
                                                            NULL, error))
-            return glnx_prefix_error (error, "Unable to iterate over \"%s/%s\"",
-                                      self->mutable_sysroot,
-                                      libdir);
+            {
+              glnx_prefix_error (error, "Unable to iterate over \"%s/%s\"",
+                                 self->mutable_sysroot, libdir);
+              goto out;
+            }
 
           if (dent == NULL)
             break;
@@ -2877,18 +2875,38 @@ pv_runtime_remove_overridden_libraries (PvRuntime *self,
             continue;
 
           path = g_build_filename (libdir, dent->d_name, NULL);
+          target = glnx_readlinkat_malloc (iters[i].fd, dent->d_name,
+                                           NULL, NULL);
+          if (target != NULL)
+            target_base = glnx_basename (target);
+          else
+            target_base = NULL;
+
+          /* Suppose we have a shared library libcurl.so.4 -> libcurl.so.4.2.0
+           * in the container and libcurl.so.4.7.0 in the provider,
+           * with a backwards-compatibility alias libcurl.so.3.
+           * dent->d_name might be any of those strings. */
 
           /* scope for soname_link */
+          if (TRUE)   /* to avoid -Wmisleading-indentation */
             {
               g_autofree gchar *soname_link = NULL;
 
+              /* If we're looking at
+               * /usr/lib/MULTIARCH/libcurl.so.4 -> libcurl.so.4.2.0, and a
+               * symlink .../overrides/lib/MULTIARCH/libcurl.so.4 exists, then
+               * we want to delete /usr/lib/MULTIARCH/libcurl.so.4 and
+               * /usr/lib/MULTIARCH/libcurl.so.4.2.0. */
               soname_link = g_build_filename (arch->libdir_in_current_namespace,
                                               dent->d_name, NULL);
 
-              /* If we found libfoo.so.1 in the container, and libfoo.so.1
-               * also exists among the overrides, delete it. */
               if (g_file_test (soname_link, G_FILE_TEST_IS_SYMLINK))
                 {
+                  if (target_base != NULL)
+                    g_hash_table_replace (delete[i],
+                                          g_strdup (target_base),
+                                          g_strdup (soname_link));
+
                   g_hash_table_replace (delete[i],
                                         g_strdup (dent->d_name),
                                         g_steal_pointer (&soname_link));
@@ -2896,22 +2914,63 @@ pv_runtime_remove_overridden_libraries (PvRuntime *self,
                 }
             }
 
-          target = glnx_readlinkat_malloc (iters[i].fd, dent->d_name,
-                                           NULL, NULL);
+          /* scope for alias_link */
+          if (TRUE)   /* to avoid -Wmisleading-indentation */
+            {
+              g_autofree gchar *alias_link = NULL;
+              g_autofree gchar *alias_target = NULL;
+
+              /* If we're looking at
+               * /usr/lib/MULTIARCH/libcurl.so.3 -> libcurl.so.4, and a
+               * symlink .../aliases/libcurl.so.3 exists and points to
+               * e.g. .../overrides/lib/$MULTIARCH/libcurl.so.4, then
+               * /usr/lib/MULTIARCH/libcurl.so.3 was overridden and should
+               * be deleted; /usr/lib/MULTIARCH/libcurl.so.4 should also
+               * be deleted.
+               *
+               * However, if .../aliases/libcurl.so.3 points to
+               * e.g. /usr/lib/MULTIARCH/libcurl.so.4, then the container's
+               * library was not overridden and we should not delete
+               * anything. */
+              alias_link = g_build_filename (arch->aliases_in_current_namespace,
+                                             dent->d_name, NULL);
+              alias_target = glnx_readlinkat_malloc (AT_FDCWD, alias_link,
+                                                     NULL, NULL);
+
+              if (alias_target != NULL
+                  && flatpak_has_path_prefix (alias_target,
+                                              self->overrides_in_container))
+                {
+                  if (target_base != NULL)
+                    g_hash_table_replace (delete[i],
+                                          g_strdup (target_base),
+                                          g_strdup (alias_link));
+
+                  g_hash_table_replace (delete[i],
+                                        g_strdup (dent->d_name),
+                                        g_steal_pointer (&alias_link));
+                  continue;
+                }
+            }
 
           if (target != NULL)
             {
               g_autofree gchar *soname_link = NULL;
 
+              /* If we're looking at
+               * /usr/lib/MULTIARCH/libcurl.so -> libcurl.so.4, and a
+               * symlink .../overrides/lib/MULTIARCH/libcurl.so.4 exists,
+               * then we want to delete /usr/lib/MULTIARCH/libcurl.so
+               * and /usr/lib/MULTIARCH/libcurl.so.4. */
               soname_link = g_build_filename (arch->libdir_in_current_namespace,
                                               glnx_basename (target),
                                               NULL);
 
-              /* If the symlink in the container points to
-               * /foo/bar/libfoo.so.1, and libfoo.so.1 also exists among
-               * the overrides, delete it. */
               if (g_file_test (soname_link, G_FILE_TEST_IS_SYMLINK))
                 {
+                  g_hash_table_replace (delete[i],
+                                        g_strdup (target_base),
+                                        g_strdup (soname_link));
                   g_hash_table_replace (delete[i],
                                         g_strdup (dent->d_name),
                                         g_steal_pointer (&soname_link));
@@ -2919,48 +2978,78 @@ pv_runtime_remove_overridden_libraries (PvRuntime *self,
                 }
             }
 
-          libfd = _srt_resolve_in_sysroot (self->mutable_sysroot_fd, path,
-                                           SRT_RESOLVE_FLAGS_READABLE, NULL,
-                                           &local_error);
-
-          if (libfd < 0)
+          if (target != NULL)
             {
-              g_warning ("Unable to open %s/%s for reading: %s",
-                         self->mutable_sysroot, path, local_error->message);
-              g_clear_error (&local_error);
-              continue;
+              g_autofree gchar *alias_link = NULL;
+              g_autofree gchar *alias_target = NULL;
+
+              /* If we're looking at
+               * /usr/lib/MULTIARCH/libcurl.so.3 -> libcurl.so.4, and a
+               * symlink .../aliases/libcurl.so.3 exists and points to
+               * e.g. .../overrides/lib/$MULTIARCH/libcurl.so.4, then
+               * /usr/lib/MULTIARCH/libcurl.so.3 was overridden and should
+               * be deleted; /usr/lib/MULTIARCH/libcurl.so.4 should also
+               * be deleted.
+               *
+               * However, if .../aliases/libcurl.so.3 points to
+               * e.g. /usr/lib/MULTIARCH/libcurl.so.4, then the container's
+               * library was not overridden and we should not delete it. */
+              alias_link = g_build_filename (arch->aliases_in_current_namespace,
+                                             glnx_basename (target),
+                                             NULL);
+              alias_target = glnx_readlinkat_malloc (AT_FDCWD, alias_link,
+                                                     NULL, NULL);
+
+              if (alias_target != NULL
+                  && flatpak_has_path_prefix (alias_target,
+                                              self->overrides_in_container))
+                {
+                  g_hash_table_replace (delete[i],
+                                        g_strdup (target_base),
+                                        g_strdup (alias_link));
+                  g_hash_table_replace (delete[i],
+                                        g_strdup (dent->d_name),
+                                        g_steal_pointer (&alias_link));
+                  continue;
+                }
             }
+        }
 
-          elf = pv_elf_open_fd (libfd, &local_error);
+      /* Iterate over the directory again, to clean up dangling development
+       * symlinks */
+      glnx_dirfd_iterator_rewind (&iters[i]);
 
-          if (elf != NULL)
-            soname = pv_elf_get_soname (elf, &local_error);
+      while (TRUE)
+        {
+          g_autofree gchar *target = NULL;
+          gpointer reason;
 
-          if (soname == NULL)
+          if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&iters[i], &dent,
+                                                           NULL, error))
             {
-              g_warning ("Unable to get SONAME of %s/%s: %s",
-                         self->mutable_sysroot, path, local_error->message);
-              g_clear_error (&local_error);
-              continue;
+              glnx_prefix_error (error, "Unable to iterate over \"%s/%s\"",
+                                 self->mutable_sysroot, libdir);
+              goto out;
             }
 
-          /* If we found a library with SONAME libfoo.so.1 in the
-           * container, and libfoo.so.1 also exists among the overrides,
-           * delete it. */
-            {
-              g_autofree gchar *soname_link = NULL;
+          if (dent == NULL)
+            break;
 
-              soname_link = g_build_filename (arch->libdir_in_current_namespace,
-                                              soname, NULL);
+          if (dent->d_type != DT_LNK)
+            continue;
 
-              if (g_file_test (soname_link, G_FILE_TEST_IS_SYMLINK))
-                {
-                  g_hash_table_replace (delete[i],
-                                        g_strdup (dent->d_name),
-                                        g_steal_pointer (&soname_link));
-                  continue;
-                }
-            }
+          /* If we were going to delete it anyway, ignore */
+          if (g_hash_table_lookup_extended (delete[i], dent->d_name, NULL, NULL))
+            continue;
+
+          target = glnx_readlinkat_malloc (iters[i].fd, dent->d_name,
+                                           NULL, NULL);
+
+          /* If we're going to delete the target, also delete the symlink
+           * rather than leaving it dangling */
+          if (g_hash_table_lookup_extended (delete[i], target, NULL, &reason))
+            g_hash_table_replace (delete[i], g_strdup (dent->d_name),
+                                  g_strdup (reason));
         }
     }
 
diff --git a/subprojects/libglnx/glnx-dirfd.c b/subprojects/libglnx/glnx-dirfd.c
index 6d1e2d216f0f7bbadbdef778432572813898ba50..0a63bcbc8016d48437558c24337eef9952779280 100644
--- a/subprojects/libglnx/glnx-dirfd.c
+++ b/subprojects/libglnx/glnx-dirfd.c
@@ -173,6 +173,24 @@ glnx_dirfd_iterator_next_dent (GLnxDirFdIterator  *dfd_iter,
   return TRUE;
 }
 
+/**
+ * glnx_dirfd_iterator_rewind:
+ * @dfd_iter: A directory iterator
+ *
+ * Rewind to the beginning of @dfd_iter. The next call to
+ * glnx_dirfd_iterator_next_dent() will provide the first entry in the
+ * directory.
+ */
+void
+glnx_dirfd_iterator_rewind (GLnxDirFdIterator  *dfd_iter)
+{
+  GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter;
+
+  g_return_if_fail (dfd_iter->initialized);
+
+  rewinddir (real_dfd_iter->d);
+}
+
 /**
  * glnx_dirfd_iterator_next_dent_ensure_dtype:
  * @dfd_iter: A directory iterator
diff --git a/subprojects/libglnx/glnx-dirfd.h b/subprojects/libglnx/glnx-dirfd.h
index 0046ac8eb651ebe9b753d604d1150a2ab2334478..d5773e729c2e3b3166c4a4b38e2039c305eece48 100644
--- a/subprojects/libglnx/glnx-dirfd.h
+++ b/subprojects/libglnx/glnx-dirfd.h
@@ -66,6 +66,7 @@ gboolean glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator  *dfd_ite
                                                      struct dirent     **out_dent,
                                                      GCancellable       *cancellable,
                                                      GError            **error);
+void glnx_dirfd_iterator_rewind (GLnxDirFdIterator  *dfd_iter);
 void glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter);
 
 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxDirFdIterator, glnx_dirfd_iterator_clear)
diff --git a/tests/pressure-vessel/meson.build b/tests/pressure-vessel/meson.build
index 68f377973ff854ca537195e8b6ca16336a56004f..792fd8907727f454a05fb37fd85ae17e85cd948f 100644
--- a/tests/pressure-vessel/meson.build
+++ b/tests/pressure-vessel/meson.build
@@ -145,7 +145,6 @@ endforeach
 # Helper programs and manual tests
 helpers = [
   'cheap-copy',
-  'elf-get-soname',
   'helper',
 ]