aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1997-03-10 04:43:42 +0000
committerIan Lance Taylor <ian@airs.com>1997-03-10 04:43:42 +0000
commitd6bfcdb505ffd51bcf218362eee92fa7c779c86f (patch)
treee9bafe59948dfa46d047fcd96e7ca0a6f51c99ca /bfd/elf.c
parent998f2b67a921506635e9f23f4ada35255972aabb (diff)
downloadgdb-d6bfcdb505ffd51bcf218362eee92fa7c779c86f.zip
gdb-d6bfcdb505ffd51bcf218362eee92fa7c779c86f.tar.gz
gdb-d6bfcdb505ffd51bcf218362eee92fa7c779c86f.tar.bz2
From Eric Youngdale <eric@andante.jic.com>:
* elf-bfd.h (elf_symbol_type): Add version field. * elfcode.h (elf_slurp_symbol_table): Set version field. * elflink.h (elf_link_add_object_symbols): When creating an indirect symbol for a default version symbol, set DEF_DYNAMIC if appropriate. Set up an indirection from the nondefault version of the symbol as well. (NAME(bfd_elf,size_dynamic_sections)): Call elf_link_assign_sym_version before checking whether there are any versions. Always record the version name as a dynamic symbol. Initialize counters. (elf_link_assign_sym_version): After finding a version, see if a symbol should be forced to local scope. Create a new version definition if appropriate. (elf_link_output_extsym): Correct indirect symbol handling. * elf.c (bfd_elf_print_symbol): Print version information. (bfd_section_from_shdr): Turn version sections into BFD sections. (elf_fake_sections): Only copy cverdefs and cverrefs into sh_info if sh_info is not already set. (_bfd_elf_copy_private_section_data): Copy sh_info for version sections. * elflink.c (_bfd_elf_link_record_dynamic_symbol): Tell _bfd_stringtab_add to copy the name into permanent memory if appropriate.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r--bfd/elf.c110
1 files changed, 100 insertions, 10 deletions
diff --git a/bfd/elf.c b/bfd/elf.c
index cdf1a31..602de95 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -701,9 +701,10 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
}
/* Display ELF-specific fields of a symbol. */
+
void
-bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
- bfd *ignore_abfd;
+bfd_elf_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
PTR filep;
asymbol *symbol;
bfd_print_symbol_type how;
@@ -733,11 +734,64 @@ bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
(bfd_is_com_section (symbol->section)
? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
: ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+
+ /* If we have version information, print it. */
+ if (elf_tdata (abfd)->dynversym_section != 0
+ && (elf_tdata (abfd)->dynverdef_section != 0
+ || elf_tdata (abfd)->dynverref_section != 0))
+ {
+ 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)
+ fprintf (file, " %-12s", version_string);
+ else
+ {
+ int i;
+
+ fprintf (file, " (%s)", version_string);
+ for (i = strlen (version_string) - 10; i > 0; --i)
+ putc (' ', file);
+ }
+ }
+
/* If the st_other field is not zero, print it. */
if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
fprintf (file, " 0x%02x",
((unsigned int)
((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
+
fprintf (file, " %s", symbol->name);
}
break;
@@ -1098,16 +1152,19 @@ bfd_section_from_shdr (abfd, shindex)
case SHT_GNU_verdef:
elf_dynverdef (abfd) = shindex;
elf_tdata (abfd)->dynverdef_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
break;
case SHT_GNU_versym:
elf_dynversym (abfd) = shindex;
elf_tdata (abfd)->dynversym_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
break;
case SHT_GNU_verneed:
elf_dynverref (abfd) = shindex;
elf_tdata (abfd)->dynverref_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
break;
case SHT_SHLIB:
@@ -1338,13 +1395,27 @@ elf_fake_sections (abfd, asect, failedptrarg)
{
this_hdr->sh_type = SHT_GNU_verdef;
this_hdr->sh_entsize = 0;
- this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverdefs. The linker will set cverdefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverdefs);
}
else if (strcmp (asect->name, ".gnu.version_r") == 0)
{
this_hdr->sh_type = SHT_GNU_verneed;
this_hdr->sh_entsize = 0;
- this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverrefs. The linker will set cverrefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
}
else if ((asect->flags & SEC_ALLOC) != 0
&& (asect->flags & SEC_LOAD) != 0)
@@ -3187,7 +3258,9 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
ohdr->sh_entsize = ihdr->sh_entsize;
if (ihdr->sh_type == SHT_SYMTAB
- || ihdr->sh_type == SHT_DYNSYM)
+ || ihdr->sh_type == SHT_DYNSYM
+ || ihdr->sh_type == SHT_GNU_verneed
+ || ihdr->sh_type == SHT_GNU_verdef)
ohdr->sh_info = ihdr->sh_info;
return true;
@@ -3831,17 +3904,34 @@ _bfd_elf_get_symbol_info (ignore_abfd, symbol, ret)
bfd_symbol_info (symbol, ret);
}
-/* Return whether a symbol name implies a local symbol. In ELF, local
- symbols generally start with ``.L''. Most targets use this
- function for the is_local_label_name entry point, but some override
- it. */
+/* Return whether a symbol name implies a local symbol. Most targets
+ use this function for the is_local_label_name entry point, but some
+ override it. */
boolean
_bfd_elf_is_local_label_name (abfd, name)
bfd *abfd;
const char *name;
{
- return name[0] == '.' && name[1] == 'L';
+ /* Normal local symbols start with ``.L''. */
+ if (name[0] == '.' && name[1] == 'L')
+ return true;
+
+ /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+ DWARF debugging symbols starting with ``..''. */
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ /* gcc will sometimes generate symbols beginning with ``_.L_'' when
+ emitting DWARF debugging output. I suspect this is actually a
+ small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+ ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+ underscore to be emitted on some ELF targets). For ease of use,
+ we treat such symbols as local. */
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ return false;
}
alent *