blob: 64970f6cbfdecd782ef977341d1aad58f0704145 [file] [log] [blame]
From 206f10ae698a3dacca03816ebedd2cd5757d7102 Mon Sep 17 00:00:00 2001
From: Fangrui Song <maskray@google.com>
Date: Tue, 16 Nov 2021 13:03:57 -0800
Subject: [PATCH 15/17] 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.
---
binutils/readelf.c | 153 +++++++++++++++++++++++++++++++++--------
include/elf/common.h | 2 +-
include/elf/external.h | 8 +++
3 files changed, 134 insertions(+), 29 deletions(-)
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 92c817ce31c..0bece24a2f6 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -321,6 +321,14 @@ typedef enum print_mode
}
print_mode;
+typedef enum
+{
+ reltype_unknown,
+ reltype_rel,
+ reltype_rela,
+ reltype_relr
+} relocation_type;
+
/* Versioned symbol info. */
enum versioned_symbol_info
{
@@ -1162,6 +1170,76 @@ slurp_rel_relocs (Filedata * filedata,
return TRUE;
}
+static bfd_boolean
+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
@@ -1214,30 +1292,46 @@ dump_relocations (Filedata * filedata,
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
- int is_rela,
+ relocation_type rel_type,
bfd_boolean is_dynsym)
{
unsigned long i;
Elf_Internal_Rela * rels;
bfd_boolean 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"));
@@ -1254,7 +1348,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"));
@@ -1644,7 +1738,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)
{
@@ -1790,7 +1884,7 @@ dump_relocations (Filedata * filedata,
version_string);
}
- if (is_rela)
+ if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
@@ -1801,7 +1895,7 @@ dump_relocations (Filedata * filedata,
}
}
}
- else if (is_rela)
+ else if (rel_type == reltype_rela)
{
bfd_vma off = rels[i].r_addend;
@@ -7534,13 +7628,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. */
@@ -7556,7 +7651,7 @@ process_relocs (Filedata * filedata)
if (do_using_dynamic)
{
- int is_rela;
+ relocation_type rel_type;
const char * name;
bfd_boolean has_dynamic_reloc;
unsigned int i;
@@ -7565,7 +7660,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];
@@ -7573,16 +7668,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;
}
}
@@ -7600,7 +7695,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 */);
}
}
@@ -7622,7 +7717,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;
@@ -7630,7 +7726,7 @@ process_relocs (Filedata * filedata)
if (rel_size)
{
- int is_rela;
+ relocation_type rel_type;
unsigned long num_rela;
printf (_("\nRelocation section "));
@@ -7646,7 +7742,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)
@@ -7668,15 +7765,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, TRUE /* is_dynamic */);
found = TRUE;
}
@@ -10954,6 +11050,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 :
@@ -11009,6 +11106,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;
@@ -11016,8 +11115,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:
diff --git a/include/elf/common.h b/include/elf/common.h
index d3eb81194fd..6745a45e774 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -1024,13 +1024,13 @@
#define DT_FINI_ARRAYSZ 28
#define DT_RUNPATH 29
#define DT_FLAGS 30
-#define DT_ENCODING 32
#define DT_PREINIT_ARRAY 32
#define DT_PREINIT_ARRAYSZ 33
#define DT_SYMTAB_SHNDX 34
#define DT_RELRSZ 35
#define DT_RELR 36
#define DT_RELRENT 37
+#define DT_ENCODING 38
/* Note, the Oct 4, 1999 draft of the ELF ABI changed the values
for DT_LOOS and DT_HIOS. Some implementations however, use
diff --git a/include/elf/external.h b/include/elf/external.h
index b24985687e6..815e39c2837 100644
--- a/include/elf/external.h
+++ b/include/elf/external.h
@@ -211,6 +211,10 @@ typedef struct {
unsigned char r_addend[4]; /* Constant addend used to compute value */
} Elf32_External_Rela;
+typedef struct {
+ unsigned char r_data[4]; /* RELR entry */
+} Elf32_External_Relr;
+
typedef struct {
unsigned char r_offset[8]; /* Location at which to apply the action */
unsigned char r_info[8]; /* index and type of relocation */
@@ -222,6 +226,10 @@ typedef struct {
unsigned char r_addend[8]; /* Constant addend used to compute value */
} Elf64_External_Rela;
+typedef struct {
+ unsigned char r_data[8]; /* RELR entry */
+} Elf64_External_Relr;
+
/* dynamic section structure */
typedef struct {
--
2.34.1