| 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 |
| |