[RFC PATCH] readelf: Add -G/--got-contents options
H.J. Lu
hjl.tools@gmail.com
Tue Aug 26 21:53:40 GMT 2025
Add -G/--got-contents options to readelf, inspired by the similar option
on Solaris, to display the contents of GOT sections:
$ readelf -G libfoo.so
Global Offset Table '.got' contains 5 entries:
Index: Address Reloc Sym. Name + Addend/Value
0: 000000002fc8 R_X86_64_GLOB_DAT bar + 0
1: 000000002fd0 R_X86_64_GLOB_DAT __gmon_start__ + 0
2: 000000002fd8 R_X86_64_GLOB_DAT _ITM_registerTMCloneTable + 0
3: 000000002fe0 R_X86_64_GLOB_DAT __cxa_finalize@GLIBC_2.2.5 + 0
4: 000000002fe8 0
Global Offset Table '.got.plt' contains 4 entries:
Index: Address Reloc Sym. Name + Addend/Value
0: 000000002ff0 2dd0
1: 000000002ff8 0
2: 000000003000 R_X86_64_JUMP_SLO printf@GLIBC_2.2.5 + 2c0
3: 000000003008 0
Any comments?
H.J.
---
* NEWS: Mention "readelf -G/--got-contents".
* readelf.c (do_got_section_contents): New.
(elf_relocation): Likewise.
(all_relocations_root): Likewise.
(all_relocations): Likewise.
(all_relocations_count): Likewise.
(update_all_relocations): Likewise.
(dump_relr_relocations): Add a bool argument to indicate if
relocations should be displayed. Populate all_relocations if
do_got_section_contents is true.
(dump_relocations): Likewise.
(options): Add -G/--got-contents.
(usage): Show -G/--got-contents.
(parse_args): Support -G/--got-contents.
(display_relocations): Add bool argument, dump_reloc, to indicate
if relocations should be displayed. Call update_all_relocations.
Pass dump_reloc to dump_relr_relocations and dump_relocations.
(process_relocs): Check do_got_section_contents. Handle
do_got_section_contents for dynamic relocations.
(process_section_contents): Pass true to display_relocations.
(elf_relocation_cmp): New.
(display_elf_relocation_at): Likewise.
(process_got_section_contents): Likewise.
(process_object): Call process_got_section_contents.
* doc/binutils.texi: Document -G/--got-contents.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
binutils/NEWS | 3 +
binutils/doc/binutils.texi | 11 +-
binutils/readelf.c | 896 ++++++++++++++++++++++++++++++-------
3 files changed, 743 insertions(+), 167 deletions(-)
diff --git a/binutils/NEWS b/binutils/NEWS
index ccda8559897..9af862a4735 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,8 @@
-*- text -*-
+* Add -G/--got-contents options to readelf to display the contents of
+ Global Offset Table (GOT) sections.
+
* Internal changes to plugin support, and stricter target checking may result
in some errors being exposed in user options passed to the various binutils.
For example objcopy --target=TARGET now will only work if the input file is
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 4543341e00c..15f31d1bcef 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -5036,6 +5036,7 @@ readelf [@option{-a}|@option{--all}]
[@option{-h}|@option{--file-header}]
[@option{-l}|@option{--program-headers}|@option{--segments}]
[@option{-S}|@option{--section-headers}|@option{--sections}]
+ [@option{-G}|@option{--got-contents}]
[@option{-g}|@option{--section-groups}]
[@option{-t}|@option{--section-details}]
[@option{-e}|@option{--headers}]
@@ -5111,7 +5112,8 @@ given.
Equivalent to specifying @option{--file-header},
@option{--program-headers}, @option{--sections}, @option{--symbols},
@option{--relocs}, @option{--dynamic}, @option{--notes},
-@option{--version-info}, @option{--arch-specific}, @option{--unwind},
+@option{--got-contents}, @option{--version-info},
+@option{--arch-specific}, @option{--unwind},
@option{--section-groups} and @option{--histogram}.
Note - this option does not enable @option{--use-dynamic} itself, so
@@ -5143,6 +5145,13 @@ Suppress "no symbols" diagnostic.
Displays the information contained in the file's section headers, if it
has any.
+@item -G
+@itemx --got-contents
+@cindex ELF section information
+@cindex ELF reloc information
+Displays the contents of the file's Global Offset Table (GOT) sections,
+if it has any.
+
@item -g
@itemx --section-groups
@cindex ELF section group information
diff --git a/binutils/readelf.c b/binutils/readelf.c
index bb81c824ac3..53255c3e8ca 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -229,6 +229,7 @@ static bool do_dyn_syms = false;
static bool do_lto_syms = false;
static bool do_reloc = false;
static bool do_sections = false;
+static bool do_got_section_contents = false;
static bool do_section_groups = false;
static bool do_section_details = false;
static bool do_segments = false;
@@ -372,6 +373,21 @@ enum versioned_symbol_info
symbol_public
};
+/* Relocation entries */
+
+typedef struct elf_relocation
+{
+ bfd_vma r_offset; /* Location at which to apply the action */
+ bfd_vma r_addend; /* Constant addend used to compute value */
+ const char *r_name; /* Relocation name. */
+ char *r_symbol; /* Relocation symbol. */
+ relocation_type r_type; /* Relocation type. */
+} elf_relocation;
+
+static elf_relocation *all_relocations_root;
+static elf_relocation *all_relocations;
+static size_t all_relocations_count;
+
static int
fseek64 (FILE *stream, int64_t offset, int whence)
{
@@ -1767,6 +1783,32 @@ symcmp (const void *p, const void *q)
return sp->st_value > sq->st_value ? 1 : (sp->st_value < sq->st_value ? -1 : 0);
}
+static void
+update_all_relocations (size_t nentries)
+{
+ size_t sz;
+
+ if (!do_got_section_contents)
+ return;
+
+ if (!all_relocations_root)
+ {
+ sz = nentries * sizeof (elf_relocation);
+ all_relocations_root = (elf_relocation *) xmalloc (sz);
+ all_relocations = all_relocations_root;
+ all_relocations_count = nentries;
+ }
+ else
+ {
+ size_t orig_count = all_relocations_count;
+ sz = (orig_count + nentries) * sizeof (elf_relocation);
+ all_relocations_root = (elf_relocation *)
+ xrealloc (all_relocations_root, sz);
+ all_relocations = all_relocations_root + orig_count;
+ all_relocations_count += nentries;
+ }
+}
+
static uint64_t
count_relr_relocations (Filedata * filedata,
Elf_Internal_Shdr * section)
@@ -1836,7 +1878,8 @@ dump_relr_relocations (Filedata * filedata,
Elf_Internal_Sym * symtab,
uint64_t nsyms,
char * strtab,
- uint64_t strtablen)
+ uint64_t strtablen,
+ bool dump_reloc)
{
uint64_t * relrs;
uint64_t nentries, i;
@@ -1861,7 +1904,8 @@ dump_relr_relocations (Filedata * filedata,
num_bits_in_entry = 63;
else
{
- warn (_("Unexpected entsize for RELR section\n"));
+ if (dump_reloc)
+ warn (_("Unexpected entsize for RELR section\n"));
return false;
}
@@ -1875,6 +1919,161 @@ dump_relr_relocations (Filedata * filedata,
if (symtab == NULL)
nsyms = 0;
+ const char *rtype = NULL;
+ if (do_got_section_contents)
+ switch (filedata->file_header.e_machine)
+ {
+ default:
+ break;
+
+ case EM_386:
+ case EM_IAMCU:
+ rtype = "R_386_RELATIVE";
+ break;
+
+ case EM_860:
+ rtype = "R_860_RELATIVE";
+ break;
+
+ case EM_68K:
+ rtype = "R_68K_RELATIVE";
+ break;
+
+ case EM_AARCH64:
+ rtype = "R_AARCH64_RELATIVE";
+ break;
+
+ case EM_AMDGPU:
+ rtype = "R_AMDGPU_RELATIVE64";
+ break;
+
+ case EM_ALPHA:
+ rtype = "R_ALPHA_RELATIVE";
+ break;
+
+ case EM_ALTERA_NIOS2:
+ rtype = "R_NIOS2_RELATIVE";
+ break;
+
+ case EM_ARM:
+ rtype = "R_ARM_RELATIVE";
+ break;
+
+ case EM_ARC:
+ case EM_ARC_COMPACT:
+ case EM_ARC_COMPACT2:
+ case EM_ARC_COMPACT3:
+ case EM_ARC_COMPACT3_64:
+ rtype = "R_ARC_RELATIVE";
+ break;
+
+ case EM_CRIS:
+ rtype = "R_CRIS_RELATIVE";
+ break;
+
+ case EM_CSKY:
+ rtype = "R_CKCORE_RELATIVE";
+ break;
+
+ case EM_KVX:
+ rtype = "R_KVX_RELATIVE";
+ break;
+
+ case EM_LATTICEMICO32:
+ rtype = "R_LM32_RELATIVE";
+ break;
+
+ case EM_LOONGARCH:
+ rtype = "R_LARCH_RELATIVE";
+ break;
+
+ case EM_M32R:
+ case EM_CYGNUS_M32R:
+ rtype = "R_M32R_RELATIVE";
+ break;
+
+ case EM_MCORE:
+ rtype = "R_MCORE_RELATIVE";
+ break;
+
+ case EM_METAG:
+ rtype = "R_METAG_RELATIVE";
+ break;
+
+ case EM_MN10300:
+ case EM_CYGNUS_MN10300:
+ rtype = "R_MN10300_RELATIVE";
+ break;
+
+ case EM_NDS32:
+ rtype = "R_NDS32_RELATIVE";
+ break;
+
+ case EM_OR1K:
+ rtype = "R_OR1K_RELATIVE";
+ break;
+
+ case EM_PPC:
+ rtype = "R_PPC_RELATIVE";
+ break;
+
+ case EM_PPC64:
+ rtype = "R_PPC64_RELATIVE";
+ break;
+
+ case EM_RISCV:
+ rtype = "R_RISCV_RELATIVE";
+ break;
+
+ case EM_S370:
+ rtype = "R_I370_RELATIVE";
+ break;
+
+ case EM_S390_OLD:
+ case EM_S390:
+ rtype = "R_390_RELATIVE";
+ break;
+
+ case EM_SH:
+ rtype = "R_SH_RELATIVE";
+ break;
+
+ case EM_OLD_SPARCV9:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPARC:
+ rtype = "R_SPARC_RELATIVE";
+ break;
+
+ case EM_TILEGX:
+ rtype = "R_TILEGX_RELATIVE";
+ break;
+
+ case EM_TILEPRO:
+ rtype = "R_TILEPRO_RELATIVE";
+ break;
+
+ case EM_V850:
+ case EM_CYGNUS_V850:
+ rtype = "R_V850_RELATIVE";
+ break;
+
+ case EM_VAX:
+ rtype = "R_VAX_RELATIVE";
+ break;
+
+ case EM_X86_64:
+ case EM_L1OM:
+ case EM_K1OM:
+ rtype = "R_X86_64_RELATIVE";
+ break;
+
+ case EM_XTENSA_OLD:
+ case EM_XTENSA:
+ rtype = "R_XTENSA_RELATIVE";
+ break;
+ }
+
if (symtab != NULL)
{
/* Symbol tables are not sorted on address, but we want a quick lookup
@@ -1885,11 +2084,15 @@ dump_relr_relocations (Filedata * filedata,
nsyms = filter_display_syms (filedata, symtab, nsyms, strtab, strtablen);
}
- if (relr_entsize == sizeof (Elf32_External_Relr))
- printf (_ ("Index: Entry Address Symbolic Address\n"));
- else
- printf (_ ("Index: Entry Address Symbolic Address\n"));
+ if (dump_reloc)
+ {
+ if (relr_entsize == sizeof (Elf32_External_Relr))
+ printf (_ ("Index: Entry Address Symbolic Address\n"));
+ else
+ printf (_ ("Index: Entry Address Symbolic Address\n"));
+ }
+ uint64_t r = 0;
for (i = 0; i < nentries; i++)
{
uint64_t entry;
@@ -1899,16 +2102,34 @@ dump_relr_relocations (Filedata * filedata,
else
entry = BYTE_GET (((Elf64_External_Relr *)relrs)[i].r_data);
- /* We assume that there will never be more than 9999 entries. */
- printf (_("%04u: "), (unsigned int) i);
- print_vma (entry, ZERO_HEX);
- printf (" ");
+ if (dump_reloc)
+ {
+ /* We assume that there will never be more than 9999
+ entries. */
+ printf (_("%04u: "), (unsigned int) i);
+ print_vma (entry, ZERO_HEX);
+ printf (" ");
+ }
if ((entry & 1) == 0)
{
where = entry;
- print_relr_addr_and_sym (filedata, symtab, nsyms, strtab, where);
- printf ("\n");
+ if (dump_reloc)
+ {
+ print_relr_addr_and_sym (filedata, symtab, nsyms, strtab,
+ where);
+ printf ("\n");
+ }
+
+ if (do_got_section_contents)
+ {
+ all_relocations[r].r_offset = where;
+ all_relocations[r].r_name = rtype;
+ all_relocations[r].r_symbol = NULL;
+ all_relocations[r].r_type = reltype_relr;
+ r++;
+ }
+
where += relr_entsize;
}
else
@@ -1921,7 +2142,7 @@ dump_relr_relocations (Filedata * filedata,
/* This can actually happen when the linker is allowed to shrink
RELR sections. For more details see: https://reviews.llvm.org/D67164. */
continue;
- else if (i == 0)
+ else if (dump_reloc && i == 0)
warn (_("Unusual RELR bitmap - no previous entry to set the base address\n"));
for (j = 0; entry >>= 1; j++)
@@ -1929,19 +2150,35 @@ dump_relr_relocations (Filedata * filedata,
{
uint64_t addr = where + (j * relr_entsize);
- if (first)
+ if (dump_reloc)
{
- print_relr_addr_and_sym (filedata, symtab, nsyms, strtab, addr);
- first = false;
+ if (first)
+ {
+ print_relr_addr_and_sym (filedata, symtab, nsyms,
+ strtab, addr);
+ first = false;
+ }
+ else
+ {
+ printf (_("\n%*s "),
+ relr_entsize == 4 ? 15 : 23, " ");
+ print_relr_addr_and_sym (filedata, symtab, nsyms,
+ strtab, addr);
+ }
}
- else
+
+ if (do_got_section_contents)
{
- printf (_("\n%*s "), relr_entsize == 4 ? 15 : 23, " ");
- print_relr_addr_and_sym (filedata, symtab, nsyms, strtab, addr);
+ all_relocations[r].r_offset = addr;
+ all_relocations[r].r_name = rtype;
+ all_relocations[r].r_symbol = NULL;
+ all_relocations[r].r_type = reltype_relr;
+ r++;
}
}
- printf ("\n");
+ if (dump_reloc)
+ printf ("\n");
where += num_bits_in_entry * relr_entsize;
}
}
@@ -1962,7 +2199,8 @@ dump_relocations (Filedata * filedata,
char * strtab,
uint64_t strtablen,
relocation_type rel_type,
- bool is_dynsym)
+ bool is_dynsym,
+ bool dump_reloc)
{
size_t i;
Elf_Internal_Rela * rels;
@@ -1987,38 +2225,41 @@ dump_relocations (Filedata * filedata,
return false;
}
- if (is_32bit_elf)
+ if (dump_reloc)
{
- if (rel_type == reltype_rela)
- {
- if (do_wide)
- printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n"));
- else
- printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n"));
- }
- else
- {
- if (do_wide)
- printf (_(" Offset Info Type Sym. Value Symbol's Name\n"));
- else
- printf (_(" Offset Info Type Sym.Value Sym. Name\n"));
- }
- }
- else
- {
- if (rel_type == reltype_rela)
+ if (is_32bit_elf)
{
- if (do_wide)
- printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n"));
+ if (rel_type == reltype_rela)
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n"));
+ else
+ printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n"));
+ }
else
- printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n"));
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Sym. Value Symbol's Name\n"));
+ else
+ printf (_(" Offset Info Type Sym.Value Sym. Name\n"));
+ }
}
else
{
- if (do_wide)
- printf (_(" Offset Info Type Symbol's Value Symbol's Name\n"));
+ if (rel_type == reltype_rela)
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n"));
+ else
+ printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n"));
+ }
else
- printf (_(" Offset Info Type Sym. Value Sym. Name\n"));
+ {
+ if (do_wide)
+ printf (_(" Offset Info Type Symbol's Value Symbol's Name\n"));
+ else
+ printf (_(" Offset Info Type Sym. Value Sym. Name\n"));
+ }
}
}
@@ -2036,18 +2277,17 @@ dump_relocations (Filedata * filedata,
type = get_reloc_type (filedata, inf);
symtab_index = get_reloc_symindex (inf);
- if (is_32bit_elf)
- {
- printf ("%8.8lx %8.8lx ",
- (unsigned long) offset & 0xffffffff,
- (unsigned long) inf & 0xffffffff);
- }
- else
+ if (dump_reloc)
{
- printf (do_wide
- ? "%16.16" PRIx64 " %16.16" PRIx64 " "
- : "%12.12" PRIx64 " %12.12" PRIx64 " ",
- offset, inf);
+ if (is_32bit_elf)
+ printf ("%8.8lx %8.8lx ",
+ (unsigned long) offset & 0xffffffff,
+ (unsigned long) inf & 0xffffffff);
+ else
+ printf (do_wide
+ ? "%16.16" PRIx64 " %16.16" PRIx64 " "
+ : "%12.12" PRIx64 " %12.12" PRIx64 " ",
+ offset, inf);
}
switch (filedata->file_header.e_machine)
@@ -2397,10 +2637,15 @@ dump_relocations (Filedata * filedata,
break;
}
- if (rtype == NULL)
- printf (_("unrecognized: %-7lx"), (unsigned long) type & 0xffffffff);
- else
- printf (do_wide ? "%-22s" : "%-17.17s", rtype);
+ char *symbol_name = NULL;
+ if (dump_reloc)
+ {
+ if (rtype == NULL)
+ printf (_("unrecognized: %-7lx"),
+ (unsigned long) type & 0xffffffff);
+ else
+ printf (do_wide ? "%-22s" : "%-17.17s", rtype);
+ }
if (filedata->file_header.e_machine == EM_ALPHA
&& rtype != NULL
@@ -2419,23 +2664,29 @@ dump_relocations (Filedata * filedata,
default: rtype = NULL;
}
- if (rtype)
- printf (" (%s)", rtype);
- else
+ if (dump_reloc)
{
- putchar (' ');
- printf (_("<unknown addend: %" PRIx64 ">"),
- rels[i].r_addend);
- res = false;
+ if (rtype)
+ printf (" (%s)", rtype);
+ else
+ {
+ putchar (' ');
+ printf (_("<unknown addend: %" PRIx64 ">"),
+ rels[i].r_addend);
+ res = false;
+ }
}
}
else if (symtab_index)
{
if (symtab == NULL || symtab_index >= nsyms)
{
- error (_(" bad symbol index: %08lx in reloc\n"),
- (unsigned long) symtab_index);
- res = false;
+ if (dump_reloc)
+ {
+ error (_(" bad symbol index: %08lx in reloc\n"),
+ (unsigned long) symtab_index);
+ res = false;
+ }
}
else
{
@@ -2454,7 +2705,8 @@ dump_relocations (Filedata * filedata,
&sym_info,
&vna_other);
- printf (" ");
+ if (dump_reloc)
+ printf (" ");
if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
{
@@ -2479,13 +2731,30 @@ dump_relocations (Filedata * filedata,
else
name = strtab + psym->st_name;
- len = print_symbol_name (width, name);
- if (version_string)
- printf (sym_info == symbol_public ? "@@%s" : "@%s",
- version_string);
- printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
+ if (do_got_section_contents)
+ {
+ if (version_string)
+ symbol_name = concat (name,
+ sym_info == symbol_public
+ ? "@@" : "@",
+ version_string, NULL);
+ else
+ symbol_name = xstrdup (name);
+ }
+
+ if (dump_reloc)
+ {
+ len = print_symbol_name (width, name);
+ if (version_string)
+ printf (sym_info == symbol_public
+ ? "@@%s" : "@%s",
+ version_string);
+ printf ("()%-*s",
+ len <= width ? (width + 1) - len : 1,
+ " ");
+ }
}
- else
+ else if (dump_reloc)
{
print_vma (psym->st_value, LONG_HEX);
@@ -2500,25 +2769,49 @@ dump_relocations (Filedata * filedata,
sec_name = printable_section_name_from_index
(filedata, psym->st_shndx, NULL);
- print_symbol_name (22, sec_name);
+ if (do_got_section_contents)
+ symbol_name = xstrdup (sec_name);
+ if (dump_reloc)
+ print_symbol_name (22, sec_name);
}
else if (strtab == NULL)
- printf (_("<string table index: %3ld>"), psym->st_name);
+ {
+ if (dump_reloc)
+ printf (_("<string table index: %3ld>"),
+ psym->st_name);
+ }
else if (psym->st_name >= strtablen)
{
- error (_("<corrupt string table index: %3ld>\n"),
- psym->st_name);
- res = false;
+ if (dump_reloc)
+ {
+ error (_("<corrupt string table index: %3ld>\n"),
+ psym->st_name);
+ res = false;
+ }
}
else
{
- print_symbol_name (22, strtab + psym->st_name);
- if (version_string)
- printf (sym_info == symbol_public ? "@@%s" : "@%s",
- version_string);
+ if (dump_reloc)
+ {
+ print_symbol_name (22, strtab + psym->st_name);
+ if (version_string)
+ printf (sym_info == symbol_public
+ ? "@@%s" : "@%s",
+ version_string);
+ }
+ if (all_relocations)
+ {
+ if (version_string)
+ symbol_name = concat (strtab + psym->st_name,
+ sym_info == symbol_public
+ ? "@@" : "@",
+ version_string, NULL);
+ else
+ symbol_name = xstrdup (strtab + psym->st_name);
+ }
}
- if (rel_type == reltype_rela)
+ if (dump_reloc && rel_type == reltype_rela)
{
uint64_t off = rels[i].r_addend;
@@ -2529,7 +2822,7 @@ dump_relocations (Filedata * filedata,
}
}
}
- else if (rel_type == reltype_rela)
+ else if (dump_reloc && rel_type == reltype_rela)
{
uint64_t off = rels[i].r_addend;
@@ -2540,37 +2833,50 @@ dump_relocations (Filedata * filedata,
printf ("%" PRIx64, off);
}
- if (filedata->file_header.e_machine == EM_SPARCV9
- && rtype != NULL
- && streq (rtype, "R_SPARC_OLO10"))
- printf (" + %" PRIx64, ELF64_R_TYPE_DATA (inf));
-
- putchar ('\n');
+ if (do_got_section_contents)
+ {
+ all_relocations[i].r_offset = offset;
+ all_relocations[i].r_name = rtype;
+ all_relocations[i].r_symbol = symbol_name;
+ all_relocations[i].r_addend = rels[i].r_addend;
+ all_relocations[i].r_type = rel_type;
+ }
- if (! is_32bit_elf && filedata->file_header.e_machine == EM_MIPS)
+ if (dump_reloc)
{
- uint64_t type2 = ELF64_MIPS_R_TYPE2 (inf);
- uint64_t type3 = ELF64_MIPS_R_TYPE3 (inf);
- const char * rtype2 = elf_mips_reloc_type (type2);
- const char * rtype3 = elf_mips_reloc_type (type3);
+ if (filedata->file_header.e_machine == EM_SPARCV9
+ && rtype != NULL
+ && streq (rtype, "R_SPARC_OLO10"))
+ printf (" + %" PRIx64, ELF64_R_TYPE_DATA (inf));
- printf (" Type2: ");
+ putchar ('\n');
- if (rtype2 == NULL)
- printf (_("unrecognized: %-7lx"),
- (unsigned long) type2 & 0xffffffff);
- else
- printf ("%-17.17s", rtype2);
+ if (! is_32bit_elf
+ && filedata->file_header.e_machine == EM_MIPS)
+ {
+ uint64_t type2 = ELF64_MIPS_R_TYPE2 (inf);
+ uint64_t type3 = ELF64_MIPS_R_TYPE3 (inf);
+ const char * rtype2 = elf_mips_reloc_type (type2);
+ const char * rtype3 = elf_mips_reloc_type (type3);
- printf ("\n Type3: ");
+ printf (" Type2: ");
- if (rtype3 == NULL)
- printf (_("unrecognized: %-7lx"),
- (unsigned long) type3 & 0xffffffff);
- else
- printf ("%-17.17s", rtype3);
+ if (rtype2 == NULL)
+ printf (_("unrecognized: %-7lx"),
+ (unsigned long) type2 & 0xffffffff);
+ else
+ printf ("%-17.17s", rtype2);
- putchar ('\n');
+ printf ("\n Type3: ");
+
+ if (rtype3 == NULL)
+ printf (_("unrecognized: %-7lx"),
+ (unsigned long) type3 & 0xffffffff);
+ else
+ printf ("%-17.17s", rtype3);
+
+ putchar ('\n');
+ }
}
}
@@ -6112,6 +6418,7 @@ static struct option options[] =
{"use-dynamic", no_argument, 0, 'D'},
{"dynamic", no_argument, 0, 'd'},
{"headers", no_argument, 0, 'e'},
+ {"got-contents", no_argument, 0, 'G'},
{"section-groups", no_argument, 0, 'g'},
{"help", no_argument, 0, 'H'},
{"file-header", no_argument, 0, 'h'},
@@ -6184,6 +6491,8 @@ usage (FILE * stream)
fprintf (stream, _("\
--sections An alias for --section-headers\n"));
fprintf (stream, _("\
+ -G --got Display GOT section contents\n"));
+ fprintf (stream, _("\
-g --section-groups Display the section groups\n"));
fprintf (stream, _("\
-t --section-details Display the section details\n"));
@@ -6418,7 +6727,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
usage (stderr);
while ((c = getopt_long
- (argc, argv, "ACDHILNPR:STU:VWXacdeghi:j:lnp:rstuvw::x:z", options, NULL)) != EOF)
+ (argc, argv, "ACDGHILNPR:STU:VWXacdeghi:j:lnp:rstuvw::x:z", options, NULL)) != EOF)
{
switch (c)
{
@@ -6442,8 +6751,13 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
do_histogram = true;
do_arch = true;
do_notes = true;
+ do_got_section_contents = true;
break;
+ case 'G':
+ do_got_section_contents = true;
+ do_dump = true;
+ break;
case 'g':
do_section_groups = true;
break;
@@ -9438,7 +9752,8 @@ rel_type_from_sh_type (unsigned int sh_type)
static bool
display_relocations (Elf_Internal_Shdr * section,
- Filedata * filedata)
+ Filedata * filedata,
+ bool dump_reloc)
{
relocation_type rel_type = rel_type_from_sh_type (section->sh_type);
@@ -9450,19 +9765,23 @@ display_relocations (Elf_Internal_Shdr * section,
if (rel_size == 0)
return false;
- if (filedata->is_separate)
- printf (_("\nIn linked file '%s' relocation section "),
- printable_string (filedata->file_name, 0));
- else
- printf (_("\nRelocation section "));
+ if (dump_reloc)
+ {
+ if (filedata->is_separate)
+ printf (_("\nIn linked file '%s' relocation section "),
+ printable_string (filedata->file_name, 0));
+ else
+ printf (_("\nRelocation section "));
- if (filedata->string_table == NULL)
- printf ("%d", section->sh_name);
- else
- printf ("'%s'", printable_section_name (filedata, section));
+ if (filedata->string_table == NULL)
+ printf ("%d", section->sh_name);
+ else
+ printf ("'%s'", printable_section_name (filedata, section));
+ }
- uint64_t num_rela = rel_size / section->sh_entsize;
uint64_t rel_offset = section->sh_offset;
+ uint64_t num_rela = rel_size / section->sh_entsize;
+ uint64_t num_reloc;
if (rel_type == reltype_relr)
{
@@ -9471,26 +9790,33 @@ display_relocations (Elf_Internal_Shdr * section,
the number of words in the compressed RELR format. So also provide
the number of locations affected. */
- uint64_t num_reloc = count_relr_relocations (filedata, section);
+ num_reloc = count_relr_relocations (filedata, section);
- printf (_(" at offset %#" PRIx64), rel_offset);
- printf (ngettext (" contains %" PRIu64 " entry which relocates",
- " contains %" PRIu64 " entries which relocate",
- num_rela), num_rela);
- printf (ngettext (" %" PRIu64 " location:\n",
- " %" PRIu64 " locations:\n",
- num_reloc), num_reloc);
+ if (dump_reloc)
+ {
+ printf (_(" at offset %#" PRIx64), rel_offset);
+ printf (ngettext (" contains %" PRIu64 " entry which relocates",
+ " contains %" PRIu64 " entries which relocate",
+ num_rela), num_rela);
+ printf (ngettext (" %" PRIu64 " location:\n",
+ " %" PRIu64 " locations:\n",
+ num_reloc), num_reloc);
+ }
}
else
{
- printf (ngettext (" at offset %#" PRIx64
- " contains %" PRIu64 " entry:\n",
- " at offset %#" PRIx64
- " contains %" PRIu64 " entries:\n",
- num_rela),
- rel_offset, num_rela);
+ num_reloc = num_rela;
+ if (dump_reloc)
+ printf (ngettext (" at offset %#" PRIx64
+ " contains %" PRIu64 " entry:\n",
+ " at offset %#" PRIx64
+ " contains %" PRIu64 " entries:\n",
+ num_rela),
+ rel_offset, num_rela);
}
+ update_all_relocations (num_reloc);
+
Elf_Internal_Shdr * symsec;
Elf_Internal_Sym * symtab = NULL;
uint64_t nsyms = 0;
@@ -9522,12 +9848,15 @@ display_relocations (Elf_Internal_Shdr * section,
bool res;
if (rel_type == reltype_relr)
- res = dump_relr_relocations (filedata, section, symtab, nsyms, strtab, strtablen);
+ res = dump_relr_relocations (filedata, section, symtab, nsyms,
+ strtab, strtablen, dump_reloc);
else
res = dump_relocations (filedata, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen,
rel_type,
- symsec == NULL ? false : symsec->sh_type == SHT_DYNSYM);
+ symsec == NULL
+ ? false : symsec->sh_type == SHT_DYNSYM,
+ dump_reloc);
free (strtab);
free (symtab);
@@ -9541,14 +9870,16 @@ process_relocs (Filedata * filedata)
{
uint64_t rel_size;
uint64_t rel_offset;
+ unsigned int rel_entsz;
- if (!do_reloc)
+ if (!do_reloc && !do_got_section_contents)
return true;
if (do_using_dynamic)
{
relocation_type rel_type;
const char * name;
+ const char * entsz_name;
bool has_dynamic_reloc;
unsigned int i;
@@ -9556,57 +9887,97 @@ process_relocs (Filedata * filedata)
for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
{
+ rel_size = filedata->dynamic_info[dynamic_relocations [i].size];
+
+ if (!rel_size)
+ continue;
+
+ has_dynamic_reloc = true;
+
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];
- if (rel_size)
- has_dynamic_reloc = true;
-
if (rel_type == reltype_unknown)
{
- if (dynamic_relocations [i].reloc == DT_JMPREL)
- switch (filedata->dynamic_info[DT_PLTREL])
- {
- case DT_REL:
- rel_type = reltype_rel;
- break;
- case DT_RELA:
- rel_type = reltype_rela;
- break;
- }
+ if (dynamic_relocations [i].reloc != DT_JMPREL)
+ abort ();
+
+ switch (filedata->dynamic_info[DT_PLTREL])
+ {
+ default:
+ printf (_("<missing dynamic or corrupt tag: DT_PLTREL>\n"));
+ continue;
+ case DT_REL:
+ rel_type = reltype_rel;
+ break;
+ case DT_RELA:
+ rel_type = reltype_rela;
+ break;
+ }
}
- if (rel_size)
+ switch (rel_type)
+ {
+ default:
+ abort ();
+ case reltype_rel:
+ rel_entsz = filedata->dynamic_info[DT_RELENT];
+ entsz_name = "DT_RELENT";
+ break;
+ case reltype_rela:
+ rel_entsz = filedata->dynamic_info[DT_RELAENT];
+ entsz_name = "DT_RELAENT";
+ break;
+ case reltype_relr:
+ rel_entsz = filedata->dynamic_info[DT_RELRENT];
+ entsz_name = "DT_RELRENT";
+ break;
+ }
+
+ if (do_reloc)
{
if (filedata->is_separate)
printf
- (_("\nIn linked file '%s' section '%s' at offset %#" PRIx64
- " contains %" PRId64 " bytes:\n"),
+ (_("\nIn linked file '%s' section '%s' at offset"
+ "%#" PRIx64 " contains %" PRId64 " bytes:\n"),
filedata->file_name, name, rel_offset, rel_size);
else
printf
(_("\n'%s' relocation section at offset %#" PRIx64
" contains %" PRId64 " bytes:\n"),
name, rel_offset, rel_size);
+ }
+
+ if (rel_type != reltype_relr)
+ {
+ if (rel_entsz == 0)
+ {
+ printf (_("<missing or corrupt dynamic tag: %s>\n"),
+ entsz_name);
+ continue;
+ }
+
+ update_all_relocations (rel_size / rel_entsz);
dump_relocations (filedata,
- offset_from_vma (filedata, rel_offset, rel_size),
+ offset_from_vma (filedata, rel_offset,
+ rel_size),
rel_size,
filedata->dynamic_symbols,
filedata->num_dynamic_syms,
filedata->dynamic_strings,
filedata->dynamic_strings_length,
- rel_type, true /* is_dynamic */);
+ rel_type, true /* is_dynamic */,
+ do_reloc);
}
}
if (is_ia64_vms (filedata))
- if (process_ia64_vms_dynamic_relocs (filedata))
+ if (process_ia64_vms_dynamic_relocs (filedata))
has_dynamic_reloc = true;
- if (! has_dynamic_reloc)
+ if (do_reloc && ! has_dynamic_reloc)
{
if (filedata->is_separate)
printf (_("\nThere are no dynamic relocations in linked file '%s'.\n"),
@@ -9625,11 +9996,11 @@ process_relocs (Filedata * filedata)
i < filedata->file_header.e_shnum;
i++, section++)
{
- if (display_relocations (section, filedata))
+ if (display_relocations (section, filedata, do_reloc))
found = true;
}
- if (! found)
+ if (do_reloc && ! found)
{
/* Users sometimes forget the -D option, so try to be helpful. */
for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++)
@@ -17613,7 +17984,7 @@ process_section_contents (Filedata * filedata)
case SHT_RELA:
case SHT_REL:
case SHT_RELR:
- res &= display_relocations (section, filedata);
+ res &= display_relocations (section, filedata, true);
break;
case SHT_NOTE:
@@ -17704,6 +18075,196 @@ process_section_contents (Filedata * filedata)
return res;
}
+static int
+elf_relocation_cmp (const void *p, const void *q)
+{
+ elf_relocation *rp = (elf_relocation *) p;
+ elf_relocation *rq = (elf_relocation *) q;
+
+ return (rp->r_offset > rq->r_offset
+ ? 1
+ : (rp->r_offset < rq->r_offset ? -1 : 0));
+}
+
+static void
+display_elf_relocation_at (uint64_t offset, uint64_t g)
+{
+ bool matched = false;
+
+ for (size_t i = 0; i < all_relocations_count; i++)
+ if (all_relocations_root[i].r_offset == offset)
+ {
+ if (do_wide)
+ printf (" %-22s", all_relocations_root[i].r_name);
+ else
+ printf (" %-17.17s", all_relocations_root[i].r_name);
+
+ uint64_t off;
+ switch (all_relocations_root[i].r_type)
+ {
+ default:
+ abort ();
+ case reltype_rel:
+ case reltype_relr:
+ off = g;
+ break;
+ case reltype_rela:
+ off = all_relocations_root[i].r_addend;
+ break;
+ }
+
+ if (all_relocations_root[i].r_symbol)
+ {
+ printf (" %s", all_relocations_root[i].r_symbol);
+ if ((int64_t) off < 0)
+ printf (" - %" PRIx64, -off);
+ else
+ printf (" + %" PRIx64, off);
+ }
+ else
+ {
+ if ((int64_t) off < 0)
+ printf (" -%" PRIx64, -off);
+ else
+ printf (" %" PRIx64, off);
+ }
+
+ matched = true;
+ break;
+ }
+ else if (all_relocations_root[i].r_offset > offset)
+ break;
+
+ if (!matched)
+ {
+ if (do_wide)
+ printf ("%*c", 24, ' ');
+ else
+ printf ("%*c", 19, ' ');
+ printf ("%" PRIx64, g);
+ }
+}
+
+static bool
+process_got_section_contents (Filedata * filedata)
+{
+ Elf_Internal_Shdr * section;
+ unsigned int i;
+ uint64_t entries;
+ unsigned char *data;
+ bool res = true;
+
+ if (! do_got_section_contents)
+ return res;
+
+ qsort (all_relocations_root, all_relocations_count,
+ sizeof (elf_relocation), elf_relocation_cmp);
+
+ initialise_dumps_byname (filedata);
+
+ for (i = 0, section = filedata->section_headers;
+ i < filedata->file_header.e_shnum;
+ i++, section++)
+ if (section->sh_type == SHT_PROGBITS
+ && section->sh_size != 0)
+ {
+ const char *name = printable_section_name (filedata, section);
+
+ if (!startswith (name, ".got"))
+ continue;
+
+ data = (unsigned char *) get_section_contents (section,
+ filedata);
+ if (data == NULL)
+ {
+ res = false;
+ goto out;
+ }
+
+ uint32_t entsz = section->sh_entsize;
+ entries = section->sh_size / entsz;
+ if (entries == 1)
+ printf (_("\nGlobal Offset Table '%s' contains 1 entry:\n"),
+ name);
+ else
+ printf (_("\nGlobal Offset Table '%s' contains %" PRIu64
+ " entries:\n"), name, entries);
+
+ uint64_t g;
+
+ if (is_32bit_elf)
+ {
+ uint32_t j, n = entries;
+ uint32_t addr;
+ struct got32
+ {
+ unsigned char bytes[4];
+ } *got;
+
+ if (do_wide)
+ printf (_(" Index: Address Reloc Sym. Name + Addend/Value\n"));
+ /* |---9---| |---8--| |---------22---------| |........... */
+ else
+ printf (_(" Index: Address Reloc Sym. Name + Addend/Value\n"));
+ /* |--7--| |---8--| |-------17------| |........... */
+ addr = section->sh_addr;
+ got = (struct got32 *) data;
+
+ for (j = 0; j < n; j++)
+ {
+ addr += entsz;
+ g = BYTE_GET (got[j].bytes);
+ if (do_wide)
+ printf ("%8" PRIu32 ": %8.8" PRIx32, j, addr);
+ else
+ printf ("%6" PRIu32 ": %8.8" PRIx32, j, addr);
+ display_elf_relocation_at (addr, g);
+ putchar ('\n');
+ }
+ }
+ else
+ {
+ uint64_t j, addr;
+ struct got64
+ {
+ unsigned char bytes[4];
+ } *got;
+
+ if (do_wide)
+ printf (_(" Index: Address Reloc Sym. Name + Addend/Value\n"));
+ /* |---9---| |------16------| |---------22---------| |........... */
+ else
+ printf (_(" Index: Address Reloc Sym. Name + Addend/Value\n"));
+ /* |--7--| |----12----| |------17-------| |........... */
+
+ addr = section->sh_addr;
+ got = (struct got64 *) data;
+ for (j = 0; j < entries; j++)
+ {
+ addr += entsz;
+ g = BYTE_GET (got[j].bytes);
+ if (do_wide)
+ printf ("%8" PRIu64 ": %16.16" PRIx64, j, addr);
+ else
+ printf ("%6" PRIu64 ": %12.12" PRIx64, j, addr);
+ display_elf_relocation_at (addr, g);
+ putchar ('\n');
+ }
+ }
+
+ free (data);
+ }
+
+ out:
+ for (size_t j = 0; j < all_relocations_count; j++)
+ free (all_relocations_root[j].r_symbol);
+ free (all_relocations_root);
+ all_relocations_root = NULL;
+ all_relocations = NULL;
+ all_relocations_count = 0;
+ return res;
+}
+
static void
process_mips_fpe_exception (int mask)
{
@@ -23819,6 +24380,9 @@ process_object (Filedata * filedata)
if (! process_section_contents (filedata))
res = false;
+ if (! process_got_section_contents (filedata))
+ res = false;
+
if (have_separate_files)
{
separate_info * d;
--
2.51.0
More information about the Binutils
mailing list