+static bool
+slurp_relr_relocs (Filedata * filedata,
+ unsigned long relr_offset,
+ unsigned long relr_size,
+ bfd_vma ** relrsp,
+ unsigned long * nrelrsp)
+{
+ void *relrs;
+ size_t size = 0, nentries, i;
+ bfd_vma base = 0, addr, entry;
+
+ relrs = get_data (NULL, filedata, relr_offset, 1, relr_size,
+ _("RELR relocation data"));
+ if (!relrs)
+ return false;
+
+ if (is_32bit_elf)
+ nentries = relr_size / sizeof (Elf32_External_Relr);
+ else
+ nentries = relr_size / sizeof (Elf64_External_Relr);
+ for (i = 0; i < nentries; i++)
+ {
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ size++;
+ else
+ while ((entry >>= 1) != 0)
+ if ((entry & 1) == 1)
+ size++;
+ }
+
+ *relrsp = (bfd_vma *) xmalloc (size * sizeof (bfd_vma));
+ if (*relrsp == NULL)
+ {
+ free (relrs);
+ error (_("out of memory parsing relocs\n"));
+ return false;
+ }
+
+ size = 0;
+ for (i = 0; i < nentries; i++)
+ {
+ const bfd_vma entry_bytes = is_32bit_elf ? 4 : 8;
+
+ if (is_32bit_elf)
+ entry = BYTE_GET (((Elf32_External_Relr *)relrs)[i].r_data);
+ else
+ entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
+ if ((entry & 1) == 0)
+ {
+ (*relrsp)[size++] = entry;
+ base = entry + entry_bytes;
+ }
+ else
+ {
+ for (addr = base; (entry >>= 1) != 0; addr += entry_bytes)
+ if ((entry & 1) != 0)
+ (*relrsp)[size++] = addr;
+ base += entry_bytes * (entry_bytes * CHAR_BIT - 1);
+ }
+ }
+
+ *nrelrsp = size;
+ free (relrs);
+ return true;
+}
+