diff --git a/sysdeps/powerpc/dl-diagnostics-cpu.c b/sysdeps/powerpc/dl-diagnostics-cpu.c
new file mode 100644
index 0000000000..db8d19c7ec
--- /dev/null
+++ b/sysdeps/powerpc/dl-diagnostics-cpu.c
@@ -0,0 +1,48 @@
+/* Print CPU diagnostics data in ld.so.  PowerPC version.
+   Copyright (C) 2025 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/>.  */
+
+#include <dl-diagnostics.h>
+#include <dl-hwcap-info.h>
+#include <ldsodefs.h>
+#include <sys/auxv.h>
+
+static void
+print_hwcap_value (const char *label, int hwcap, unsigned long int value)
+{
+  _dl_printf ("powerpc.cpu_features.%s=\"", label);
+  size_t offset = 0;
+  for (int i = 0; i < __dl_hwcap_info_size; ++i)
+    {
+      const char *hwcap_name = __dl_hwcap_names + offset;
+      size_t hwcap_name_len = strlen (hwcap_name);
+      if (hwcap == __dl_hwcap_info[i].hwcap
+	  && value & __dl_hwcap_info[i].value)
+	_dl_printf ("%s ", hwcap_name);
+      offset += hwcap_name_len + 1;
+    }
+  _dl_printf ("\"\n");
+}
+
+void
+_dl_diagnostics_cpu (void)
+{
+  print_hwcap_value ("hwcap", AT_HWCAP, GLRO(dl_hwcap));
+  print_hwcap_value ("hwcap2", AT_HWCAP2, GLRO(dl_hwcap2));
+  print_hwcap_value ("hwcap3", AT_HWCAP3, GLRO(dl_hwcap3));
+  print_hwcap_value ("hwcap4", AT_HWCAP4, GLRO(dl_hwcap4));
+}
diff --git a/sysdeps/powerpc/dl-procinfo.c b/sysdeps/powerpc/dl-procinfo.c
index 1df247ac07..0db1e65112 100644
--- a/sysdeps/powerpc/dl-procinfo.c
+++ b/sysdeps/powerpc/dl-procinfo.c
@@ -62,37 +62,6 @@ PROCINFO_CLASS struct cpu_features _dl_powerpc_cpu_features
 # endif
 #endif
 
-#if !defined PROCINFO_DECL && defined SHARED
-  ._dl_powerpc_cap_flags
-#else
-PROCINFO_CLASS const char _dl_powerpc_cap_flags[_DL_HWCAP_COUNT][15]
-#endif
-#ifndef PROCINFO_DECL
-= {
-    "ppcle", "true_le", "", "",
-    "", "", "archpmu", "vsx",
-    "arch_2_06", "power6x", "dfp", "pa6t",
-    "arch_2_05", "ic_snoop", "smt", "booke",
-    "cellbe", "power5+", "power5", "power4",
-    "notb", "efpdouble", "efpsingle", "spe",
-    "ucache", "4xxmac", "mmu", "fpu",
-    "altivec", "ppc601", "ppc64", "ppc32",
-    "", "", "", "",
-    "", "", "", "",
-    "", "", "", "",
-    "", "", "", "",
-    "", "mma", "arch_3_1", "htm-no-suspend",
-    "scv", "darn", "ieee128", "arch_3_00",
-    "htm-nosc", "vcrypto", "tar", "isel",
-    "ebb", "dscr", "htm", "arch_2_07",
-  }
-#endif
-#if !defined SHARED || defined PROCINFO_DECL
-;
-#else
-,
-#endif
-
 #if !IS_IN (ldconfig)
 # if !defined PROCINFO_DECL && defined SHARED
      ._dl_cache_line_size
diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h
index 585ce41226..04bbe7ba1c 100644
--- a/sysdeps/powerpc/dl-procinfo.h
+++ b/sysdeps/powerpc/dl-procinfo.h
@@ -20,20 +20,6 @@
 #define _DL_PROCINFO_H 1
 
 #include <ldsodefs.h>
-#include <sysdep.h>	/* This defines the PPC_FEATURE[2]_* macros.  */
-
-/* Feature masks are all 32-bits in size.  */
-#define _DL_HWCAP_SIZE		32
-
-/* AT_HWCAP2 feature strings follow the AT_HWCAP feature strings.  */
-#define _DL_HWCAP2_OFFSET	_DL_HWCAP_SIZE
-
-/* AT_HWCAP3 feature strings follow the AT_HWCAP2 feature strings.  */
-#define _DL_HWCAP3_OFFSET	(_DL_HWCAP2_OFFSET + _DL_HWCAP_SIZE)
-
-/* AT_HWCAP4 feature strings follow the AT_HWCAP3 feature strings.  */
-#define _DL_HWCAP4_OFFSET	(_DL_HWCAP3_OFFSET + _DL_HWCAP_SIZE)
-
 
 #define _DL_FIRST_PLATFORM	32
 
@@ -56,13 +42,6 @@
 #define PPC_PLATFORM_POWER10		15
 #define PPC_PLATFORM_POWER11		16
 
-static inline const char *
-__attribute__ ((unused))
-_dl_hwcap_string (int idx)
-{
-  return GLRO(dl_powerpc_cap_flags)[idx];
-}
-
 static inline int
 __attribute__ ((unused, always_inline))
 _dl_string_platform (const char *str)
@@ -183,47 +162,6 @@ _dl_procinfo (unsigned int type, unsigned long int word)
 {
   switch(type)
     {
-    case AT_HWCAP:
-      _dl_printf ("AT_HWCAP:            ");
-
-      for (int i = 0; i < _DL_HWCAP_SIZE; ++i)
-       if (word & (1 << i))
-         _dl_printf (" %s", _dl_hwcap_string (i));
-      break;
-    case AT_HWCAP2:
-      {
-
-       _dl_printf ("AT_HWCAP2:           ");
-
-       /* We have to go through them all because the kernel added the
-	  AT_HWCAP2 features starting with the high bits.  */
-       for (int i = 0; i < _DL_HWCAP_SIZE; ++i)
-	 if (word & (1 << i))
-	   _dl_printf (" %s", _dl_hwcap_string (_DL_HWCAP2_OFFSET + i));
-       break;
-      }
-    case AT_HWCAP3:
-      {
-       _dl_printf ("AT_HWCAP3:           ");
-
-       /* We have to go through them all because the kernel added the
-	  AT_HWCAP3 features starting with the high bits.  */
-       for (int i = 0; i < _DL_HWCAP_SIZE; ++i)
-	 if (word & (1 << i))
-	   _dl_printf (" %s", _dl_hwcap_string (_DL_HWCAP3_OFFSET + i));
-       break;
-      }
-    case AT_HWCAP4:
-      {
-       _dl_printf ("AT_HWCAP4:           ");
-
-       /* We have to go through them all because the kernel added the
-	  AT_HWCAP4 features starting with the high bits.  */
-       for (int i = 0; i <= _DL_HWCAP_SIZE; ++i)
-	 if (word & (1 << i))
-	   _dl_printf (" %s", _dl_hwcap_string (_DL_HWCAP4_OFFSET + i));
-       break;
-      }
     case AT_L1I_CACHEGEOMETRY:
       {
 	cache_geometry ("AT_L1I_CACHEGEOMETRY: ", word);
diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile
index 24827efe79..cddb624bf2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/Makefile
+++ b/sysdeps/unix/sysv/linux/powerpc/Makefile
@@ -13,6 +13,10 @@ gen-as-const-headers += ucontext_i.sym
 endif
 
 ifeq ($(subdir),elf)
+dl-routines += \
+  dl-hwcap-info \
+  # dl-routines
+
 # Otherwise tst-tls-dlinfo fails due to tst-tlsmod2.so using static tls.
 ifeq ($(have-tls-get-addr-optimize),yes)
 LDFLAGS-tst-tlsmod2.so += -Wl,--no-tls-get-addr-optimize
diff --git a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
index bcce635763..f0fabac0e0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.c
@@ -21,9 +21,22 @@
 #include <cpu-features.h>
 #include <elf/dl-tunables.h>
 #include <dl-tunables-parse.h>
+#include <dl-hwcap-info.h>
 #include <unistd.h>
 #include <string.h>
 
+#define ENABLE_BIT(__hwcap, __v)        __hwcap &= (__v)
+#define DISABLE_BIT(__hwcap, __h, __v)  __hwcap |= (__h) & (__v)
+
+static void set_hwcap_bit (unsigned long int *hwcap, bool disable,
+			  unsigned long int tcb_value, unsigned int value)
+{
+  if (disable)
+    *hwcap &= ~value;
+  else
+    *hwcap |= tcb_value & value;
+}
+
 static void
 TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
 {
@@ -55,32 +68,27 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
 	continue;
 
       size_t offset = 0;
-      for (int i = 0; i < array_length (hwcap_tunables); ++i)
+      for (int i = 0; i < __dl_hwcap_info_size; ++i)
 	{
-	  const char *hwcap_name = hwcap_names + offset;
+	  const char *hwcap_name = __dl_hwcap_names + offset;
 	  size_t hwcap_name_len = strlen (hwcap_name);
 	  /* Check the tunable name on the supported list.  */
 	  if (tunable_str_comma_strcmp (&t, hwcap_name, hwcap_name_len))
 	    {
-	      /* Update the hwcap and hwcap2 bits.  */
-	      if (t.disable)
+	      switch (__dl_hwcap_info[i].hwcap)
 		{
-		  /* Id is 1 for hwcap2 tunable.  */
-		  if (hwcap_tunables[i].id)
-		    cpu_features->hwcap2 &= ~(hwcap_tunables[i].mask);
-		  else
-		    cpu_features->hwcap &= ~(hwcap_tunables[i].mask);
-		}
-	      else
-		{
-		  /* Enable the features and also check that no unsupported
-		     features were enabled by user.  */
-		  if (hwcap_tunables[i].id)
-		    cpu_features->hwcap2 |= (tcbv_hwcap2 & hwcap_tunables[i].mask);
-		  else
-		    cpu_features->hwcap |= (tcbv_hwcap & hwcap_tunables[i].mask);
+		case AT_HWCAP:
+		  set_hwcap_bit (&cpu_features->hwcap, t.disable, tcbv_hwcap,
+				 __dl_hwcap_info[i].value);
+		  break;
+
+		case AT_HWCAP2:
+		  set_hwcap_bit (&cpu_features->hwcap2, t.disable, tcbv_hwcap2,
+				 __dl_hwcap_info[i].value);
+		  break;
+
+		/* Ignore unknown values.  */
 		}
-	      break;
 	    }
 	  offset += hwcap_name_len + 1;
 	}
diff --git a/sysdeps/unix/sysv/linux/powerpc/cpu-features.h b/sysdeps/unix/sysv/linux/powerpc/cpu-features.h
index 3c5cc6e84d..f15a80374c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/cpu-features.h
+++ b/sysdeps/unix/sysv/linux/powerpc/cpu-features.h
@@ -30,103 +30,4 @@ struct cpu_features
   unsigned long int hwcap4;
 };
 
-static const char hwcap_names[] = {
-  "4xxmac\0"
-  "altivec\0"
-  "arch_2_05\0"
-  "arch_2_06\0"
-  "archpmu\0"
-  "booke\0"
-  "cellbe\0"
-  "dfp\0"
-  "efpdouble\0"
-  "efpsingle\0"
-  "fpu\0"
-  "ic_snoop\0"
-  "mmu\0"
-  "notb\0"
-  "pa6t\0"
-  "power4\0"
-  "power5\0"
-  "power5+\0"
-  "power6x\0"
-  "ppc32\0"
-  "ppc601\0"
-  "ppc64\0"
-  "ppcle\0"
-  "smt\0"
-  "spe\0"
-  "true_le\0"
-  "ucache\0"
-  "vsx\0"
-  "arch_2_07\0"
-  "dscr\0"
-  "ebb\0"
-  "htm\0"
-  "htm-nosc\0"
-  "htm-no-suspend\0"
-  "isel\0"
-  "tar\0"
-  "vcrypto\0"
-  "arch_3_00\0"
-  "ieee128\0"
-  "darn\0"
-  "scv\0"
-  "arch_3_1\0"
-  "mma\0"
-};
-
-static const struct
-{
-  unsigned int mask;
-  bool id;
-} hwcap_tunables[] = {
-   /* AT_HWCAP tunable masks.  */
-   { PPC_FEATURE_HAS_4xxMAC,                 0 },
-   { PPC_FEATURE_HAS_ALTIVEC,                0 },
-   { PPC_FEATURE_ARCH_2_05,                  0 },
-   { PPC_FEATURE_ARCH_2_06,                  0 },
-   { PPC_FEATURE_PSERIES_PERFMON_COMPAT,     0 },
-   { PPC_FEATURE_BOOKE,                      0 },
-   { PPC_FEATURE_CELL_BE,                    0 },
-   { PPC_FEATURE_HAS_DFP,                    0 },
-   { PPC_FEATURE_HAS_EFP_DOUBLE,             0 },
-   { PPC_FEATURE_HAS_EFP_SINGLE,             0 },
-   { PPC_FEATURE_HAS_FPU,                    0 },
-   { PPC_FEATURE_ICACHE_SNOOP,               0 },
-   { PPC_FEATURE_HAS_MMU,                    0 },
-   { PPC_FEATURE_NO_TB,                      0 },
-   { PPC_FEATURE_PA6T,                       0 },
-   { PPC_FEATURE_POWER4,                     0 },
-   { PPC_FEATURE_POWER5,                     0 },
-   { PPC_FEATURE_POWER5_PLUS,                0 },
-   { PPC_FEATURE_POWER6_EXT,                 0 },
-   { PPC_FEATURE_32,                         0 },
-   { PPC_FEATURE_601_INSTR,                  0 },
-   { PPC_FEATURE_64,                         0 },
-   { PPC_FEATURE_PPC_LE,                     0 },
-   { PPC_FEATURE_SMT,                        0 },
-   { PPC_FEATURE_HAS_SPE,                    0 },
-   { PPC_FEATURE_TRUE_LE,                    0 },
-   { PPC_FEATURE_UNIFIED_CACHE,              0 },
-   { PPC_FEATURE_HAS_VSX,                    0 },
-
-   /* AT_HWCAP2 tunable masks.  */
-   { PPC_FEATURE2_ARCH_2_07,                 1 },
-   { PPC_FEATURE2_HAS_DSCR,                  1 },
-   { PPC_FEATURE2_HAS_EBB,                   1 },
-   { PPC_FEATURE2_HAS_HTM,                   1 },
-   { PPC_FEATURE2_HTM_NOSC,                  1 },
-   { PPC_FEATURE2_HTM_NO_SUSPEND,            1 },
-   { PPC_FEATURE2_HAS_ISEL,                  1 },
-   { PPC_FEATURE2_HAS_TAR,                   1 },
-   { PPC_FEATURE2_HAS_VEC_CRYPTO,            1 },
-   { PPC_FEATURE2_ARCH_3_00,                 1 },
-   { PPC_FEATURE2_HAS_IEEE128,               1 },
-   { PPC_FEATURE2_DARN,                      1 },
-   { PPC_FEATURE2_SCV,                       1 },
-   { PPC_FEATURE2_ARCH_3_1,                  1 },
-   { PPC_FEATURE2_MMA,                       1 },
-};
-
 #endif /* __CPU_FEATURES_H  */
diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.c b/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.c
new file mode 100644
index 0000000000..1178828744
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.c
@@ -0,0 +1,117 @@
+/* HWCAP string information.  PowerPC version.
+   Copyright (C) 2017-2025 Free Software Foundation, Inc.
+
+   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/>.  */
+
+#include <array_length.h>
+#include <dl-hwcap-info.h>
+
+const char __dl_hwcap_names[] = {
+  "4xxmac\0"
+  "altivec\0"
+  "arch_2_05\0"
+  "arch_2_06\0"
+  "archpmu\0"
+  "booke\0"
+  "cellbe\0"
+  "dfp\0"
+  "efpdouble\0"
+  "efpsingle\0"
+  "fpu\0"
+  "ic_snoop\0"
+  "mmu\0"
+  "notb\0"
+  "pa6t\0"
+  "power4\0"
+  "power5\0"
+  "power5+\0"
+  "power6x\0"
+  "ppc32\0"
+  "ppc601\0"
+  "ppc64\0"
+  "ppcle\0"
+  "smt\0"
+  "spe\0"
+  "true_le\0"
+  "ucache\0"
+  "vsx\0"
+  "arch_2_07\0"
+  "dscr\0"
+  "ebb\0"
+  "htm\0"
+  "htm-nosc\0"
+  "htm-no-suspend\0"
+  "isel\0"
+  "tar\0"
+  "vcrypto\0"
+  "arch_3_00\0"
+  "ieee128\0"
+  "darn\0"
+  "scv\0"
+  "arch_3_1\0"
+  "mma\0"
+};
+
+const struct hwcap_info_t __dl_hwcap_info[] =
+{
+   /* AT_HWCAP tunable masks.  */
+   { PPC_FEATURE_HAS_4xxMAC,                 AT_HWCAP },
+   { PPC_FEATURE_HAS_ALTIVEC,                AT_HWCAP },
+   { PPC_FEATURE_ARCH_2_05,                  AT_HWCAP },
+   { PPC_FEATURE_ARCH_2_06,                  AT_HWCAP },
+   { PPC_FEATURE_PSERIES_PERFMON_COMPAT,     AT_HWCAP },
+   { PPC_FEATURE_BOOKE,                      AT_HWCAP },
+   { PPC_FEATURE_CELL_BE,                    AT_HWCAP },
+   { PPC_FEATURE_HAS_DFP,                    AT_HWCAP },
+   { PPC_FEATURE_HAS_EFP_DOUBLE,             AT_HWCAP },
+   { PPC_FEATURE_HAS_EFP_SINGLE,             AT_HWCAP },
+   { PPC_FEATURE_HAS_FPU,                    AT_HWCAP },
+   { PPC_FEATURE_ICACHE_SNOOP,               AT_HWCAP },
+   { PPC_FEATURE_HAS_MMU,                    AT_HWCAP },
+   { PPC_FEATURE_NO_TB,                      AT_HWCAP },
+   { PPC_FEATURE_PA6T,                       AT_HWCAP },
+   { PPC_FEATURE_POWER4,                     AT_HWCAP },
+   { PPC_FEATURE_POWER5,                     AT_HWCAP },
+   { PPC_FEATURE_POWER5_PLUS,                AT_HWCAP },
+   { PPC_FEATURE_POWER6_EXT,                 AT_HWCAP },
+   { PPC_FEATURE_32,                         AT_HWCAP },
+   { PPC_FEATURE_601_INSTR,                  AT_HWCAP },
+   { PPC_FEATURE_64,                         AT_HWCAP },
+   { PPC_FEATURE_PPC_LE,                     AT_HWCAP },
+   { PPC_FEATURE_SMT,                        AT_HWCAP },
+   { PPC_FEATURE_HAS_SPE,                    AT_HWCAP },
+   { PPC_FEATURE_TRUE_LE,                    AT_HWCAP },
+   { PPC_FEATURE_UNIFIED_CACHE,              AT_HWCAP },
+   { PPC_FEATURE_HAS_VSX,                    AT_HWCAP },
+
+   /* AT_HWCAP2 tunable masks.  */
+   { PPC_FEATURE2_ARCH_2_07,                 AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_DSCR,                  AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_EBB,                   AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_HTM,                   AT_HWCAP2 },
+   { PPC_FEATURE2_HTM_NOSC,                  AT_HWCAP2 },
+   { PPC_FEATURE2_HTM_NO_SUSPEND,            AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_ISEL,                  AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_TAR,                   AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_VEC_CRYPTO,            AT_HWCAP2 },
+   { PPC_FEATURE2_ARCH_3_00,                 AT_HWCAP2 },
+   { PPC_FEATURE2_HAS_IEEE128,               AT_HWCAP2 },
+   { PPC_FEATURE2_DARN,                      AT_HWCAP2 },
+   { PPC_FEATURE2_SCV,                       AT_HWCAP2 },
+   { PPC_FEATURE2_ARCH_3_1,                  AT_HWCAP2 },
+   { PPC_FEATURE2_MMA,                       AT_HWCAP2 },
+};
+
+size_t __dl_hwcap_info_size = array_length (__dl_hwcap_info);
diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.h b/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.h
new file mode 100644
index 0000000000..194f40ce4d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/dl-hwcap-info.h
@@ -0,0 +1,34 @@
+/* HWCAP string information.  PowerPC version.
+   Copyright (C) 2017-2025 Free Software Foundation, Inc.
+
+   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_HWCAP_INFO_H
+#define _DL_HWCAP_INFO_H
+
+#include <stddef.h>
+#include <sys/auxv.h>
+
+extern const char __dl_hwcap_names[] attribute_hidden;
+
+struct hwcap_info_t
+{
+  unsigned int value;
+  int hwcap;
+};
+extern const struct hwcap_info_t __dl_hwcap_info[] attribute_hidden;
+extern size_t __dl_hwcap_info_size attribute_hidden;
+
+#endif
