aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2021-11-16 13:03:57 -0800
committerFangrui Song <maskray@google.com>2021-11-16 13:04:33 -0800
commita7fd11862703e45d2774981a4888bc127d473b06 (patch)
tree6caa5fcbd7a7b71a0b6ab895a2bf9a4a00193fa9 /binutils
parent830070c66d25e6749b7159009f1d87d85f02eaa3 (diff)
downloadbinutils-a7fd11862703e45d2774981a4888bc127d473b06.zip
binutils-a7fd11862703e45d2774981a4888bc127d473b06.tar.gz
binutils-a7fd11862703e45d2774981a4888bc127d473b06.tar.bz2
readelf: Support SHT_RELR/DT_RELR for -r
The -r output for SHT_RELR looks like: Relocation section '.relr.dyn' at offset 0x530 contains 4 entries: 7 offsets 00000000000028c0 00000000000028c8 0000000000003ad0 0000000000003ad8 0000000000003ae0 0000000000003ae8 0000000000003af0 For --use-dynamic, the header looks like 'RELR' relocation section at offset 0x530 contains 32 bytes: include/ * elf/common.h (DT_ENCODING): Bump to 38. * elf/external.h (Elf32_External_Relr): New. (Elf64_External_Relr): New. binutils/ * readelf.c (enum relocation_type): New. (slurp_relr_relocs): New. (dump_relocations): Change is_rela to rel_type. Dump RELR. (dynamic_relocations): Add DT_RELR. (process_relocs): Check SHT_RELR and DT_RELR. (process_dynamic_section): Store into dynamic_info for DT_RELR/DT_RELRENT/DT_RELRSZ.
Diffstat (limited to 'binutils')
-rw-r--r--binutils/ChangeLog11
-rw-r--r--binutils/NEWS2
-rw-r--r--binutils/readelf.c154
3 files changed, 138 insertions, 29 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 6850edb..8d2f041 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,14 @@
+2021-11-16 Fangrui Song <maskray@google.com>
+
+ * readelf.c (enum relocation_type): New.
+ (slurp_relr_relocs): New.
+ (dump_relocations): Change is_rela to rel_type.
+ Dump RELR.
+ (dynamic_relocations): Add DT_RELR.
+ (process_relocs): Check SHT_RELR and DT_RELR.
+ (process_dynamic_section): Store into dynamic_info for
+ DT_RELR/DT_RELRENT/DT_RELRSZ.
+
2021-11-09 Nick Clifton <nickc@redhat.com>
* nm.c: Add --unicode option to control how unicode characters are
diff --git a/binutils/NEWS b/binutils/NEWS
index f948d34..f388125 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -11,6 +11,8 @@
using --unicode=highlight will display them as unicode escape sequences
highlighted in red (if supported by the output device).
+* readelf -r dumps RELR relative relocations now.
+
Changes in 2.37:
* The readelf tool has a new command line option which can be used to specify
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 19c6491..116f879 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -342,7 +342,14 @@ typedef enum unicode_display_type
static unicode_display_type unicode_display = unicode_default;
-
+typedef enum
+{
+ reltype_unknown,
+ reltype_rel,
+ reltype_rela,
+ reltype_relr
+} relocation_type;
+
/* Versioned symbol info. */
enum versioned_symbol_info
{
@@ -1354,6 +1361,76 @@ slurp_rel_relocs (Filedata * filedata,
return true;
}
+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;
+}
+
/* Returns the reloc type extracted from the reloc info field. */
static unsigned int
@@ -1406,30 +1483,46 @@ dump_relocations (Filedata * filedata,
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
- int is_rela,
+ relocation_type rel_type,
bool is_dynsym)
{
unsigned long i;
Elf_Internal_Rela * rels;
bool res = true;
- if (is_rela == UNKNOWN)
- is_rela = guess_is_rela (filedata->file_header.e_machine);
+ if (rel_type == reltype_unknown)
+ rel_type = guess_is_rela (filedata->file_header.e_machine) ? reltype_rela : reltype_rel;
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (!slurp_rela_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
return false;
}
- else
+ else if (rel_type == reltype_rel)
{
if (!slurp_rel_relocs (filedata, rel_offset, rel_size, &rels, &rel_size))
return false;
}
+ else if (rel_type == reltype_relr)
+ {
+ bfd_vma * relrs;
+ const char *format
+ = is_32bit_elf ? "%08" BFD_VMA_FMT "x\n" : "%016" BFD_VMA_FMT "x\n";
+
+ if (!slurp_relr_relocs (filedata, rel_offset, rel_size, &relrs,
+ &rel_size))
+ return false;
+
+ printf (ngettext (" %lu offset\n", " %lu offsets\n", rel_size), rel_size);
+ for (i = 0; i < rel_size; i++)
+ printf (format, relrs[i]);
+ free (relrs);
+ return true;
+ }
if (is_32bit_elf)
{
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (do_wide)
printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n"));
@@ -1446,7 +1539,7 @@ dump_relocations (Filedata * filedata,
}
else
{
- if (is_rela)
+ if (rel_type == reltype_rela)
{
if (do_wide)
printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n"));
@@ -1841,7 +1934,7 @@ dump_relocations (Filedata * filedata,
if (filedata->file_header.e_machine == EM_ALPHA
&& rtype != NULL
&& streq (rtype, "R_ALPHA_LITUSE")
- && is_rela)
+ && rel_type == reltype_rela)
{
switch (rels[i].r_addend)
{
@@ -1989,7 +2082,7 @@ dump_relocations (Filedata * filedata,
version_string);
}
- if (is_rela)
+ if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
@@ -2000,7 +2093,7 @@ dump_relocations (Filedata * filedata,
}
}
}
- else if (is_rela)
+ else if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
@@ -8021,13 +8114,14 @@ static struct
const char * name;
int reloc;
int size;
- int rela;
+ relocation_type rel_type;
}
dynamic_relocations [] =
{
- { "REL", DT_REL, DT_RELSZ, false },
- { "RELA", DT_RELA, DT_RELASZ, true },
- { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN }
+ { "REL", DT_REL, DT_RELSZ, reltype_rel },
+ { "RELA", DT_RELA, DT_RELASZ, reltype_rela },
+ { "RELR", DT_RELR, DT_RELRSZ, reltype_relr },
+ { "PLT", DT_JMPREL, DT_PLTRELSZ, reltype_unknown }
};
/* Process the reloc section. */
@@ -8043,7 +8137,7 @@ process_relocs (Filedata * filedata)
if (do_using_dynamic)
{
- int is_rela;
+ relocation_type rel_type;
const char * name;
bool has_dynamic_reloc;
unsigned int i;
@@ -8052,7 +8146,7 @@ process_relocs (Filedata * filedata)
for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
{
- is_rela = dynamic_relocations [i].rela;
+ rel_type = dynamic_relocations [i].rel_type;
name = dynamic_relocations [i].name;
rel_size = filedata->dynamic_info[dynamic_relocations [i].size];
rel_offset = filedata->dynamic_info[dynamic_relocations [i].reloc];
@@ -8060,16 +8154,16 @@ process_relocs (Filedata * filedata)
if (rel_size)
has_dynamic_reloc = true;
- if (is_rela == UNKNOWN)
+ if (rel_type == reltype_unknown)
{
if (dynamic_relocations [i].reloc == DT_JMPREL)
switch (filedata->dynamic_info[DT_PLTREL])
{
case DT_REL:
- is_rela = false;
+ rel_type = reltype_rel;
break;
case DT_RELA:
- is_rela = true;
+ rel_type = reltype_rela;
break;
}
}
@@ -8092,7 +8186,7 @@ process_relocs (Filedata * filedata)
filedata->num_dynamic_syms,
filedata->dynamic_strings,
filedata->dynamic_strings_length,
- is_rela, true /* is_dynamic */);
+ rel_type, true /* is_dynamic */);
}
}
@@ -8120,7 +8214,8 @@ process_relocs (Filedata * filedata)
i++, section++)
{
if ( section->sh_type != SHT_RELA
- && section->sh_type != SHT_REL)
+ && section->sh_type != SHT_REL
+ && section->sh_type != SHT_RELR)
continue;
rel_offset = section->sh_offset;
@@ -8128,7 +8223,7 @@ process_relocs (Filedata * filedata)
if (rel_size)
{
- int is_rela;
+ relocation_type rel_type;
unsigned long num_rela;
if (filedata->is_separate)
@@ -8148,7 +8243,8 @@ process_relocs (Filedata * filedata)
num_rela),
rel_offset, num_rela);
- is_rela = section->sh_type == SHT_RELA;
+ rel_type = section->sh_type == SHT_RELA ? reltype_rela :
+ section->sh_type == SHT_REL ? reltype_rel : reltype_relr;
if (section->sh_link != 0
&& section->sh_link < filedata->file_header.e_shnum)
@@ -8170,15 +8266,14 @@ process_relocs (Filedata * filedata)
dump_relocations (filedata, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen,
- is_rela,
+ rel_type,
symsec->sh_type == SHT_DYNSYM);
free (strtab);
free (symtab);
}
else
dump_relocations (filedata, rel_offset, rel_size,
- NULL, 0, NULL, 0, is_rela,
- false /* is_dynamic */);
+ NULL, 0, NULL, 0, rel_type, false /* is_dynamic */);
found = true;
}
@@ -11499,6 +11594,7 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
case DT_RPATH :
case DT_SYMBOLIC:
case DT_REL :
+ case DT_RELR :
case DT_DEBUG :
case DT_TEXTREL :
case DT_JMPREL :
@@ -11555,6 +11651,8 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
case DT_STRSZ :
case DT_RELSZ :
case DT_RELAENT :
+ case DT_RELRENT :
+ case DT_RELRSZ :
case DT_SYMENT :
case DT_RELENT :
filedata->dynamic_info[entry->d_tag] = entry->d_un.d_val;
@@ -11562,8 +11660,6 @@ the .dynstr section doesn't match the DT_STRTAB and DT_STRSZ tags\n"));
case DT_PLTPADSZ:
case DT_MOVEENT :
case DT_MOVESZ :
- case DT_RELRENT :
- case DT_RELRSZ :
case DT_PREINIT_ARRAYSZ:
case DT_INIT_ARRAYSZ:
case DT_FINI_ARRAYSZ: