This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Adding a MIPS GOT dump to readelf -A
- From: Richard Sandiford <rsandifo at nildram dot co dot uk>
- To: binutils at sourceware dot org
- Date: Wed, 19 Mar 2008 21:36:48 +0000
- Subject: Adding a MIPS GOT dump to readelf -A
IRIX elfdump had a nice GOT-dumping option, and I've often wanted
something similar for GNU/Linux. Here's an attempt to add it to
"readelf -A". Example output for an n32 /bin/ls:
Primary GOT:
Canonical gp value: 10030610
Reserved entries:
Address Access Initial Purpose
10028620 -32752(gp) 00000000 Lazy resolver
10028624 -32748(gp) 80000000 Module pointer (GNU extension)
Local entries:
Address Access Initial
10028628 -32744(gp) 10001c70
1002862c -32740(gp) 10001d10
10028630 -32736(gp) 10013c60
10028634 -32732(gp) 10010000
10028638 -32728(gp) 10028000
1002863c -32724(gp) 10028900
10028640 -32720(gp) 00000000
10028644 -32716(gp) 00000000
10028648 -32712(gp) 00000000
1002864c -32708(gp) 00000000
10028650 -32704(gp) 00000000
10028654 -32700(gp) 00000000
Global entries:
Address Access Initial Sym.Val. Type Ndx Name
10028658 -32696(gp) 1000a128 1000a128 FUNC 11 gnu_mbswidth
1002865c -32692(gp) 10001b90 10001b90 FUNC 10 _init
10028660 -32688(gp) 10007bc0 10007bc0 FUNC 11 main
10028664 -32684(gp) 1000e0d0 1000e0d0 FUNC 11 get_quoting_style
10028668 -32680(gp) 1000b200 1000b200 FUNC 11 rpl_gettimeofday
1002866c -32676(gp) 10028904 10028904 OBJECT 24 program_name
10028670 -32672(gp) 10011470 10011470 FUNC 11 xstrtoumax
10028674 -32668(gp) 10014130 10014130 FUNC UND exit
10028678 -32664(gp) 10010e98 10010e98 FUNC 11 xmemdup
...
AFAIK, GNU ld always generates GOTs in which Initial == Sym.Val.;
we never use lazy binding for locally-defined-but-not-locally-binding
functions. (I think we should unless -z now is passed. Thoughts?)
But printing both is useful for prelinked objects.
Most of this is straightforward. The only two major decisions were:
- What should we print in the Access field for entries outside the
16-bit range? This can occur for XGOTs, but it can also -- arguably
more often -- occur for entries in normal GOTs that are only used for
dynamic relocations. (The latter case includes multi-GOT objects.)
Although a 32-bit offset is legitimate macro syntax, it isn't what
you'd see in a disassembly dump, and I think it would be a little
confusing. You already have to do a bit of work to piece together
XGOT addresses, so I think the Address column would be enough for
them.
I've therefore just left these fields blank for _gp+32768 onwards.
- Should "narrow" n64 output use two lines for each entry, or print
one line that's longer than 80 characters instead? I experimented
with both, and even though I religiously use 80-character terminals,
I found the latter much easier to read. It's also what we do
for --symbols on n64.
Tested on mips{,64}{,el}-linux-gnu and mips64{,el}-elf. OK to install?
Richard
binutils/
* readelf.c (print_mips_got_entry): New function.
(process_mips_specific): Print GOT information.
ld/testsuite/
* ld-mips-elf/got-dump-1.d, ld-mips-elf/got-dump-1.s,
ld-mips-elf/got-dump-1.ld, ld-mips-elf/got-dump-2.d,
ld-mips-elf/got-dump-2.s, ld-mips-elf/got-dump-2.ld: New tests.
* ld-mips-elf/mips-elf.exp: Run them.
Index: binutils/readelf.c
===================================================================
--- binutils/readelf.c 2008-03-19 19:30:55.000000000 +0000
+++ binutils/readelf.c 2008-03-19 21:00:59.000000000 +0000
@@ -9125,6 +9125,33 @@ process_power_specific (FILE *file)
display_power_gnu_attribute);
}
+/* DATA points to the contents of a MIPS GOT that starts at VMA PLTGOT.
+ Print the Address, Access and Initial fields of an entry at VMA ADDR
+ and return the VMA of the next entry. */
+
+static bfd_vma
+print_mips_got_entry (unsigned char *data, bfd_vma pltgot, bfd_vma addr)
+{
+ printf (" ");
+ print_vma (addr, LONG_HEX);
+ printf (" ");
+ if (addr < pltgot + 0xfff0)
+ printf ("%6d(gp)", (int) (addr - pltgot - 0x7ff0));
+ else
+ printf ("%10s", "");
+ printf (" ");
+ if (data == NULL)
+ printf ("%*s", is_32bit_elf ? 8 : 16, "<unknown>");
+ else
+ {
+ bfd_vma entry;
+
+ entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+ print_vma (entry, LONG_HEX);
+ }
+ return addr + (is_32bit_elf ? 4 : 8);
+}
+
static int
process_mips_specific (FILE *file)
{
@@ -9134,6 +9161,10 @@ process_mips_specific (FILE *file)
size_t conflictsno = 0;
size_t options_offset = 0;
size_t conflicts_offset = 0;
+ bfd_vma pltgot = 0;
+ bfd_vma local_gotno = 0;
+ bfd_vma gotsym = 0;
+ bfd_vma symtabno = 0;
process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
display_mips_gnu_attribute);
@@ -9165,6 +9196,17 @@ process_mips_specific (FILE *file)
case DT_MIPS_CONFLICTNO:
conflictsno = entry->d_un.d_val;
break;
+ case DT_PLTGOT:
+ pltgot = entry->d_un.d_val;
+ case DT_MIPS_LOCAL_GOTNO:
+ local_gotno = entry->d_un.d_val;
+ break;
+ case DT_MIPS_GOTSYM:
+ gotsym = entry->d_un.d_val;
+ break;
+ case DT_MIPS_SYMTABNO:
+ symtabno = entry->d_un.d_val;
+ break;
default:
break;
}
@@ -9515,6 +9557,87 @@ process_mips_specific (FILE *file)
free (iconf);
}
+ if (pltgot != 0 && local_gotno != 0)
+ {
+ bfd_vma entry, local_end, global_end;
+ size_t addr_size, i, offset;
+ unsigned char *data;
+
+ entry = pltgot;
+ addr_size = (is_32bit_elf ? 4 : 8);
+ local_end = pltgot + local_gotno * addr_size;
+ global_end = local_end + (symtabno - gotsym) * addr_size;
+
+ offset = offset_from_vma (file, pltgot, global_end - pltgot);
+ data = get_data (NULL, file, offset, global_end - pltgot, 1, _("GOT"));
+ printf (_("\nPrimary GOT:\n"));
+ printf (_(" Canonical gp value: "));
+ print_vma (pltgot + 0x7ff0, LONG_HEX);
+ printf ("\n\n");
+
+ printf (_(" Reserved entries:\n"));
+ printf (_(" %*s %10s %*s Purpose\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial");
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" Lazy resolver\n");
+ if (data
+ && (byte_get (data + entry - pltgot, addr_size)
+ >> (addr_size * 8 - 1)) != 0)
+ {
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" Module pointer (GNU extension)\n");
+ }
+ printf ("\n");
+
+ if (entry < local_end)
+ {
+ printf (_(" Local entries:\n"));
+ printf (_(" %*s %10s %*s\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial");
+ while (entry < local_end)
+ {
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf ("\n");
+ }
+ printf ("\n");
+ }
+
+ if (gotsym < symtabno)
+ {
+ int sym_width;
+
+ printf (_(" Global entries:\n"));
+ printf (_(" %*s %10s %*s %*s %-7s %3s %s\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial",
+ addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name");
+ sym_width = (is_32bit_elf ? 80 : 160) - 28 - addr_size * 6 - 1;
+ for (i = gotsym; i < symtabno; i++)
+ {
+ Elf_Internal_Sym *psym;
+
+ psym = dynamic_symbols + i;
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" ");
+ print_vma (psym->st_value, LONG_HEX);
+ printf (" %-7s %3s ",
+ get_symbol_type (ELF_ST_TYPE (psym->st_info)),
+ get_symbol_index_type (psym->st_shndx));
+ if (VALID_DYNAMIC_NAME (psym->st_name))
+ print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
+ else
+ printf ("<corrupt: %14ld>", psym->st_name);
+ printf ("\n");
+ }
+ printf ("\n");
+ }
+
+ if (data)
+ free (data);
+ }
+
return 1;
}
Index: ld/testsuite/ld-mips-elf/got-dump-1.d
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-1.d 2008-03-19 19:32:34.000000000 +0000
@@ -0,0 +1,25 @@
+#name: GOT dump (readelf -A) test 1
+#source: got-dump-1.s
+#as: -mips3
+#ld: -Tgot-dump-1.ld -shared
+#readelf: -A
+
+Primary GOT:
+ Canonical gp value: 00068000
+
+ Reserved entries:
+ Address Access Initial Purpose
+ 00060010 -32752\(gp\) 00000000 Lazy resolver
+ 00060014 -32748\(gp\) 80000000 Module pointer \(GNU extension\)
+
+ Local entries:
+ Address Access Initial
+ 00060018 -32744\(gp\) 00060000
+ 0006001c -32740\(gp\) 00060004
+
+ Global entries:
+ Address Access Initial Sym.Val. Type Ndx Name
+ 00060020 -32736\(gp\) 00050020 00050020 FUNC UND extern
+ 00060024 -32732\(gp\) 00000000 00000000 NOTYPE UND undef
+ 00060028 -32728\(gp\) 00050000 00050000 FUNC 7 glob
+
Index: ld/testsuite/ld-mips-elf/got-dump-1.s
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-1.s 2008-03-19 19:32:34.000000000 +0000
@@ -0,0 +1,22 @@
+ .global glob
+ .ent glob
+glob:
+ lw $4,%got(local)($28)
+ addiu $4,$4,%lo(local)
+ lw $4,%got(hidden)($28)
+ lw $4,%call16(glob)($28)
+ lw $4,%call16(extern)($28)
+ .end glob
+
+ .data
+ .type local,%object
+ .size local,4
+local:
+ .word undef
+
+ .globl hidden
+ .hidden hidden
+ .type hidden,%object
+ .size hidden,4
+hidden:
+ .word 0
Index: ld/testsuite/ld-mips-elf/got-dump-1.ld
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-1.ld 2008-03-19 19:32:34.000000000 +0000
@@ -0,0 +1,19 @@
+SECTIONS
+{
+ . = 0x40000;
+ .reginfo : { *(.reginfo) }
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : { *(.rel.dyn) }
+
+ . = 0x50000;
+ .text : { *(.text) }
+ .MIPS.stubs : { *(.MIPS.stubs) }
+
+ . = 0x60000;
+ .data : { *(.data) }
+ _gp = ALIGN (16) + 0x7ff0;
+ .got : { *(.got) }
+}
Index: ld/testsuite/ld-mips-elf/got-dump-2.d
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-2.d 2008-03-19 19:42:31.000000000 +0000
@@ -0,0 +1,25 @@
+#name: GOT dump (readelf -A) test 2
+#source: got-dump-2.s
+#as: -mips3 -EB -64
+#ld: -Tgot-dump-2.ld -shared -melf64btsmip
+#readelf: -A
+
+Primary GOT:
+ Canonical gp value: 0001236000008000
+
+ Reserved entries:
+ Address Access Initial Purpose
+ 0001236000000010 -32752\(gp\) 0000000000000000 Lazy resolver
+ 0001236000000018 -32744\(gp\) 8000000000000000 Module pointer \(GNU extension\)
+
+ Local entries:
+ Address Access Initial
+ 0001236000000020 -32736\(gp\) 0001236000000000
+ 0001236000000028 -32728\(gp\) 0001236000000008
+
+ Global entries:
+ Address Access Initial Sym.Val. Type Ndx Name
+ 0001236000000030 -32720\(gp\) 0001235000000020 0001235000000020 FUNC UND extern
+ 0001236000000038 -32712\(gp\) 0000000000000000 0000000000000000 NOTYPE UND undef
+ 0001236000000040 -32704\(gp\) 0001235000000000 0001235000000000 FUNC 7 glob
+
Index: ld/testsuite/ld-mips-elf/got-dump-2.s
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-2.s 2008-03-19 19:32:34.000000000 +0000
@@ -0,0 +1,22 @@
+ .global glob
+ .ent glob
+glob:
+ ld $4,%got_page(local)($28)
+ daddiu $4,$4,%got_ofst(local)
+ ld $4,%got_disp(hidden)($28)
+ ld $4,%call16(glob)($28)
+ ld $4,%call16(extern)($28)
+ .end glob
+
+ .data
+ .type local,%object
+ .size local,8
+local:
+ .dword undef
+
+ .globl hidden
+ .hidden hidden
+ .type hidden,%object
+ .size hidden,8
+hidden:
+ .dword 0
Index: ld/testsuite/ld-mips-elf/got-dump-2.ld
===================================================================
--- /dev/null 2008-03-17 07:04:11.552097000 +0000
+++ ld/testsuite/ld-mips-elf/got-dump-2.ld 2008-03-19 19:41:40.000000000 +0000
@@ -0,0 +1,18 @@
+SECTIONS
+{
+ . = 0x1234000000000;
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.dyn : { *(.rel.dyn) }
+
+ . = 0x1235000000000;
+ .text : { *(.text) }
+ .MIPS.stubs : { *(.MIPS.stubs) }
+
+ . = 0x1236000000000;
+ .data : { *(.data) }
+ _gp = ALIGN (16) + 0x7ff0;
+ .got : { *(.got) }
+}
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- ld/testsuite/ld-mips-elf/mips-elf.exp 2008-03-19 19:30:55.000000000 +0000
+++ ld/testsuite/ld-mips-elf/mips-elf.exp 2008-03-19 19:42:21.000000000 +0000
@@ -156,6 +156,10 @@ if { $linux_gnu } {
run_dump_test "got-page-2"
}
run_dump_test "got-page-3"
+ run_dump_test "got-dump-1"
+ if $has_newabi {
+ run_dump_test "got-dump-2"
+ }
}
if $has_newabi {