Display symbol version when dumping dynrelocs

Both readelf/objdump know how to get symbol version string for dynamic
symbols.  This patch extracts this functionality into a separate
function and uses it to add symbol version string to versioned symbol
names when dumping dynamic relocations.

bfd/

	PR binutils/16496
	* elf-bfd.h (bfd_elf_get_symbol_version_string): New.
	* elf.c (bfd_elf_get_symbol_version_string): New.  Extracted
	from bfd_elf_print_symbol.
	(bfd_elf_print_symbol): Use it.

binutils/

	PR binutils/16496
	* objdump.c (objdump_print_symname): Call
	bfd_elf_get_symbol_version_string to get ELF symbol version
	string.  Append version string if needed.

	* readelf.c (versioned_symbol_info): New enum.
	(get_symbol_version_string): New.  Extracted from
	process_symbol_table.
	(dump_relocations): Add a new argument to indicate if dynamic
	symbol table is used.  Use get_symbol_version_string to get
	symbol version string for dynamic symbol.  Append version string
	if needed.
	(process_relocs): Updated dump_relocations call.
	(process_symbol_table): Use get_symbol_version_string.

ld/testsuite/

	PR binutils/16496
	* ld-cris/weakref3.d: Add symbol version string to versioned
	symbol names in dynamic relocation.
	* ld-cris/weakref4.d: Likewise.
	* ld-elfvers/vers24.rd: Likewise.

	* ld-elf/pr16496a.c: New file.
	* ld-elf/pr16496a.map: Likewise.
	* ld-elf/pr16496b.c: Likewise.
	* ld-elf/pr16496b.od: Likewise.

	* ld-elf/shared.exp (build_tests): Add libpr16496a.so and
	libpr16496b.so tests.
This commit is contained in:
H.J. Lu 2014-11-25 06:47:44 -08:00
parent dd7e64d45b
commit bb4d2ac2cc
15 changed files with 378 additions and 206 deletions

View file

@ -1,3 +1,11 @@
2014-11-25 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/16496
* elf-bfd.h (bfd_elf_get_symbol_version_string): New.
* elf.c (bfd_elf_get_symbol_version_string): New. Extracted
from bfd_elf_print_symbol.
(bfd_elf_print_symbol): Use it.
2014-11-25 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_got_plt_entry): New.

View file

@ -1772,6 +1772,8 @@ extern bfd_boolean _bfd_elf_copy_private_bfd_data
(bfd *, bfd *);
extern bfd_boolean _bfd_elf_print_private_bfd_data
(bfd *, void *);
const char * bfd_elf_get_symbol_version_string
(bfd *, asymbol *, bfd_boolean *);
extern void bfd_elf_print_symbol
(bfd *, void *, asymbol *, bfd_print_symbol_type);

View file

@ -1422,6 +1422,53 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
return FALSE;
}
/* Get version string. */
const char *
bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
bfd_boolean *hidden)
{
const char *version_string = NULL;
if (elf_dynversym (abfd) != 0
&& (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0))
{
unsigned int vernum = ((elf_symbol_type *) symbol)->version;
*hidden = (vernum & VERSYM_HIDDEN) != 0;
vernum &= VERSYM_VERSION;
if (vernum == 0)
version_string = "";
else if (vernum == 1)
version_string = "Base";
else if (vernum <= elf_tdata (abfd)->cverdefs)
version_string =
elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
else
{
Elf_Internal_Verneed *t;
version_string = "";
for (t = elf_tdata (abfd)->verref;
t != NULL;
t = t->vn_nextref)
{
Elf_Internal_Vernaux *a;
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
if (a->vna_other == vernum)
{
version_string = a->vna_nodename;
break;
}
}
}
}
}
return version_string;
}
/* Display ELF-specific fields of a symbol. */
void
@ -1448,6 +1495,8 @@ bfd_elf_print_symbol (bfd *abfd,
const struct elf_backend_data *bed;
unsigned char st_other;
bfd_vma val;
const char *version_string;
bfd_boolean hidden;
section_name = symbol->section ? symbol->section->name : "(*none*)";
@ -1473,45 +1522,12 @@ bfd_elf_print_symbol (bfd *abfd,
bfd_fprintf_vma (abfd, file, val);
/* If we have version information, print it. */
if (elf_dynversym (abfd) != 0
&& (elf_dynverdef (abfd) != 0
|| elf_dynverref (abfd) != 0))
version_string = bfd_elf_get_symbol_version_string (abfd,
symbol,
&hidden);
if (version_string)
{
unsigned int vernum;
const char *version_string;
vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION;
if (vernum == 0)
version_string = "";
else if (vernum == 1)
version_string = "Base";
else if (vernum <= elf_tdata (abfd)->cverdefs)
version_string =
elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
else
{
Elf_Internal_Verneed *t;
version_string = "";
for (t = elf_tdata (abfd)->verref;
t != NULL;
t = t->vn_nextref)
{
Elf_Internal_Vernaux *a;
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
if (a->vna_other == vernum)
{
version_string = a->vna_nodename;
break;
}
}
}
}
if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0)
if (!hidden)
fprintf (file, " %-11s", version_string);
else
{

View file

@ -1,3 +1,20 @@
2014-11-25 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/16496
* objdump.c (objdump_print_symname): Call
bfd_elf_get_symbol_version_string to get ELF symbol version
string. Append version string if needed.
* readelf.c (versioned_symbol_info): New enum.
(get_symbol_version_string): New. Extracted from
process_symbol_table.
(dump_relocations): Add a new argument to indicate if dynamic
symbol table is used. Use get_symbol_version_string to get
symbol version string for dynamic symbol. Append version string
if needed.
(process_relocs): Updated dump_relocations call.
(process_symbol_table): Use get_symbol_version_string.
2014-11-24 H.J. Lu <hongjiu.lu@intel.com>
* configure: Regenerated.

View file

@ -795,7 +795,8 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf,
asymbol *sym)
{
char *alloc;
const char *name;
const char *name, *version_string = NULL;
bfd_boolean hidden = FALSE;
alloc = NULL;
name = bfd_asymbol_name (sym);
@ -807,10 +808,26 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf,
name = alloc;
}
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
version_string = bfd_elf_get_symbol_version_string (abfd, sym,
&hidden);
if (bfd_is_und_section (bfd_get_section (sym)))
hidden = TRUE;
if (inf != NULL)
(*inf->fprintf_func) (inf->stream, "%s", name);
{
(*inf->fprintf_func) (inf->stream, "%s", name);
if (version_string && *version_string != '\0')
(*inf->fprintf_func) (inf->stream, hidden ? "@%s" : "@@%s",
version_string);
}
else
printf ("%s", name);
{
printf ("%s", name);
if (version_string && *version_string != '\0')
printf (hidden ? "@%s" : "@@%s", version_string);
}
if (alloc != NULL)
free (alloc);

View file

@ -272,6 +272,20 @@ typedef enum print_mode
}
print_mode;
/* Versioned symbol info. */
enum versioned_symbol_info
{
symbol_undefined,
symbol_hidden,
symbol_public
};
static const char *get_symbol_version_string
(FILE *file, int is_dynsym, const char *strtab,
unsigned long int strtab_size, unsigned int si,
Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info,
unsigned short *vna_other);
#define UNKNOWN -1
#define SECTION_NAME(X) \
@ -1015,7 +1029,8 @@ dump_relocations (FILE * file,
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
int is_rela)
int is_rela,
int is_dynsym)
{
unsigned int i;
Elf_Internal_Rela * rels;
@ -1448,9 +1463,20 @@ dump_relocations (FILE * file,
else
{
Elf_Internal_Sym * psym;
const char * version_string;
enum versioned_symbol_info sym_info;
unsigned short vna_other;
psym = symtab + symtab_index;
version_string
= get_symbol_version_string (file, is_dynsym,
strtab, strtablen,
symtab_index,
psym,
&sym_info,
&vna_other);
printf (" ");
if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
@ -1477,6 +1503,9 @@ dump_relocations (FILE * file,
name = strtab + psym->st_name;
len = print_symbol (width, name);
if (version_string)
printf (sym_info == symbol_public ? "@@%s" : "@%s",
version_string);
printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
}
else
@ -1533,7 +1562,12 @@ dump_relocations (FILE * file,
else if (psym->st_name >= strtablen)
printf (_("<corrupt string table index: %3ld>"), psym->st_name);
else
print_symbol (22, strtab + psym->st_name);
{
print_symbol (22, strtab + psym->st_name);
if (version_string)
printf (sym_info == symbol_public ? "@@%s" : "@%s",
version_string);
}
if (is_rela)
{
@ -6097,7 +6131,8 @@ process_relocs (FILE * file)
offset_from_vma (file, rel_offset, rel_size),
rel_size,
dynamic_symbols, num_dynamic_syms,
dynamic_strings, dynamic_strings_length, is_rela);
dynamic_strings, dynamic_strings_length,
is_rela, 1);
}
}
@ -6172,14 +6207,16 @@ process_relocs (FILE * file)
}
dump_relocations (file, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen, is_rela);
symtab, nsyms, strtab, strtablen,
is_rela,
symsec->sh_type == SHT_DYNSYM);
if (strtab)
free (strtab);
free (symtab);
}
else
dump_relocations (file, rel_offset, rel_size,
NULL, 0, NULL, 0, is_rela);
NULL, 0, NULL, 0, is_rela, 0);
found = 1;
}
@ -9879,6 +9916,181 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn)
putchar ('\n');
}
static const char *
get_symbol_version_string (FILE *file, int is_dynsym,
const char *strtab,
unsigned long int strtab_size,
unsigned int si, Elf_Internal_Sym *psym,
enum versioned_symbol_info *sym_info,
unsigned short *vna_other)
{
const char *version_string = NULL;
if (is_dynsym
&& version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
{
unsigned char data[2];
unsigned short vers_data;
unsigned long offset;
int is_nobits;
int check_def;
offset = offset_from_vma
(file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
sizeof data + si * sizeof (vers_data));
if (get_data (&data, file, offset + si * sizeof (vers_data),
sizeof (data), 1, _("version data")) == NULL)
return NULL;
vers_data = byte_get (data, 2);
is_nobits = (psym->st_shndx < elf_header.e_shnum
&& section_headers[psym->st_shndx].sh_type
== SHT_NOBITS);
check_def = (psym->st_shndx != SHN_UNDEF);
if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
{
if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
&& (is_nobits || ! check_def))
{
Elf_External_Verneed evn;
Elf_Internal_Verneed ivn;
Elf_Internal_Vernaux ivna;
/* We must test both. */
offset = offset_from_vma
(file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
sizeof evn);
do
{
unsigned long vna_off;
if (get_data (&evn, file, offset, sizeof (evn), 1,
_("version need")) == NULL)
{
ivna.vna_next = 0;
ivna.vna_other = 0;
ivna.vna_name = 0;
break;
}
ivn.vn_aux = BYTE_GET (evn.vn_aux);
ivn.vn_next = BYTE_GET (evn.vn_next);
vna_off = offset + ivn.vn_aux;
do
{
Elf_External_Vernaux evna;
if (get_data (&evna, file, vna_off,
sizeof (evna), 1,
_("version need aux (3)")) == NULL)
{
ivna.vna_next = 0;
ivna.vna_other = 0;
ivna.vna_name = 0;
}
else
{
ivna.vna_other = BYTE_GET (evna.vna_other);
ivna.vna_next = BYTE_GET (evna.vna_next);
ivna.vna_name = BYTE_GET (evna.vna_name);
}
vna_off += ivna.vna_next;
}
while (ivna.vna_other != vers_data
&& ivna.vna_next != 0);
if (ivna.vna_other == vers_data)
break;
offset += ivn.vn_next;
}
while (ivn.vn_next != 0);
if (ivna.vna_other == vers_data)
{
*sym_info = symbol_undefined;
*vna_other = ivna.vna_other;
version_string = (ivna.vna_name < strtab_size
? strtab + ivna.vna_name
: _("<corrupt>"));
check_def = 0;
}
else if (! is_nobits)
error (_("bad dynamic symbol\n"));
else
check_def = 1;
}
if (check_def)
{
if (vers_data != 0x8001
&& version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
{
Elf_Internal_Verdef ivd;
Elf_Internal_Verdaux ivda;
Elf_External_Verdaux evda;
unsigned long off;
off = offset_from_vma
(file,
version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
sizeof (Elf_External_Verdef));
do
{
Elf_External_Verdef evd;
if (get_data (&evd, file, off, sizeof (evd),
1, _("version def")) == NULL)
{
ivd.vd_ndx = 0;
ivd.vd_aux = 0;
ivd.vd_next = 0;
}
else
{
ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
ivd.vd_aux = BYTE_GET (evd.vd_aux);
ivd.vd_next = BYTE_GET (evd.vd_next);
}
off += ivd.vd_next;
}
while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
&& ivd.vd_next != 0);
off -= ivd.vd_next;
off += ivd.vd_aux;
if (get_data (&evda, file, off, sizeof (evda),
1, _("version def aux")) == NULL)
return version_string;
ivda.vda_name = BYTE_GET (evda.vda_name);
if (psym->st_name != ivda.vda_name)
{
*sym_info = ((vers_data & VERSYM_HIDDEN) != 0
? symbol_hidden : symbol_public);
version_string = (ivda.vda_name < strtab_size
? strtab + ivda.vda_name
: _("<corrupt>"));
}
}
}
}
}
return version_string;
}
/* Dump the symbol table. */
static int
process_symbol_table (FILE * file)
@ -10179,6 +10391,10 @@ process_symbol_table (FILE * file)
for (si = 0, psym = symtab; si < num_syms; si++, psym++)
{
const char *version_string;
enum versioned_symbol_info sym_info;
unsigned short vna_other;
printf ("%6d: ", si);
print_vma (psym->st_value, LONG_HEX);
putchar (' ');
@ -10195,163 +10411,18 @@ process_symbol_table (FILE * file)
print_symbol (25, psym->st_name < strtab_size
? strtab + psym->st_name : _("<corrupt>"));
if (section->sh_type == SHT_DYNSYM
&& version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
version_string
= get_symbol_version_string (file,
section->sh_type == SHT_DYNSYM,
strtab, strtab_size, si,
psym, &sym_info, &vna_other);
if (version_string)
{
unsigned char data[2];
unsigned short vers_data;
unsigned long offset;
int is_nobits;
int check_def;
offset = offset_from_vma
(file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
sizeof data + si * sizeof (vers_data));
if (get_data (&data, file, offset + si * sizeof (vers_data),
sizeof (data), 1, _("version data")) == NULL)
break;
vers_data = byte_get (data, 2);
is_nobits = (psym->st_shndx < elf_header.e_shnum
&& section_headers[psym->st_shndx].sh_type
== SHT_NOBITS);
check_def = (psym->st_shndx != SHN_UNDEF);
if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
{
if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
&& (is_nobits || ! check_def))
{
Elf_External_Verneed evn;
Elf_Internal_Verneed ivn;
Elf_Internal_Vernaux ivna;
/* We must test both. */
offset = offset_from_vma
(file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
sizeof evn);
do
{
unsigned long vna_off;
if (get_data (&evn, file, offset, sizeof (evn), 1,
_("version need")) == NULL)
{
ivna.vna_next = 0;
ivna.vna_other = 0;
ivna.vna_name = 0;
break;
}
ivn.vn_aux = BYTE_GET (evn.vn_aux);
ivn.vn_next = BYTE_GET (evn.vn_next);
vna_off = offset + ivn.vn_aux;
do
{
Elf_External_Vernaux evna;
if (get_data (&evna, file, vna_off,
sizeof (evna), 1,
_("version need aux (3)")) == NULL)
{
ivna.vna_next = 0;
ivna.vna_other = 0;
ivna.vna_name = 0;
}
else
{
ivna.vna_other = BYTE_GET (evna.vna_other);
ivna.vna_next = BYTE_GET (evna.vna_next);
ivna.vna_name = BYTE_GET (evna.vna_name);
}
vna_off += ivna.vna_next;
}
while (ivna.vna_other != vers_data
&& ivna.vna_next != 0);
if (ivna.vna_other == vers_data)
break;
offset += ivn.vn_next;
}
while (ivn.vn_next != 0);
if (ivna.vna_other == vers_data)
{
printf ("@%s (%d)",
ivna.vna_name < strtab_size
? strtab + ivna.vna_name : _("<corrupt>"),
ivna.vna_other);
check_def = 0;
}
else if (! is_nobits)
error (_("bad dynamic symbol\n"));
else
check_def = 1;
}
if (check_def)
{
if (vers_data != 0x8001
&& version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
{
Elf_Internal_Verdef ivd;
Elf_Internal_Verdaux ivda;
Elf_External_Verdaux evda;
unsigned long off;
off = offset_from_vma
(file,
version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
sizeof (Elf_External_Verdef));
do
{
Elf_External_Verdef evd;
if (get_data (&evd, file, off, sizeof (evd),
1, _("version def")) == NULL)
{
ivd.vd_ndx = 0;
ivd.vd_aux = 0;
ivd.vd_next = 0;
}
else
{
ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
ivd.vd_aux = BYTE_GET (evd.vd_aux);
ivd.vd_next = BYTE_GET (evd.vd_next);
}
off += ivd.vd_next;
}
while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
&& ivd.vd_next != 0);
off -= ivd.vd_next;
off += ivd.vd_aux;
if (get_data (&evda, file, off, sizeof (evda),
1, _("version def aux")) == NULL)
break;
ivda.vda_name = BYTE_GET (evda.vda_name);
if (psym->st_name != ivda.vda_name)
printf ((vers_data & VERSYM_HIDDEN)
? "@%s" : "@@%s",
ivda.vda_name < strtab_size
? strtab + ivda.vda_name : _("<corrupt>"));
}
}
}
if (sym_info == symbol_undefined)
printf ("@%s (%d)", version_string, vna_other);
else
printf (sym_info == symbol_hidden ? "@%s" : "@@%s",
version_string);
}
putchar ('\n');

View file

@ -1,3 +1,19 @@
2014-11-25 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/16496
* ld-cris/weakref3.d: Add symbol version string to versioned
symbol names in dynamic relocation.
* ld-cris/weakref4.d: Likewise.
* ld-elfvers/vers24.rd: Likewise.
* ld-elf/pr16496a.c: New file.
* ld-elf/pr16496a.map: Likewise.
* ld-elf/pr16496b.c: Likewise.
* ld-elf/pr16496b.od: Likewise.
* ld-elf/shared.exp (build_tests): Add libpr16496a.so and
libpr16496b.so tests.
2014-11-25 H.J. Lu <hongjiu.lu@intel.com>
* ld-i386/i386.exp: Add run-time relocation tests for plt-main.

View file

@ -16,11 +16,11 @@
#...
Relocation section '.rela.dyn' at offset 0x... contains 1 entries:
Offset +Info +Type +Sym.Value +Sym. Name \+ Addend
.* R_CRIS_COPY .* __expobj2 \+ 0
.* R_CRIS_COPY .* __expobj2@TST3 \+ 0
Relocation section '.rela.plt' at offset 0x... contains 1 entries:
Offset +Info +Type +Sym.Value +Sym. Name \+ Addend
.* R_CRIS_JUMP_SLOT .* expfn2 \+ 0
.* R_CRIS_JUMP_SLOT .* expfn2@TST3 \+ 0
The decoding of unwind sections for machine type Axis Communications 32-bit embedded processor is not currently supported.

View file

@ -17,7 +17,7 @@
#...
Relocation section '.rela.dyn' at offset 0x... contains 1 entries:
#...
.* R_CRIS_COPY .* __expobj2 \+ 0
.* R_CRIS_COPY .* __expobj2@TST3 \+ 0
The decoding of unwind sections for machine type Axis Communications 32-bit embedded processor is not currently supported.

View file

@ -0,0 +1,4 @@
void
sd_get_seats (void)
{
}

View file

@ -0,0 +1,4 @@
LIBSYSTEMD_209 {
global:
sd_get_seats;
};

View file

@ -0,0 +1,5 @@
void sd_get_seats (void);
void call_sd_get_seats (void)
{
sd_get_seats ();
}

View file

@ -0,0 +1,3 @@
#...
.* sd_get_seats@LIBSYSTEMD_209
#pass

View file

@ -246,6 +246,15 @@ set build_tests {
{"Build dynamic-1"
"-Wl,--dynamic-list,dynamic-1.syms -Wl,--gc-sections" "-ffunction-sections"
{dynamic-1.c} {{readelf {-s} dynamic-1.rd}} "dynamic-1"}
{"Build libpr16496a.so"
"-shared -Wl,--version-script=pr16496a.map" "-fPIC"
{pr16496a.c} {} "libpr16496a.so"}
{"Build libpr16496b.a"
"" "-fPIC"
{pr16496b.c} {} "libpr16496b.a"}
{"Build libpr16496b.so"
"-shared tmpdir/pr16496b.o tmpdir/libpr16496a.so" ""
{dummy.c} {{objdump {-R} pr16496b.od}} "libpr16496b.so"}
}
run_cc_link_tests $build_tests

View file

@ -1,7 +1,7 @@
Relocation section .*
# Ensure there is a dynamic relocation against x
#...
[0-9a-f]+ +[0-9a-f]+ R_.* +_?x(| \+ 0)
[0-9a-f]+ +[0-9a-f]+ R_.* +_?x@VERS.0(| \+ 0)
#...
Symbol table '.dynsym' contains [0-9]+ entries:
# And ensure the dynamic symbol table contains at least x@VERS.0