diff --git a/elf/dl-iterate_cpu.h b/elf/dl-iterate_cpu.h
new file mode 100644
index 0000000000..772efffae1
--- /dev/null
+++ b/elf/dl-iterate_cpu.h
@@ -0,0 +1,135 @@
+/* Iterate over all CPUs, for CPU-specific diagnostics.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef DL_ITERATE_CPU_H
+#define DL_ITERATE_CPU_H
+
+#include <dl-affinity.h>
+
+struct dl_iterate_cpu
+{
+  /* Sequential iteration count, starting at 0.  */
+  unsigned int processor_index;
+
+  /* Requested CPU.  Can be -1 if affinity could not be set.  */
+  int requested_cpu;
+
+  /* Observed current CPU.  -1 if unavailable.  */
+  int actual_cpu;
+
+  /* Observed node ID for the CPU.  -1 if unavailable.  */
+  int actual_node;
+
+  /* Internal fields to implement the iteration.   */
+
+  /* Affinity as obtained by _dl_iterate_cpu_init, using
+     _dl_getaffinity.  Space for 8,192 CPUs.  */
+  unsigned long int mask_reference[8192 / sizeof (unsigned long int) / 8];
+
+  /* This array is used by _dl_setaffinity calls.  */
+  unsigned long int mask_request[8192 / sizeof (unsigned long int) / 8];
+
+  /* Return value from the initial _dl_getaffinity call.   */
+  int length_reference;
+};
+
+static void
+_dl_iterate_cpu_init (struct dl_iterate_cpu *dic)
+{
+  dic->length_reference
+    = _dl_getaffinity (dic->mask_reference, sizeof (dic->mask_reference));
+  /* Prepare for the first _dl_iterate_cpu_next call.  */
+  dic->processor_index = -1;
+  dic->requested_cpu = -1;
+}
+
+static bool
+_dl_iterate_cpu_next (struct dl_iterate_cpu *dic)
+{
+  ++dic->processor_index;
+
+  if (dic->length_reference > 0)
+    {
+      /* Search for the next CPU to switch to.  */
+      while (true)
+        {
+          ++dic->requested_cpu;
+
+          /* Array index and bit number within the array.  */
+          unsigned int long_index
+            = dic->requested_cpu / sizeof (unsigned long int) / 8;
+          unsigned int bit_index
+            = dic->requested_cpu % (sizeof (unsigned long int) * 8);
+
+          if (long_index * sizeof (unsigned long int) >= dic->length_reference)
+            /* All possible CPUs have been covered.  */
+            return false;
+
+          unsigned long int bit = 1UL << bit_index;
+          if (dic->mask_reference[long_index] & bit)
+            {
+              /* The CPU is available.  Try to select it.  */
+              dic->mask_request[long_index] = bit;
+              if (_dl_setaffinity (dic->mask_request,
+                                   (long_index + 1)
+                                   * sizeof (unsigned long int)) < 0)
+                {
+                  /* Record that we could not perform a CPU request.  */
+                  dic->length_reference = -1;
+
+                  if (dic->processor_index > 0)
+                    /* We already reported something.  There is no need to
+                       continue because the new data is probably not useful.  */
+                    return false;
+                }
+
+              /* Clear the bit in case the next iteration switches to the
+                 next long value.  */
+              dic->mask_request[long_index] = 0;
+
+              /* We found a CPU to run on.  */
+              break;
+            }
+        }
+    }
+  else
+    {
+      /* No way to set CPU affinity.  Iterate just once.  */
+      if (dic->processor_index > 0)
+        return false;
+    }
+
+  /* Fill in the actual CPU information.  CPU pinning may not actually
+     be effective, depending on the container host.  */
+  unsigned int cpu, node;
+  if (_dl_getcpu (&cpu, &node) < 0)
+    {
+      /* No CPU information available.  */
+      dic->actual_cpu = -1;
+      dic->actual_node = -1;
+    }
+  else
+    {
+      dic->actual_cpu = cpu;
+      dic->actual_node = node;
+    }
+
+  return true;
+}
+
+#endif /* DL_ITERATE_CPU_H */
diff --git a/sysdeps/generic/dl-affinity.h b/sysdeps/generic/dl-affinity.h
new file mode 100644
index 0000000000..d117f737e9
--- /dev/null
+++ b/sysdeps/generic/dl-affinity.h
@@ -0,0 +1,54 @@
+/* CPU affinity handling for the dynamic linker.  Stub version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <errno.h>
+#include <stddef.h>
+
+/* On success, write the current CPU ID to *CPU, and the current node
+   ID to *NODE, and return 0.  Return a negative error code on
+   failure.  */
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+  return -ENOSYS;
+}
+
+/* On success, write CPU ID affinity bits for the current thread to
+   *BITS, which must be SIZE bytes long, and return the number of
+   bytes updated, a multiple of sizeof (unsigned long int).  On
+   failure, return a negative error code.  */
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+  return -ENOSYS;
+}
+
+/* Set the CPU affinity mask for the current thread to *BITS, using
+   the SIZE bytes from that array, which should be a multiple of
+   sizeof (unsigned long int).  Return 0 on success, and a negative
+   error code on failure.  */
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+  return -ENOSYS;
+}
+
+#endif /* DL_AFFINITY_H */
diff --git a/sysdeps/unix/sysv/linux/dl-affinity.h b/sysdeps/unix/sysv/linux/dl-affinity.h
new file mode 100644
index 0000000000..bbfede7750
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/dl-affinity.h
@@ -0,0 +1,46 @@
+/* CPU affinity handling for the dynamic linker.  Linux version.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.
+
+   The GNU C 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* See sysdeps/generic/dl-affinity.h for documentation of these interfaces.  */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <sysdep.h>
+#include <stddef.h>
+#include <unistd.h>
+
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+  return INTERNAL_SYSCALL_CALL (getcpu, cpu, node);
+}
+
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+  return INTERNAL_SYSCALL_CALL (sched_getaffinity, /* TID */ 0, size, bits);
+}
+
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+  return INTERNAL_SYSCALL_CALL (sched_setaffinity, /* TID */ 0, size, bits);
+}
+
+#endif /* DL_AFFINITY_H */
