Add support for IRELATIVE relocations.
That's the second part of the IFUNC support. So far x86 and x86-64
only.
diff --git a/src/readelf.c b/src/readelf.c
index 1c79065..9ce4604 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -211,9 +211,11 @@
static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
static void print_scngrp (Ebl *ebl);
static void print_dynamic (Ebl *ebl, GElf_Ehdr *ehdr);
-static void print_relocs (Ebl *ebl);
-static void handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
-static void handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
+static void print_relocs (Ebl *ebl, GElf_Ehdr *ehdr);
+static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+ GElf_Shdr *shdr);
+static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
+ GElf_Shdr *shdr);
static void print_symtab (Ebl *ebl, int type);
static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
static void print_verinfo (Ebl *ebl);
@@ -652,7 +654,7 @@
if (print_dynamic_table)
print_dynamic (ebl, ehdr);
if (print_relocations)
- print_relocs (pure_ebl);
+ print_relocs (pure_ebl, ehdr);
if (print_histogram)
handle_hash (ebl);
if (print_symbol_table)
@@ -1449,7 +1451,7 @@
/* Print relocations. */
static void
-print_relocs (Ebl *ebl)
+print_relocs (Ebl *ebl, GElf_Ehdr *ehdr)
{
/* Find all relocation sections and handle them. */
Elf_Scn *scn = NULL;
@@ -1463,9 +1465,9 @@
if (likely (shdr != NULL))
{
if (shdr->sh_type == SHT_REL)
- handle_relocs_rel (ebl, scn, shdr);
+ handle_relocs_rel (ebl, ehdr, scn, shdr);
else if (shdr->sh_type == SHT_RELA)
- handle_relocs_rela (ebl, scn, shdr);
+ handle_relocs_rela (ebl, ehdr, scn, shdr);
}
}
}
@@ -1473,7 +1475,7 @@
/* Handle a relocation section. */
static void
-handle_relocs_rel (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
{
int class = gelf_getclass (ebl->elf);
int nentries = shdr->sh_size / shdr->sh_entsize;
@@ -1545,6 +1547,7 @@
Offset Type Value Name\n"),
stdout);
+ int is_statically_linked = 0;
for (int cnt = 0; cnt < nentries; ++cnt)
{
GElf_Rel relmem;
@@ -1558,16 +1561,56 @@
GELF_R_SYM (rel->r_info),
&symmem, &xndx);
if (unlikely (sym == NULL))
- printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
- class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
- /* Avoid the leading R_ which isn't carrying any
- information. */
- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
- buf, sizeof (buf)) + 2
- : gettext ("<INVALID RELOC>"),
- gettext ("INVALID SYMBOL"),
- (long int) GELF_R_SYM (rel->r_info));
+ {
+ /* As a special case we have to handle relocations in static
+ executables. This only happens for IRELATIVE relocations
+ (so far). There is no symbol table. */
+ if (is_statically_linked == 0)
+ {
+ /* Find the program header and look for a PT_INTERP entry. */
+ is_statically_linked = -1;
+ if (ehdr->e_type == ET_EXEC)
+ {
+ is_statically_linked = 1;
+
+ for (size_t inner = 0; inner < ehdr->e_phnum; ++inner)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
+ &phdr_mem);
+ if (phdr != NULL && phdr->p_type == PT_INTERP)
+ {
+ is_statically_linked = -1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_statically_linked > 0 && shdr->sh_link == 0)
+ printf ("\
+ %#0*" PRIx64 " %-20s %*s %s\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ else
+ printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ gettext ("INVALID SYMBOL"),
+ (long int) GELF_R_SYM (rel->r_info));
+ }
else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
printf (" %#0*" PRIx64 " %-20s %#0*" PRIx64 " %s\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
@@ -1618,7 +1661,7 @@
/* Handle a relocation section. */
static void
-handle_relocs_rela (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
+handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
{
int class = gelf_getclass (ebl->elf);
int nentries = shdr->sh_size / shdr->sh_entsize;
@@ -1676,6 +1719,7 @@
Offset Type Value Addend Name\n"),
stdout);
+ int is_statically_linked = 0;
for (int cnt = 0; cnt < nentries; ++cnt)
{
GElf_Rela relmem;
@@ -1690,16 +1734,57 @@
&symmem, &xndx);
if (unlikely (sym == NULL))
- printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
- class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
- /* Avoid the leading R_ which isn't carrying any
- information. */
- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
- buf, sizeof (buf)) + 2
- : gettext ("<INVALID RELOC>"),
- gettext ("INVALID SYMBOL"),
- (long int) GELF_R_SYM (rel->r_info));
+ {
+ /* As a special case we have to handle relocations in static
+ executables. This only happens for IRELATIVE relocations
+ (so far). There is no symbol table. */
+ if (is_statically_linked == 0)
+ {
+ /* Find the program header and look for a PT_INTERP entry. */
+ is_statically_linked = -1;
+ if (ehdr->e_type == ET_EXEC)
+ {
+ is_statically_linked = 1;
+
+ for (size_t inner = 0; inner < ehdr->e_phnum; ++inner)
+ {
+ GElf_Phdr phdr_mem;
+ GElf_Phdr *phdr = gelf_getphdr (ebl->elf, inner,
+ &phdr_mem);
+ if (phdr != NULL && phdr->p_type == PT_INTERP)
+ {
+ is_statically_linked = -1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (is_statically_linked > 0 && shdr->sh_link == 0)
+ printf ("\
+ %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " %s\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ rel->r_addend,
+ elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ else
+ printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ gettext ("INVALID SYMBOL"),
+ (long int) GELF_R_SYM (rel->r_info));
+ }
else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
printf ("\
%#0*" PRIx64 " %-15s %#0*" PRIx64 " %+6" PRId64 " %s\n",