* 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.
+Sun Mar 9 23:08:49 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ 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.
+
Fri Mar 7 11:55:31 1997 H.J. Lu <hjl@gnu.ai.mit.edu>
* elf64-alpha.c (alpha_elf_dynamic_symbol_p): Fully parenthesize.
/* BFD back-end data structures for ELF files.
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
PTR any;
}
tc_data;
+
+ /* Version information. This is from an Elf_Internal_Versym
+ structure in a SHT_GNU_versym section. It is zero if there is no
+ version information. */
+ unsigned short version;
+
} elf_symbol_type;
\f
/* ELF linker hash table entries. */
from the beginning of the section. */
struct elf_linker_section_pointers *linker_section_pointer;
+ /* Version information. */
+ union
+ {
+ /* This field is used for a symbol which is not defined in a
+ regular object. It points to the version information read in
+ from the dynamic object. */
+ Elf_Internal_Verdef *verdef;
+ /* This field is used for a symbol which is defined in a regular
+ object. It is set up in size_dynamic_sections. It points to
+ the version information we should write out for this symbol. */
+ struct bfd_elf_version_tree *vertree;
+ } verinfo;
+
/* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */
char type;
unsigned char other;
/* Some flags; legal values follow. */
- unsigned char elf_link_hash_flags;
+ unsigned short elf_link_hash_flags;
/* Symbol is referenced by a non-shared object. */
#define ELF_LINK_HASH_REF_REGULAR 01
/* Symbol is defined by a non-shared object. */
#define ELF_LINK_HASH_NEEDS_PLT 0100
/* Symbol appears in a non-ELF input file. */
#define ELF_LINK_NON_ELF 0200
- /* Note: If you add more flags, you must change the type of
- elf_link_hash_flags. */
+ /* Symbol should be marked as hidden in the version information. */
+#define ELF_LINK_HIDDEN 0400
};
/* ELF linker hash table. */
Elf_Internal_Shdr strtab_hdr;
Elf_Internal_Shdr dynsymtab_hdr;
Elf_Internal_Shdr dynstrtab_hdr;
+ Elf_Internal_Shdr dynversym_hdr;
+ Elf_Internal_Shdr dynverref_hdr;
+ Elf_Internal_Shdr dynverdef_hdr;
unsigned int symtab_section, shstrtab_section;
unsigned int strtab_section, dynsymtab_section;
+ unsigned int dynversym_section, dynverdef_section, dynverref_section;
file_ptr next_file_pos;
void *prstatus; /* The raw /proc prstatus structure */
void *prpsinfo; /* The raw /proc prpsinfo structure */
find_nearest_line. */
struct mips_elf_find_line *find_line_info;
+ /* An array of stub sections indexed by symbol number, used by the
+ MIPS ELF linker. FIXME: We should figure out some way to only
+ include this field for a MIPS ELF target. */
+ asection **local_stubs;
+
/* Used to determine if the e_flags field has been initialized */
boolean flags_init;
+ /* Number of symbol version definitions we are about to emit. */
+ int cverdefs;
+
+ /* Number of symbol version references we are about to emit. */
+ int cverrefs;
+
+ /* Symbol version definitions in external objects. */
+ Elf_Internal_Verdef *verdef;
+
+ /* Symbol version references to external objects. */
+ Elf_Internal_Verneed *verref;
+
/* Linker sections that we are interested in. */
struct elf_linker_section *linker_section[ (int)LINKER_SECTION_MAX ];
};
#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr)
#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section)
#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section)
+#define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section)
+#define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section)
+#define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section)
#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals)
#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals)
#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms)
#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init)
#define elf_linker_section(bfd,n) (elf_tdata(bfd) -> linker_section[(int)n])
\f
+extern void _bfd_elf_swap_verdef_in
+ PARAMS ((bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *));
+extern void _bfd_elf_swap_verdef_out
+ PARAMS ((bfd *, const Elf_Internal_Verdef *, Elf_External_Verdef *));
+extern void _bfd_elf_swap_verdaux_in
+ PARAMS ((bfd *, const Elf_External_Verdaux *, Elf_Internal_Verdaux *));
+extern void _bfd_elf_swap_verdaux_out
+ PARAMS ((bfd *, const Elf_Internal_Verdaux *, Elf_External_Verdaux *));
+extern void _bfd_elf_swap_verneed_in
+ PARAMS ((bfd *, const Elf_External_Verneed *, Elf_Internal_Verneed *));
+extern void _bfd_elf_swap_verneed_out
+ PARAMS ((bfd *, const Elf_Internal_Verneed *, Elf_External_Verneed *));
+extern void _bfd_elf_swap_vernaux_in
+ PARAMS ((bfd *, const Elf_External_Vernaux *, Elf_Internal_Vernaux *));
+extern void _bfd_elf_swap_vernaux_out
+ PARAMS ((bfd *, const Elf_Internal_Vernaux *, Elf_External_Vernaux *));
+extern void _bfd_elf_swap_versym_in
+ PARAMS ((bfd *, const Elf_External_Versym *, Elf_Internal_Versym *));
+extern void _bfd_elf_swap_versym_out
+ PARAMS ((bfd *, const Elf_Internal_Versym *, Elf_External_Versym *));
+
extern int _bfd_elf_section_from_bfd_section PARAMS ((bfd *, asection *));
extern char *bfd_elf_string_from_elf_section
PARAMS ((bfd *, unsigned, unsigned));
struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
struct bfd_hash_table *,
const char *)));
+extern boolean _bfd_elf_slurp_version_tables PARAMS ((bfd *));
extern boolean _bfd_elf_copy_private_symbol_data
PARAMS ((bfd *, asymbol *, bfd *, asymbol *));
extern asymbol *_bfd_elf_make_empty_symbol PARAMS ((bfd *));
extern void _bfd_elf_get_symbol_info PARAMS ((bfd *, asymbol *,
symbol_info *));
+extern boolean _bfd_elf_is_local_label_name PARAMS ((bfd *, const char *));
extern alent *_bfd_elf_get_lineno PARAMS ((bfd *, asymbol *));
extern boolean _bfd_elf_set_arch_mach PARAMS ((bfd *, enum bfd_architecture,
unsigned long));
}
/* 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;
(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;
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:
{
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)
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;
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 *
goto error_return;
if (hi->root.type == bfd_link_hash_indirect)
- hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+ {
+ hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+ if (dynamic)
+ hi->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC;
+ /* We don't set DEF_REGULAR because we don't the
+ symbol to get exported even if we are
+ exporting all defined symbols. FIXME: What a
+ hack. */
+ /* FIXME: Do we need to copy any flags from H to
+ HI? */
+ }
+
+ /* We also need to define an indirection from the
+ nondefault version of the symbol. */
+
+ shortname = bfd_hash_allocate (&info->hash->table,
+ strlen (name));
+ if (shortname == NULL)
+ goto error_return;
+ strncpy (shortname, name, p - name);
+ strcpy (shortname + (p - name), p + 1);
+
+ hi = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, shortname, BSF_INDIRECT,
+ bfd_ind_section_ptr, (bfd_vma) 0, name, false,
+ collect, (struct bfd_link_hash_entry **) &hi)))
+ goto error_return;
+
+ if (hi->root.type == bfd_link_hash_indirect)
+ {
+ hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+ if (dynamic)
+ hi->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC;
+ }
}
}
size_t i;
size_t bucketcount = 0;
Elf_Internal_Sym isym;
+ struct elf_assign_sym_version_info sinfo;
/* Set up the version definition section. */
s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
BFD_ASSERT (s != NULL);
+
+ /* Attach all the symbols to their version information. This
+ may cause some symbols to be unexported. */
+ sinfo.output_bfd = output_bfd;
+ sinfo.info = info;
+ sinfo.verdefs = verdefs;
+ sinfo.export_dynamic = export_dynamic;
+ sinfo.removed_dynamic = false;
+ sinfo.failed = false;
+
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_link_assign_sym_version,
+ (PTR) &sinfo);
+ if (sinfo.failed)
+ return false;
+
+ /* We may have created additional version definitions if we are
+ just linking a regular application. */
+ verdefs = sinfo.verdefs;
+
if (verdefs == NULL)
{
- struct elf_assign_sym_version_info sinfo;
asection **spp;
- /* No version script was used. In this case, we just check
- that there were no version overrides for any symbols. */
- sinfo.output_bfd = output_bfd;
- sinfo.info = info;
- sinfo.verdefs = verdefs;
- sinfo.removed_dynamic = false;
- sinfo.export_dynamic = export_dynamic;
- sinfo.failed = false;
-
- elf_link_hash_traverse (elf_hash_table (info),
- elf_link_assign_sym_version,
- (PTR) &sinfo);
- if (sinfo.failed)
- return false;
-
/* Don't include this section in the output file. */
for (spp = &output_bfd->sections;
*spp != s->output_section;
}
else
{
- struct elf_assign_sym_version_info sinfo;
unsigned int cdefs;
bfd_size_type size;
struct bfd_elf_version_tree *t;
Elf_Internal_Verdef def;
Elf_Internal_Verdaux defaux;
- /* Attach all of the symbols to their version information.
- This may cause some symbols to be unexported. */
- sinfo.output_bfd = output_bfd;
- sinfo.info = info;
- sinfo.verdefs = verdefs;
- sinfo.export_dynamic = export_dynamic;
- sinfo.removed_dynamic = false;
- sinfo.failed = false;
- elf_link_hash_traverse (elf_hash_table (info),
- elf_link_assign_sym_version,
- (PTR) &sinfo);
- if (sinfo.failed)
- return false;
-
if (sinfo.removed_dynamic)
{
/* Some dynamic symbols were changed to be local
h->type = STT_OBJECT;
h->verinfo.vertree = t;
- if (info->shared)
- {
- if (! _bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
- }
+ if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
def.vd_version = VER_DEF_CURRENT;
def.vd_flags = 0;
bfd_byte *p;
/* Build the version definition section. */
+ size = 0;
+ crefs = 0;
for (t = elf_tdata (output_bfd)->verref;
t != NULL;
t = t->vn_nextref)
{
h->verinfo.vertree = t;
t->used = true;
+
+ /* See if there is anything to force this symbol to
+ local scope. */
+ if (t->locals != NULL)
+ {
+ int len;
+ char *alc;
+ struct bfd_elf_version_expr *d;
+
+ len = p - h->root.root.string;
+ alc = bfd_alloc (sinfo->output_bfd, len);
+ if (alc == NULL)
+ return false;
+ strncpy (alc, h->root.root.string, len - 1);
+ alc[len - 1] = '\0';
+ if (alc[len - 2] == ELF_VER_CHR)
+ alc[len - 2] = '\0';
+
+ for (d = t->locals; d != NULL; d = d->next)
+ {
+ if ((d->match[0] == '*' && d->match[1] == '\0')
+ || fnmatch (d->match, alc, 0) == 0)
+ {
+ if (h->dynindx != -1
+ && info->shared
+ && ! sinfo->export_dynamic
+ && (h->elf_link_hash_flags
+ & ELF_LINK_HASH_NEEDS_PLT) == 0)
+ {
+ sinfo->removed_dynamic = true;
+ h->dynindx = -1;
+ /* FIXME: The name of the symbol has
+ already been recorded in the dynamic
+ string table section. */
+ }
+
+ break;
+ }
+ }
+
+ bfd_release (sinfo->output_bfd, alc);
+ }
+
break;
}
}
- if (t == NULL)
+ /* If we are building an application, we need to create a
+ version node for this version. */
+ if (t == NULL && ! info->shared)
+ {
+ struct bfd_elf_version_tree **pp;
+ int version_index;
+
+ /* If we aren't going to export this symbol, we don't need
+ to worry about it. */
+ if (h->dynindx == -1)
+ return true;
+
+ t = ((struct bfd_elf_version_tree *)
+ bfd_alloc (sinfo->output_bfd, sizeof *t));
+ if (t == NULL)
+ {
+ sinfo->failed = true;
+ return false;
+ }
+
+ t->next = NULL;
+ t->name = p;
+ t->globals = NULL;
+ t->locals = NULL;
+ t->deps = NULL;
+ t->name_indx = (unsigned int) -1;
+ t->used = true;
+
+ version_index = 1;
+ for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+ ++version_index;
+ t->vernum = version_index;
+
+ *pp = t;
+
+ h->verinfo.vertree = t;
+ }
+ else if (t == NULL)
{
- /* We could not find the version. Return an error.
- FIXME: Why? */
+ /* We could not find the version for a symbol when
+ generating a shared archive. Return an error. */
(*_bfd_error_handler)
("%s: invalid version %s", bfd_get_filename (sinfo->output_bfd),
h->root.root.string);
to the decorated version of the name. For example, if the
symbol foo@@GNU_1.2 is the default, which should be used when
foo is used with no version, then we add an indirect symbol
- foo which points to foo@@GNU_1.2. */
- if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
+ foo which points to foo@@GNU_1.2. We ignore these symbols,
+ since the indirected symbol is already in the hash table. If
+ the indirect symbol is non-ELF, fall through and output it. */
+ if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) == 0)
return true;
/* Fall through. */