/* This function is called to create an indirect symbol from the
default for the symbol with the default version if needed. The
- symbol is described by H, NAME, SYM, SEC, VALUE, and OVERRIDE. We
+ symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE. We
set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED
indicates if it comes from a DT_NEEDED entry of a shared object. */
static boolean
-elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
+elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
dynsym, override, dt_needed)
bfd *abfd;
struct bfd_link_info *info;
struct elf_link_hash_entry *h;
const char *name;
Elf_Internal_Sym *sym;
- asection **sec;
+ asection **psec;
bfd_vma *value;
boolean *dynsym;
boolean override;
boolean dynamic;
char *p;
size_t len, shortlen;
+ asection *sec;
/* If this symbol has a version, and it is the default version, we
create an indirect symbol from the default name to the fully
actually going to define an indirect symbol. */
type_change_ok = false;
size_change_ok = false;
- if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+ sec = *psec;
+ if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
&hi, &override, &type_change_ok,
&size_change_ok, dt_needed))
return false;
| ELF_LINK_HASH_DEF_REGULAR)) == 0);
ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
- (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
+ (*bed->elf_backend_copy_indirect_symbol) (bed, ht, hi);
/* See if the new flags lead us to realize that the symbol must
be dynamic. */
/* Once again, merge with any existing symbol. */
type_change_ok = false;
size_change_ok = false;
- if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+ sec = *psec;
+ if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
&hi, &override, &type_change_ok,
&size_change_ok, dt_needed))
return false;
if (override)
{
/* Here SHORTNAME is a versioned name, so we don't expect to see
- the type of override we do in the case above. */
- (*_bfd_error_handler)
- (_("%s: warning: unexpected redefinition of `%s'"),
- bfd_archive_filename (abfd), shortname);
+ the type of override we do in the case above unless it is
+ overridden by a versioned definiton. */
+ if (hi->root.type != bfd_link_hash_defined
+ && hi->root.type != bfd_link_hash_defweak)
+ (*_bfd_error_handler)
+ (_("%s: warning: unexpected redefinition of indirect versioned symbol `%s'"),
+ bfd_archive_filename (abfd), shortname);
}
else
{
& (ELF_LINK_HASH_DEF_DYNAMIC
| ELF_LINK_HASH_DEF_REGULAR)) == 0);
- (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+ (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
/* See if the new flags lead us to realize that the symbol
must be dynamic. */
struct elf_info_failed eif;
struct elf_link_hash_entry *h;
asection *dynstr;
+ struct bfd_elf_version_tree *t;
+ struct bfd_elf_version_expr *d;
+ boolean all_defined;
*sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
BFD_ASSERT (*sinterpptr != NULL || info->shared);
return false;
}
+ /* Make all global versions with definiton. */
+ for (t = verdefs; t != NULL; t = t->next)
+ for (d = t->globals; d != NULL; d = d->next)
+ if (!d->symver && strchr (d->pattern, '*') == NULL)
+ {
+ const char *verstr, *name;
+ size_t namelen, verlen, newlen;
+ char *newname, *p;
+ struct elf_link_hash_entry *newh;
+
+ name = d->pattern;
+ namelen = strlen (name);
+ verstr = t->name;
+ verlen = strlen (verstr);
+ newlen = namelen + verlen + 3;
+
+ newname = (char *) bfd_malloc ((bfd_size_type) newlen);
+ if (newname == NULL)
+ return false;
+ memcpy (newname, name, namelen);
+
+ /* Check the hidden versioned definition. */
+ p = newname + namelen;
+ *p++ = ELF_VER_CHR;
+ memcpy (p, verstr, verlen + 1);
+ newh = elf_link_hash_lookup (elf_hash_table (info),
+ newname, false, false,
+ false);
+ if (newh == NULL
+ || (newh->root.type != bfd_link_hash_defined
+ && newh->root.type != bfd_link_hash_defweak))
+ {
+ /* Check the default versioned definition. */
+ *p++ = ELF_VER_CHR;
+ memcpy (p, verstr, verlen + 1);
+ newh = elf_link_hash_lookup (elf_hash_table (info),
+ newname, false, false,
+ false);
+ }
+ free (newname);
+
+ /* Mark this version if there is a definition and it is
+ not defined in a shared object. */
+ if (newh != NULL
+ && ((newh->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
+ && (newh->root.type == bfd_link_hash_defined
+ || newh->root.type == bfd_link_hash_defweak))
+ d->symver = 1;
+ }
+
/* Attach all the symbols to their version information. */
asvinfo.output_bfd = output_bfd;
asvinfo.info = info;
if (asvinfo.failed)
return false;
+ if (!info->allow_undefined_version)
+ {
+ /* Check if all global versions have a definiton. */
+ all_defined = true;
+ for (t = verdefs; t != NULL; t = t->next)
+ for (d = t->globals; d != NULL; d = d->next)
+ if (!d->symver && !d->script
+ && strchr (d->pattern, '*') == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%s: undefined version: %s"),
+ d->pattern, t->name);
+ all_defined = false;
+ }
+
+ if (!all_defined)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ }
+
/* Find all symbols which were defined in a dynamic object and make
the backend pick a reasonable value for them. */
elf_link_hash_traverse (elf_hash_table (info),
{
struct elf_link_hash_entry *weakdef;
+ weakdef = h->weakdef;
+ if (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak);
- weakdef = h->weakdef;
BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
|| weakdef->root.type == bfd_link_hash_defweak);
BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
struct elf_backend_data *bed;
bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
- (*bed->elf_backend_copy_indirect_symbol) (weakdef, h);
+ (*bed->elf_backend_copy_indirect_symbol) (bed, weakdef, h);
}
}
(_("%s: undefined versioned symbol name %s"),
bfd_get_filename (sinfo->output_bfd), h->root.root.string);
bfd_set_error (bfd_error_bad_value);
- error_return:
sinfo->failed = true;
return false;
}
{
if (t->globals != NULL)
{
+ boolean matched;
+
+ matched = false;
for (d = t->globals; d != NULL; d = d->next)
{
if ((*d->match) (d, h->root.root.string))
{
- h->verinfo.vertree = t;
- local_ver = NULL;
- break;
+ if (d->symver)
+ matched = true;
+ else
+ {
+ /* There is a version without definition. Make
+ the symbol the default definition for this
+ version. */
+ h->verinfo.vertree = t;
+ local_ver = NULL;
+ d->script = 1;
+ break;
+ }
}
}
if (d != NULL)
break;
+ else if (matched)
+ /* There is no undefined version for this symbol. Hide the
+ default one. */
+ (*bed->elf_backend_hide_symbol) (info, h, true);
}
if (t->locals != NULL)
(*bed->elf_backend_hide_symbol) (info, h, true);
}
}
-
- /* We need to check if a hidden versioned definition should
- hide the default one. */
- if (h->dynindx != -1 && h->verinfo.vertree != NULL)
- {
- const char *verstr, *name;
- size_t namelen, verlen, newlen;
- char *newname;
- struct elf_link_hash_entry *newh;
-
- name = h->root.root.string;
- namelen = strlen (name);
- verstr = h->verinfo.vertree->name;
- verlen = strlen (verstr);
- newlen = namelen + verlen + 2;
-
- newname = (char *) bfd_malloc ((bfd_size_type) newlen);
- if (newname == NULL)
- goto error_return;
- memcpy (newname, name, namelen);
-
- /* Check the hidden versioned definition. */
- p = newname + namelen;
- *p++ = ELF_VER_CHR;
- memcpy (p, verstr, verlen + 1);
- newh = elf_link_hash_lookup (elf_hash_table (info), newname,
- false, false, false);
-
- if (newh
- && (newh->root.type == bfd_link_hash_defined
- || newh->root.type == bfd_link_hash_defweak))
- /* We found a hidden versioned definition. Hide the
- default one. */
- (*bed->elf_backend_hide_symbol) (info, h, true);
-
- free (newname);
- }
}
return true;