aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.h
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elflink.h')
-rw-r--r--bfd/elflink.h1254
1 files changed, 627 insertions, 627 deletions
diff --git a/bfd/elflink.h b/bfd/elflink.h
index 5046416..638f80a 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -149,18 +149,13 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
carsym * symdef;
{
Elf_Internal_Shdr * hdr;
- Elf_Internal_Shdr * shndx_hdr;
- Elf_External_Sym * esym;
- Elf_External_Sym * esymend;
- Elf_External_Sym * buf = NULL;
- Elf_External_Sym_Shndx * shndx_buf = NULL;
- Elf_External_Sym_Shndx * shndx;
bfd_size_type symcount;
bfd_size_type extsymcount;
bfd_size_type extsymoff;
- boolean result = false;
- file_ptr pos;
- bfd_size_type amt;
+ Elf_Internal_Sym *isymbuf;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
+ boolean result;
abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
if (abfd == (bfd *) NULL)
@@ -178,15 +173,9 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
/* Select the appropriate symbol table. */
if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
- {
- hdr = &elf_tdata (abfd)->symtab_hdr;
- shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- }
+ hdr = &elf_tdata (abfd)->symtab_hdr;
else
- {
- hdr = &elf_tdata (abfd)->dynsymtab_hdr;
- shndx_hdr = NULL;
- }
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
symcount = hdr->sh_size / sizeof (Elf_External_Sym);
@@ -203,58 +192,34 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
extsymoff = hdr->sh_info;
}
- amt = extsymcount * sizeof (Elf_External_Sym);
- buf = (Elf_External_Sym *) bfd_malloc (amt);
- if (buf == NULL && extsymcount != 0)
+ if (extsymcount == 0)
return false;
- /* Read in the symbol table.
- FIXME: This ought to be cached somewhere. */
- pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) buf, amt, abfd) != amt)
- goto error_exit;
-
- if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
- {
- amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
- shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (shndx_buf == NULL && extsymcount != 0)
- goto error_exit;
-
- pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
- goto error_exit;
- }
+ /* Read in the symbol table. */
+ isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ return false;
/* Scan the symbol table looking for SYMDEF. */
- esymend = buf + extsymcount;
- for (esym = buf, shndx = shndx_buf;
- esym < esymend;
- esym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
+ result = false;
+ for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++)
{
- Elf_Internal_Sym sym;
- const char * name;
-
- elf_swap_symbol_in (abfd, esym, shndx, &sym);
+ const char *name;
- name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+ name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ isym->st_name);
if (name == (const char *) NULL)
break;
if (strcmp (name, symdef->name) == 0)
{
- result = is_global_data_symbol_definition (abfd, & sym);
+ result = is_global_data_symbol_definition (abfd, isym);
break;
}
}
- error_exit:
- if (shndx_buf != NULL)
- free (shndx_buf);
- if (buf != NULL)
- free (buf);
+ free (isymbuf);
return result;
}
@@ -313,12 +278,10 @@ elf_link_add_archive_symbols (abfd, info)
return true;
amt = c;
amt *= sizeof (boolean);
- defined = (boolean *) bfd_malloc (amt);
- included = (boolean *) bfd_malloc (amt);
+ defined = (boolean *) bfd_zmalloc (amt);
+ included = (boolean *) bfd_zmalloc (amt);
if (defined == (boolean *) NULL || included == (boolean *) NULL)
goto error_return;
- memset (defined, 0, (size_t) amt);
- memset (included, 0, (size_t) amt);
symdefs = bfd_ardata (abfd)->symdefs;
@@ -355,26 +318,40 @@ elf_link_add_archive_symbols (abfd, info)
if (h == NULL)
{
char *p, *copy;
+ size_t len, first;
/* If this is a default version (the name contains @@),
- look up the symbol again without the version. The
- effect is that references to the symbol without the
- version will be matched by the default symbol in the
- archive. */
+ look up the symbol again with only one `@' as well
+ as without the version. The effect is that references
+ to the symbol with and without the version will be
+ matched by the default symbol in the archive. */
p = strchr (symdef->name, ELF_VER_CHR);
if (p == NULL || p[1] != ELF_VER_CHR)
continue;
- copy = bfd_alloc (abfd, (bfd_size_type) (p - symdef->name + 1));
+ /* First check with only one `@'. */
+ len = strlen (symdef->name);
+ copy = bfd_alloc (abfd, (bfd_size_type) len);
if (copy == NULL)
goto error_return;
- memcpy (copy, symdef->name, (size_t) (p - symdef->name));
- copy[p - symdef->name] = '\0';
+ first = p - symdef->name + 1;
+ memcpy (copy, symdef->name, first);
+ memcpy (copy + first, symdef->name + first + 1, len - first);
h = elf_link_hash_lookup (elf_hash_table (info), copy,
false, false, false);
+ if (h == NULL)
+ {
+ /* We also need to check references to the symbol
+ without the version. */
+
+ copy[first - 1] = '\0';
+ h = elf_link_hash_lookup (elf_hash_table (info),
+ copy, false, false, false);
+ }
+
bfd_release (abfd, copy);
}
@@ -922,19 +899,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
/* 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;
@@ -948,6 +925,8 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
boolean collect;
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
@@ -960,7 +939,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
if (override)
{
/* We are overridden by an old defition. We need to check if we
- need to crreate the indirect symbol from the default name. */
+ need to create the indirect symbol from the default name. */
hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
false, false);
BFD_ASSERT (hi != NULL);
@@ -979,12 +958,12 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
collect = bed->collect;
dynamic = (abfd->flags & DYNAMIC) != 0;
- shortname = bfd_hash_allocate (&info->hash->table,
- (size_t) (p - name + 1));
+ shortlen = p - name;
+ shortname = bfd_hash_allocate (&info->hash->table, shortlen + 1);
if (shortname == NULL)
return false;
- strncpy (shortname, name, (size_t) (p - name));
- shortname [p - name] = '\0';
+ memcpy (shortname, name, shortlen);
+ shortname[shortlen] = '\0';
/* We are going to create a new symbol. Merge it with any existing
symbol with this name. For the purposes of the merge, act as
@@ -992,7 +971,8 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
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;
@@ -1064,7 +1044,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
| 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. */
@@ -1089,16 +1069,18 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
/* We also need to define an indirection from the nondefault version
of the symbol. */
- shortname = bfd_hash_allocate (&info->hash->table, strlen (name));
+ len = strlen (name);
+ shortname = bfd_hash_allocate (&info->hash->table, len);
if (shortname == NULL)
return false;
- strncpy (shortname, name, (size_t) (p - name));
- strcpy (shortname + (p - name), p + 1);
+ memcpy (shortname, name, shortlen);
+ memcpy (shortname + shortlen, p + 1, len - shortlen);
/* 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;
@@ -1106,10 +1088,13 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
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
{
@@ -1131,7 +1116,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
& (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. */
@@ -1172,25 +1157,20 @@ elf_link_add_object_symbols (abfd, info)
asection *, const Elf_Internal_Rela *));
boolean collect;
Elf_Internal_Shdr *hdr;
- Elf_Internal_Shdr *shndx_hdr;
bfd_size_type symcount;
bfd_size_type extsymcount;
bfd_size_type extsymoff;
- Elf_External_Sym *buf = NULL;
- Elf_External_Sym_Shndx *shndx_buf = NULL;
- Elf_External_Sym_Shndx *shndx;
struct elf_link_hash_entry **sym_hash;
boolean dynamic;
Elf_External_Versym *extversym = NULL;
Elf_External_Versym *ever;
- Elf_External_Dyn *dynbuf = NULL;
struct elf_link_hash_entry *weaks;
- Elf_External_Sym *esym;
- Elf_External_Sym *esymend;
+ Elf_Internal_Sym *isymbuf = NULL;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
struct elf_backend_data *bed;
boolean dt_needed;
struct elf_link_hash_table * hash_table;
- file_ptr pos;
bfd_size_type amt;
hash_table = elf_hash_table (info);
@@ -1289,85 +1269,7 @@ elf_link_add_object_symbols (abfd, info)
}
}
- /* If this is a dynamic object, we always link against the .dynsym
- symbol table, not the .symtab symbol table. The dynamic linker
- will only see the .dynsym symbol table, so there is no reason to
- look at .symtab for a dynamic object. */
-
- if (! dynamic || elf_dynsymtab (abfd) == 0)
- {
- hdr = &elf_tdata (abfd)->symtab_hdr;
- shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- }
- else
- {
- hdr = &elf_tdata (abfd)->dynsymtab_hdr;
- shndx_hdr = NULL;
- }
-
- if (dynamic)
- {
- /* Read in any version definitions. */
-
- if (! _bfd_elf_slurp_version_tables (abfd))
- goto error_return;
-
- /* Read in the symbol versions, but don't bother to convert them
- to internal format. */
- if (elf_dynversym (abfd) != 0)
- {
- Elf_Internal_Shdr *versymhdr;
-
- versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
- if (extversym == NULL)
- goto error_return;
- amt = versymhdr->sh_size;
- if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) extversym, amt, abfd) != amt)
- goto error_return;
- }
- }
-
- symcount = hdr->sh_size / sizeof (Elf_External_Sym);
-
- /* The sh_info field of the symtab header tells us where the
- external symbols start. We don't care about the local symbols at
- this point. */
- if (elf_bad_symtab (abfd))
- {
- extsymcount = symcount;
- extsymoff = 0;
- }
- else
- {
- extsymcount = symcount - hdr->sh_info;
- extsymoff = hdr->sh_info;
- }
-
- amt = extsymcount * sizeof (Elf_External_Sym);
- buf = (Elf_External_Sym *) bfd_malloc (amt);
- if (buf == NULL && extsymcount != 0)
- goto error_return;
-
- if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
- {
- amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
- shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (shndx_buf == NULL && extsymcount != 0)
- goto error_return;
- }
-
- /* We store a pointer to the hash table entry for each external
- symbol. */
- amt = extsymcount * sizeof (struct elf_link_hash_entry *);
- sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
- if (sym_hash == NULL)
- goto error_return;
- elf_sym_hashes (abfd) = sym_hash;
-
dt_needed = false;
-
if (! dynamic)
{
/* If we are creating a shared library, create all the dynamic
@@ -1417,6 +1319,7 @@ elf_link_add_object_symbols (abfd, info)
s = bfd_get_section_by_name (abfd, ".dynamic");
if (s != NULL)
{
+ Elf_External_Dyn *dynbuf = NULL;
Elf_External_Dyn *extdyn;
Elf_External_Dyn *extdynend;
int elfsec;
@@ -1430,30 +1333,13 @@ elf_link_add_object_symbols (abfd, info)
if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf,
(file_ptr) 0, s->_raw_size))
- goto error_return;
+ goto error_free_dyn;
elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
if (elfsec == -1)
- goto error_return;
+ goto error_free_dyn;
shlink = elf_elfsections (abfd)[elfsec]->sh_link;
- {
- /* The shared libraries distributed with hpux11 have a bogus
- sh_link field for the ".dynamic" section. This code detects
- when SHLINK refers to a section that is not a string table
- and tries to find the string table for the ".dynsym" section
- instead. */
- Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[shlink];
- if (shdr->sh_type != SHT_STRTAB)
- {
- asection *ds = bfd_get_section_by_name (abfd, ".dynsym");
- int elfdsec = _bfd_elf_section_from_bfd_section (abfd, ds);
- if (elfdsec == -1)
- goto error_return;
- shlink = elf_elfsections (abfd)[elfdsec]->sh_link;
- }
- }
-
extdyn = dynbuf;
extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
rpath = 0;
@@ -1468,7 +1354,7 @@ elf_link_add_object_symbols (abfd, info)
unsigned int tagv = dyn.d_un.d_val;
name = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (name == NULL)
- goto error_return;
+ goto error_free_dyn;
}
if (dyn.d_tag == DT_NEEDED)
{
@@ -1480,11 +1366,12 @@ elf_link_add_object_symbols (abfd, info)
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
- goto error_return;
- anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+ goto error_free_dyn;
+ amt = strlen (fnm) + 1;
+ anm = bfd_alloc (abfd, amt);
if (anm == NULL)
- goto error_return;
- strcpy (anm, fnm);
+ goto error_free_dyn;
+ memcpy (anm, fnm, (size_t) amt);
n->name = anm;
n->by = abfd;
n->next = NULL;
@@ -1511,11 +1398,12 @@ elf_link_add_object_symbols (abfd, info)
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
- goto error_return;
- anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+ goto error_free_dyn;
+ amt = strlen (fnm) + 1;
+ anm = bfd_alloc (abfd, amt);
if (anm == NULL)
- goto error_return;
- strcpy (anm, fnm);
+ goto error_free_dyn;
+ memcpy (anm, fnm, (size_t) amt);
n->name = anm;
n->by = abfd;
n->next = NULL;
@@ -1538,11 +1426,16 @@ elf_link_add_object_symbols (abfd, info)
n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
if (n == NULL || fnm == NULL)
- goto error_return;
- anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+ goto error_free_dyn;
+ amt = strlen (fnm) + 1;
+ anm = bfd_alloc (abfd, amt);
if (anm == NULL)
- goto error_return;
- strcpy (anm, fnm);
+ {
+ error_free_dyn:
+ free (dynbuf);
+ goto error_return;
+ }
+ memcpy (anm, fnm, (size_t) amt);
n->name = anm;
n->by = abfd;
n->next = NULL;
@@ -1556,7 +1449,6 @@ elf_link_add_object_symbols (abfd, info)
}
free (dynbuf);
- dynbuf = NULL;
}
/* We do not want to include any of the sections in a dynamic
@@ -1606,10 +1498,6 @@ elf_link_add_object_symbols (abfd, info)
if (dyn.d_tag == DT_NEEDED
&& dyn.d_un.d_val == strindex)
{
- if (buf != NULL)
- free (buf);
- if (extversym != NULL)
- free (extversym);
_bfd_elf_strtab_delref (hash_table->dynstr, strindex);
return true;
}
@@ -1627,31 +1515,79 @@ elf_link_add_object_symbols (abfd, info)
elf_dt_name (abfd) = name;
}
- pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
- amt = extsymcount * sizeof (Elf_External_Sym);
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) buf, amt, abfd) != amt)
- goto error_return;
+ /* If this is a dynamic object, we always link against the .dynsym
+ symbol table, not the .symtab symbol table. The dynamic linker
+ will only see the .dynsym symbol table, so there is no reason to
+ look at .symtab for a dynamic object. */
+
+ if (! dynamic || elf_dynsymtab (abfd) == 0)
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ else
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
- if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
+ /* The sh_info field of the symtab header tells us where the
+ external symbols start. We don't care about the local symbols at
+ this point. */
+ if (elf_bad_symtab (abfd))
{
- amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
- pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+ extsymcount = symcount;
+ extsymoff = 0;
+ }
+ else
+ {
+ extsymcount = symcount - hdr->sh_info;
+ extsymoff = hdr->sh_info;
+ }
+
+ sym_hash = NULL;
+ if (extsymcount != 0)
+ {
+ isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
goto error_return;
+
+ /* We store a pointer to the hash table entry for each external
+ symbol. */
+ amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+ sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
+ if (sym_hash == NULL)
+ goto error_free_sym;
+ elf_sym_hashes (abfd) = sym_hash;
+ }
+
+ if (dynamic)
+ {
+ /* Read in any version definitions. */
+ if (! _bfd_elf_slurp_version_tables (abfd))
+ goto error_free_sym;
+
+ /* Read in the symbol versions, but don't bother to convert them
+ to internal format. */
+ if (elf_dynversym (abfd) != 0)
+ {
+ Elf_Internal_Shdr *versymhdr;
+
+ versymhdr = &elf_tdata (abfd)->dynversym_hdr;
+ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+ if (extversym == NULL)
+ goto error_free_sym;
+ amt = versymhdr->sh_size;
+ if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread ((PTR) extversym, amt, abfd) != amt)
+ goto error_free_vers;
+ }
}
weaks = NULL;
ever = extversym != NULL ? extversym + extsymoff : NULL;
- esymend = buf + extsymcount;
- for (esym = buf, shndx = shndx_buf;
- esym < esymend;
- esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL),
- shndx = (shndx != NULL ? shndx + 1 : NULL))
+ for (isym = isymbuf, isymend = isymbuf + extsymcount;
+ isym < isymend;
+ isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
{
- Elf_Internal_Sym sym;
int bind;
bfd_vma value;
asection *sec;
@@ -1666,14 +1602,12 @@ elf_link_add_object_symbols (abfd, info)
override = false;
- elf_swap_symbol_in (abfd, esym, shndx, &sym);
-
flags = BSF_NO_FLAGS;
sec = NULL;
- value = sym.st_value;
+ value = isym->st_value;
*sym_hash = NULL;
- bind = ELF_ST_BIND (sym.st_info);
+ bind = ELF_ST_BIND (isym->st_info);
if (bind == STB_LOCAL)
{
/* This should be impossible, since ELF requires that all
@@ -1684,8 +1618,8 @@ elf_link_add_object_symbols (abfd, info)
}
else if (bind == STB_GLOBAL)
{
- if (sym.st_shndx != SHN_UNDEF
- && sym.st_shndx != SHN_COMMON)
+ if (isym->st_shndx != SHN_UNDEF
+ && isym->st_shndx != SHN_COMMON)
flags = BSF_GLOBAL;
}
else if (bind == STB_WEAK)
@@ -1695,35 +1629,37 @@ elf_link_add_object_symbols (abfd, info)
/* Leave it up to the processor backend. */
}
- if (sym.st_shndx == SHN_UNDEF)
+ if (isym->st_shndx == SHN_UNDEF)
sec = bfd_und_section_ptr;
- else if (sym.st_shndx < SHN_LORESERVE || sym.st_shndx > SHN_HIRESERVE)
+ else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
{
- sec = section_from_elf_index (abfd, sym.st_shndx);
+ sec = section_from_elf_index (abfd, isym->st_shndx);
if (sec == NULL)
sec = bfd_abs_section_ptr;
else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
value -= sec->vma;
}
- else if (sym.st_shndx == SHN_ABS)
+ else if (isym->st_shndx == SHN_ABS)
sec = bfd_abs_section_ptr;
- else if (sym.st_shndx == SHN_COMMON)
+ else if (isym->st_shndx == SHN_COMMON)
{
sec = bfd_com_section_ptr;
/* What ELF calls the size we call the value. What ELF
calls the value we call the alignment. */
- value = sym.st_size;
+ value = isym->st_size;
}
else
{
/* Leave it up to the processor backend. */
}
- name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+ name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ isym->st_name);
if (name == (const char *) NULL)
- goto error_return;
+ goto error_free_vers;
- if (sym.st_shndx == SHN_COMMON && ELF_ST_TYPE (sym.st_info) == STT_TLS)
+ if (isym->st_shndx == SHN_COMMON
+ && ELF_ST_TYPE (isym->st_info) == STT_TLS)
{
asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
@@ -1735,15 +1671,15 @@ elf_link_add_object_symbols (abfd, info)
| SEC_IS_COMMON
| SEC_LINKER_CREATED
| SEC_THREAD_LOCAL)))
- goto error_return;
+ goto error_free_vers;
}
sec = tcomm;
}
else if (add_symbol_hook)
{
- if (! (*add_symbol_hook) (abfd, info, &sym, &name, &flags, &sec,
+ if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec,
&value))
- goto error_return;
+ goto error_free_vers;
/* The hook function sets the name to NULL if this symbol
should be skipped for some reason. */
@@ -1755,7 +1691,7 @@ elf_link_add_object_symbols (abfd, info)
if (sec == (asection *) NULL)
{
bfd_set_error (bfd_error_bad_value);
- goto error_return;
+ goto error_free_vers;
}
if (bfd_is_und_section (sec)
@@ -1786,11 +1722,10 @@ elf_link_add_object_symbols (abfd, info)
|| (vernum > 1 && ! bfd_is_abs_section (sec)))
{
const char *verstr;
- unsigned int namelen;
- bfd_size_type newlen;
+ size_t namelen, verlen, newlen;
char *newname, *p;
- if (sym.st_shndx != SHN_UNDEF)
+ if (isym->st_shndx != SHN_UNDEF)
{
if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
{
@@ -1799,7 +1734,7 @@ elf_link_add_object_symbols (abfd, info)
bfd_archive_filename (abfd), name, vernum,
elf_tdata (abfd)->dynverdef_hdr.sh_info);
bfd_set_error (bfd_error_bad_value);
- goto error_return;
+ goto error_free_vers;
}
else if (vernum > 1)
verstr =
@@ -1839,37 +1774,39 @@ elf_link_add_object_symbols (abfd, info)
(_("%s: %s: invalid needed version %d"),
bfd_archive_filename (abfd), name, vernum);
bfd_set_error (bfd_error_bad_value);
- goto error_return;
+ goto error_free_vers;
}
}
namelen = strlen (name);
- newlen = namelen + strlen (verstr) + 2;
- if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+ verlen = strlen (verstr);
+ newlen = namelen + verlen + 2;
+ if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+ && isym->st_shndx != SHN_UNDEF)
++newlen;
- newname = (char *) bfd_alloc (abfd, newlen);
+ newname = (char *) bfd_alloc (abfd, (bfd_size_type) newlen);
if (newname == NULL)
- goto error_return;
- strcpy (newname, name);
+ goto error_free_vers;
+ memcpy (newname, name, namelen);
p = newname + namelen;
*p++ = ELF_VER_CHR;
/* If this is a defined non-hidden version symbol,
we add another @ to the name. This indicates the
default version of the symbol. */
if ((iver.vs_vers & VERSYM_HIDDEN) == 0
- && sym.st_shndx != SHN_UNDEF)
+ && isym->st_shndx != SHN_UNDEF)
*p++ = ELF_VER_CHR;
- strcpy (p, verstr);
+ memcpy (p, verstr, verlen + 1);
name = newname;
}
}
- if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
+ if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value,
sym_hash, &override, &type_change_ok,
&size_change_ok, dt_needed))
- goto error_return;
+ goto error_free_vers;
if (override)
definition = false;
@@ -1897,7 +1834,7 @@ elf_link_add_object_symbols (abfd, info)
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, flags, sec, value, (const char *) NULL,
false, collect, (struct bfd_link_hash_entry **) sym_hash)))
- goto error_return;
+ goto error_free_vers;
h = *sym_hash;
while (h->root.type == bfd_link_hash_indirect
@@ -1909,7 +1846,7 @@ elf_link_add_object_symbols (abfd, info)
if (dynamic
&& definition
&& (flags & BSF_WEAK) != 0
- && ELF_ST_TYPE (sym.st_info) != STT_FUNC
+ && ELF_ST_TYPE (isym->st_info) != STT_FUNC
&& info->hash->creator->flavour == bfd_target_elf_flavour
&& h->weakdef == NULL)
{
@@ -1931,16 +1868,16 @@ elf_link_add_object_symbols (abfd, info)
}
/* Set the alignment of a common symbol. */
- if (sym.st_shndx == SHN_COMMON
+ if (isym->st_shndx == SHN_COMMON
&& h->root.type == bfd_link_hash_common)
{
unsigned int align;
- align = bfd_log2 (sym.st_value);
+ align = bfd_log2 (isym->st_value);
if (align > old_alignment
/* Permit an alignment power of zero if an alignment of one
is specified and no other alignments have been specified. */
- || (sym.st_value == 1 && old_alignment == 0))
+ || (isym->st_value == 1 && old_alignment == 0))
h->root.u.c.p->alignment_power = align;
}
@@ -1951,16 +1888,16 @@ elf_link_add_object_symbols (abfd, info)
int new_flag;
/* Remember the symbol size and type. */
- if (sym.st_size != 0
+ if (isym->st_size != 0
&& (definition || h->size == 0))
{
- if (h->size != 0 && h->size != sym.st_size && ! size_change_ok)
+ if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
(*_bfd_error_handler)
(_("Warning: size of symbol `%s' changed from %lu to %lu in %s"),
- name, (unsigned long) h->size, (unsigned long) sym.st_size,
- bfd_archive_filename (abfd));
+ name, (unsigned long) h->size,
+ (unsigned long) isym->st_size, bfd_archive_filename (abfd));
- h->size = sym.st_size;
+ h->size = isym->st_size;
}
/* If this is a common symbol, then we always want H->SIZE
@@ -1971,37 +1908,37 @@ elf_link_add_object_symbols (abfd, info)
if (h->root.type == bfd_link_hash_common)
h->size = h->root.u.c.size;
- if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE
+ if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
&& (definition || h->type == STT_NOTYPE))
{
if (h->type != STT_NOTYPE
- && h->type != ELF_ST_TYPE (sym.st_info)
+ && h->type != ELF_ST_TYPE (isym->st_info)
&& ! type_change_ok)
(*_bfd_error_handler)
(_("Warning: type of symbol `%s' changed from %d to %d in %s"),
- name, h->type, ELF_ST_TYPE (sym.st_info),
+ name, h->type, ELF_ST_TYPE (isym->st_info),
bfd_archive_filename (abfd));
- h->type = ELF_ST_TYPE (sym.st_info);
+ h->type = ELF_ST_TYPE (isym->st_info);
}
/* If st_other has a processor-specific meaning, specific code
might be needed here. */
- if (sym.st_other != 0)
+ if (isym->st_other != 0)
{
/* Combine visibilities, using the most constraining one. */
unsigned char hvis = ELF_ST_VISIBILITY (h->other);
- unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+ unsigned char symvis = ELF_ST_VISIBILITY (isym->st_other);
if (symvis && (hvis > symvis || hvis == 0))
- h->other = sym.st_other;
+ h->other = isym->st_other;
/* If neither has visibility, use the st_other of the
definition. This is an arbitrary choice, since the
other bits have no general meaning. */
if (!symvis && !hvis
&& (definition || h->other == 0))
- h->other = sym.st_other;
+ h->other = isym->st_other;
}
/* Set a flag in the hash table entry indicating the type of
@@ -2045,21 +1982,21 @@ elf_link_add_object_symbols (abfd, info)
/* Check to see if we need to add an indirect symbol for
the default name. */
if (definition || h->root.type == bfd_link_hash_common)
- if (! elf_add_default_symbol (abfd, info, h, name, &sym,
+ if (! elf_add_default_symbol (abfd, info, h, name, isym,
&sec, &value, &dynsym,
override, dt_needed))
- goto error_return;
+ goto error_free_vers;
if (dynsym && h->dynindx == -1)
{
if (! _bfd_elf_link_record_dynamic_symbol (info, h))
- goto error_return;
+ goto error_free_vers;
if (h->weakdef != NULL
&& ! new_weakdef
&& h->weakdef->dynindx == -1)
{
if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
- goto error_return;
+ goto error_free_vers;
}
}
else if (dynsym && h->dynindx != -1)
@@ -2082,7 +2019,7 @@ elf_link_add_object_symbols (abfd, info)
bfd_size_type strindex;
if (! is_elf_hash_table (info))
- goto error_return;
+ goto error_free_vers;
/* The symbol from a DT_NEEDED object is referenced from
the regular object to create a dynamic executable. We
@@ -2093,7 +2030,7 @@ elf_link_add_object_symbols (abfd, info)
strindex = _bfd_elf_strtab_add (hash_table->dynstr,
elf_dt_soname (abfd), false);
if (strindex == (bfd_size_type) -1)
- goto error_return;
+ goto error_free_vers;
if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
{
@@ -2119,11 +2056,21 @@ elf_link_add_object_symbols (abfd, info)
}
if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NEEDED, strindex))
- goto error_return;
+ goto error_free_vers;
}
}
}
+ if (extversym != NULL)
+ {
+ free (extversym);
+ extversym = NULL;
+ }
+
+ if (isymbuf != NULL)
+ free (isymbuf);
+ isymbuf = NULL;
+
/* Now set the weakdefs field correctly for all the weak defined
symbols we found. The only way to do this is to search all the
symbols. Since we only need the information for non functions in
@@ -2191,24 +2138,11 @@ elf_link_add_object_symbols (abfd, info)
if (! _bfd_elf_link_record_dynamic_symbol (info, hlook))
goto error_return;
}
-
break;
}
}
}
- if (buf != NULL)
- {
- free (buf);
- buf = NULL;
- }
-
- if (extversym != NULL)
- {
- free (extversym);
- extversym = NULL;
- }
-
/* If this object is the same format as the output object, and it is
not a shared library, then let the backend look through the
relocs.
@@ -2254,7 +2188,7 @@ elf_link_add_object_symbols (abfd, info)
ok = (*check_relocs) (abfd, info, o, internal_relocs);
- if (! info->keep_memory)
+ if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
if (! ok)
@@ -2317,15 +2251,29 @@ elf_link_add_object_symbols (abfd, info)
}
}
+ if (is_elf_hash_table (info))
+ {
+ /* Add this bfd to the loaded list. */
+ struct elf_link_loaded_list *n;
+
+ n = ((struct elf_link_loaded_list *)
+ bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)));
+ if (n == NULL)
+ goto error_return;
+ n->abfd = abfd;
+ n->next = hash_table->loaded;
+ hash_table->loaded = n;
+ }
+
return true;
- error_return:
- if (buf != NULL)
- free (buf);
- if (dynbuf != NULL)
- free (dynbuf);
+ error_free_vers:
if (extversym != NULL)
free (extversym);
+ error_free_sym:
+ if (isymbuf != NULL)
+ free (isymbuf);
+ error_return:
return false;
}
@@ -2506,92 +2454,6 @@ elf_add_dynamic_entry (info, tag, val)
return true;
}
-
-/* Record a new local dynamic symbol. */
-
-boolean
-elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
- struct bfd_link_info *info;
- bfd *input_bfd;
- long input_indx;
-{
- struct elf_link_local_dynamic_entry *entry;
- struct elf_link_hash_table *eht;
- struct elf_strtab_hash *dynstr;
- Elf_External_Sym esym;
- Elf_External_Sym_Shndx eshndx;
- Elf_External_Sym_Shndx *shndx;
- unsigned long dynstr_index;
- char *name;
- file_ptr pos;
- bfd_size_type amt;
-
- if (! is_elf_hash_table (info))
- return false;
-
- /* See if the entry exists already. */
- for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
- if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
- return true;
-
- entry = (struct elf_link_local_dynamic_entry *)
- bfd_alloc (input_bfd, (bfd_size_type) sizeof (*entry));
- if (entry == NULL)
- return false;
-
- /* Go find the symbol, so that we can find it's name. */
- amt = sizeof (Elf_External_Sym);
- pos = elf_tdata (input_bfd)->symtab_hdr.sh_offset + input_indx * amt;
- if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) &esym, amt, input_bfd) != amt)
- return false;
- shndx = NULL;
- if (elf_tdata (input_bfd)->symtab_shndx_hdr.sh_size != 0)
- {
- amt = sizeof (Elf_External_Sym_Shndx);
- pos = elf_tdata (input_bfd)->symtab_shndx_hdr.sh_offset;
- pos += input_indx * amt;
- shndx = &eshndx;
- if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx, amt, input_bfd) != amt)
- return false;
- }
- elf_swap_symbol_in (input_bfd, &esym, shndx, &entry->isym);
-
- name = (bfd_elf_string_from_elf_section
- (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
- entry->isym.st_name));
-
- dynstr = elf_hash_table (info)->dynstr;
- if (dynstr == NULL)
- {
- /* Create a strtab to hold the dynamic symbol names. */
- elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
- if (dynstr == NULL)
- return false;
- }
-
- dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
- if (dynstr_index == (unsigned long) -1)
- return false;
- entry->isym.st_name = dynstr_index;
-
- eht = elf_hash_table (info);
-
- entry->next = eht->dynlocal;
- eht->dynlocal = entry;
- entry->input_bfd = input_bfd;
- entry->input_indx = input_indx;
- eht->dynsymcount++;
-
- /* Whatever binding the symbol had before, it's now local. */
- entry->isym.st_info
- = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
-
- /* The dynindx will be set at the end of size_dynamic_sections. */
-
- return true;
-}
/* Read and swap the relocs from the section indicated by SHDR. This
may be either a REL or a RELA section. The relocations are
@@ -2909,11 +2771,11 @@ compute_bucket_count (info)
elf_link_hash_traverse (elf_hash_table (info),
elf_collect_hash_codes, &hashcodesp);
-/* We have a problem here. The following code to optimize the table
- size requires an integer type with more the 32 bits. If
- BFD_HOST_U_64_BIT is set we know about such a type. */
+ /* We have a problem here. The following code to optimize the table
+ size requires an integer type with more the 32 bits. If
+ BFD_HOST_U_64_BIT is set we know about such a type. */
#ifdef BFD_HOST_U_64_BIT
- if (info->optimize == true)
+ if (info->optimize)
{
unsigned long int nsyms = hashcodesp - hashcodes;
size_t minsize;
@@ -3054,7 +2916,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
return true;
if (! is_elf_hash_table (info))
- return false;
+ return true;
/* Any syms created from now on start with -1 in
got.refcount/offset and plt.refcount/offset. */
@@ -3082,6 +2944,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
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);
@@ -3162,6 +3027,57 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
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;
@@ -3174,6 +3090,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
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),
@@ -3229,7 +3167,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
{
(*_bfd_error_handler)
(_("%s: .preinit_array section is not allowed in DSO"),
- bfd_archive_filename (sub));
+ bfd_archive_filename (sub));
break;
}
@@ -3664,10 +3602,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
BFD_ASSERT (s != NULL);
hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
- s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+ s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size);
if (s->contents == NULL)
return false;
- memset (s->contents, 0, (size_t) s->_raw_size);
bfd_put (8 * hash_entry_size, output_bfd, (bfd_vma) bucketcount,
s->contents);
@@ -3966,7 +3903,7 @@ elf_fix_symbol_flags (h, eif)
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);
}
}
@@ -4086,7 +4023,7 @@ elf_adjust_dynamic_symbol (h, data)
&& (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
(*_bfd_error_handler)
(_("warning: type and size of dynamic symbol `%s' are not defined"),
- h->root.root.string);
+ h->root.root.string);
dynobj = elf_hash_table (eif->info)->dynobj;
bed = get_elf_backend_data (dynobj);
@@ -4146,7 +4083,7 @@ elf_export_symbol (h, data)
if (!eif->verdefs)
{
-doit:
+ doit:
if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
{
eif->failed = true;
@@ -4313,7 +4250,7 @@ elf_link_assign_sym_version (h, data)
alc = bfd_malloc ((bfd_size_type) len);
if (alc == NULL)
return false;
- strncpy (alc, h->root.root.string, len - 1);
+ memcpy (alc, h->root.root.string, len - 1);
alc[len - 1] = '\0';
if (alc[len - 2] == ELF_VER_CHR)
alc[len - 2] = '\0';
@@ -4416,45 +4353,58 @@ elf_link_assign_sym_version (h, data)
if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
{
struct bfd_elf_version_tree *t;
- struct bfd_elf_version_tree *deflt;
+ struct bfd_elf_version_tree *local_ver;
struct bfd_elf_version_expr *d;
/* See if can find what version this symbol is in. If the
symbol is supposed to be local, then don't actually register
it. */
- deflt = NULL;
+ local_ver = NULL;
for (t = sinfo->verdefs; t != NULL; t = t->next)
{
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;
- 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)
{
for (d = t->locals; d != NULL; d = d->next)
{
+ /* If the match is "*", keep looking for a more
+ explicit, perhaps even global, match. */
if (d->pattern[0] == '*' && d->pattern[1] == '\0')
- deflt = t;
+ local_ver = t;
else if ((*d->match) (d, h->root.root.string))
{
- h->verinfo.vertree = t;
- if (h->dynindx != -1
- && info->shared
- && ! info->export_dynamic)
- {
- (*bed->elf_backend_hide_symbol) (info, h, true);
- }
+ local_ver = t;
break;
}
}
@@ -4464,9 +4414,9 @@ elf_link_assign_sym_version (h, data)
}
}
- if (deflt != NULL && h->verinfo.vertree == NULL)
+ if (local_ver != NULL)
{
- h->verinfo.vertree = deflt;
+ h->verinfo.vertree = local_ver;
if (h->dynindx != -1
&& info->shared
&& ! info->export_dynamic)
@@ -4538,6 +4488,8 @@ static boolean elf_link_output_extsym
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_link_sec_merge_syms
PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_check_versioned_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static boolean elf_link_input_bfd
PARAMS ((struct elf_final_link_info *, bfd *));
static boolean elf_reloc_link_order
@@ -4681,7 +4633,7 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irela[j].r_info));
+ ELF_R_TYPE (irela[j].r_info));
if (bed->s->swap_reloca_out)
(*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela);
@@ -4694,10 +4646,12 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
free (irela);
}
-struct elf_link_sort_rela {
+struct elf_link_sort_rela
+{
bfd_vma offset;
enum elf_reloc_type_class type;
- union {
+ union
+ {
Elf_Internal_Rel rel;
Elf_Internal_Rela rela;
} u;
@@ -5033,7 +4987,7 @@ elf_bfd_final_link (abfd, info)
o->reloc_count
+= (*bed->elf_backend_count_relocs) (sec, relocs);
- if (!info->keep_memory)
+ if (elf_section_data (o)->relocs != relocs)
free (relocs);
}
@@ -5371,7 +5325,7 @@ elf_bfd_final_link (abfd, info)
size = 0;
for (o = sec->link_order_head; o != NULL; o = o->next)
if (size < o->offset + o->size)
- size = o->offset + o->size;
+ size = o->offset + o->size;
}
end = sec->vma + size;
}
@@ -5510,8 +5464,8 @@ elf_bfd_final_link (abfd, info)
sym = e->isym;
if (e->isym.st_shndx != SHN_UNDEF
- && (e->isym.st_shndx < SHN_LORESERVE
- || e->isym.st_shndx > SHN_HIRESERVE))
+ && (e->isym.st_shndx < SHN_LORESERVE
+ || e->isym.st_shndx > SHN_HIRESERVE))
{
s = bfd_section_from_elf_index (e->input_bfd,
e->isym.st_shndx);
@@ -5694,7 +5648,13 @@ elf_bfd_final_link (abfd, info)
name = ".fini_array";
get_size:
o = bfd_get_section_by_name (abfd, name);
- BFD_ASSERT (o != NULL);
+ if (o == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%s: could not find output section %s"),
+ bfd_get_filename (abfd), name);
+ goto error_return;
+ }
if (o->_raw_size == 0)
(*_bfd_error_handler)
(_("warning: %s section has zero size"), name);
@@ -5731,7 +5691,13 @@ elf_bfd_final_link (abfd, info)
name = ".gnu.version";
get_vma:
o = bfd_get_section_by_name (abfd, name);
- BFD_ASSERT (o != NULL);
+ if (o == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%s: could not find output section %s"),
+ bfd_get_filename (abfd), name);
+ goto error_return;
+ }
dyn.d_un.d_ptr = o->vma;
elf_swap_dyn_out (dynobj, &dyn, dyncon);
break;
@@ -5810,6 +5776,15 @@ elf_bfd_final_link (abfd, info)
}
}
+ if (info->relocateable)
+ {
+ boolean failed = false;
+
+ bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
+ if (failed)
+ goto error_return;
+ }
+
/* If we have optimized stabs strings, output them. */
if (elf_hash_table (info)->stab_info != NULL)
{
@@ -6023,6 +5998,127 @@ elf_link_sec_merge_syms (h, data)
return true;
}
+/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in
+ allowing an unsatisfied unversioned symbol in the DSO to match a
+ versioned symbol that would normally require an explicit version. */
+
+static boolean
+elf_link_check_versioned_symbol (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ bfd *undef_bfd = h->root.u.undef.abfd;
+ struct elf_link_loaded_list *loaded;
+
+ if ((undef_bfd->flags & DYNAMIC) == 0
+ || info->hash->creator->flavour != bfd_target_elf_flavour
+ || elf_dt_soname (h->root.u.undef.abfd) == NULL)
+ return false;
+
+ for (loaded = elf_hash_table (info)->loaded;
+ loaded != NULL;
+ loaded = loaded->next)
+ {
+ bfd *input;
+ Elf_Internal_Shdr *hdr;
+ bfd_size_type symcount;
+ bfd_size_type extsymcount;
+ bfd_size_type extsymoff;
+ Elf_Internal_Shdr *versymhdr;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
+ Elf_Internal_Sym *isymbuf;
+ Elf_External_Versym *ever;
+ Elf_External_Versym *extversym;
+
+ input = loaded->abfd;
+
+ /* We check each DSO for a possible hidden versioned definition. */
+ if (input == undef_bfd
+ || (input->flags & DYNAMIC) == 0
+ || elf_dynversym (input) == 0)
+ continue;
+
+ hdr = &elf_tdata (input)->dynsymtab_hdr;
+
+ symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+ if (elf_bad_symtab (input))
+ {
+ extsymcount = symcount;
+ extsymoff = 0;
+ }
+ else
+ {
+ extsymcount = symcount - hdr->sh_info;
+ extsymoff = hdr->sh_info;
+ }
+
+ if (extsymcount == 0)
+ continue;
+
+ isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ return false;
+
+ /* Read in any version definitions. */
+ versymhdr = &elf_tdata (input)->dynversym_hdr;
+ extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+ if (extversym == NULL)
+ goto error_ret;
+
+ if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0
+ || (bfd_bread ((PTR) extversym, versymhdr->sh_size, input)
+ != versymhdr->sh_size))
+ {
+ free (extversym);
+ error_ret:
+ free (isymbuf);
+ return false;
+ }
+
+ ever = extversym + extsymoff;
+ isymend = isymbuf + extsymcount;
+ for (isym = isymbuf; isym < isymend; isym++, ever++)
+ {
+ const char *name;
+ Elf_Internal_Versym iver;
+
+ if (ELF_ST_BIND (isym->st_info) == STB_LOCAL
+ || isym->st_shndx == SHN_UNDEF)
+ continue;
+
+ name = bfd_elf_string_from_elf_section (input,
+ hdr->sh_link,
+ isym->st_name);
+ if (strcmp (name, h->root.root.string) != 0)
+ continue;
+
+ _bfd_elf_swap_versym_in (input, ever, &iver);
+
+ if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+ {
+ /* If we have a non-hidden versioned sym, then it should
+ have provided a definition for the undefined sym. */
+ abort ();
+ }
+
+ if ((iver.vs_vers & VERSYM_VERSION) == 2)
+ {
+ /* This is the oldest (default) sym. We can use it. */
+ free (extversym);
+ free (isymbuf);
+ return true;
+ }
+ }
+
+ free (extversym);
+ free (isymbuf);
+ }
+
+ return false;
+}
+
/* Add an external symbol to the symbol table. This is called from
the hash table traversal routine. When generating a shared object,
we go through the symbol table twice. The first time we output
@@ -6072,7 +6168,8 @@ elf_link_output_extsym (h, data)
&& ! finfo->info->shared
&& h->root.type == bfd_link_hash_undefined
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0)
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
+ && ! elf_link_check_versioned_symbol (finfo->info, h))
{
if (! ((*finfo->info->callbacks->undefined_symbol)
(finfo->info, h->root.root.string, h->root.u.undef.abfd,
@@ -6245,8 +6342,8 @@ elf_link_output_extsym (h, data)
sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other);
/* If this symbol should be put in the .dynsym section, then put it
- there now. We have already know the symbol index. We also fill
- in the entry in the .hash section. */
+ there now. We already know the symbol index. We also fill in
+ the entry in the .hash section. */
if (h->dynindx != -1
&& elf_hash_table (finfo->info)->dynamic_sections_created)
{
@@ -6305,7 +6402,7 @@ elf_link_output_extsym (h, data)
/* If we're stripping it, then it was just a dynamic symbol, and
there's nothing else to do. */
- if (strip)
+ if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
return true;
h->indx = bfd_get_symcount (finfo->output_bfd);
@@ -6357,19 +6454,19 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
}
else
{
- (*_bfd_error_handler) (
- _("%s: relocation size mismatch in %s section %s"),
- bfd_get_filename (output_bfd),
- bfd_archive_filename (input_section->owner),
- input_section->name);
+ (*_bfd_error_handler)
+ (_("%s: relocation size mismatch in %s section %s"),
+ bfd_get_filename (output_bfd),
+ bfd_archive_filename (input_section->owner),
+ input_section->name);
bfd_set_error (bfd_error_wrong_object_format);
return false;
}
bed = get_elf_backend_data (output_bfd);
irela = internal_relocs;
- irelaend = irela + NUM_SHDR_ENTRIES (input_rel_hdr)
- * bed->s->int_rels_per_ext_rel;
+ irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+ * bed->s->int_rels_per_ext_rel);
if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
{
@@ -6441,15 +6538,11 @@ elf_link_input_bfd (finfo, input_bfd)
Elf_Internal_Sym *, asection **));
bfd *output_bfd;
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
size_t locsymcount;
size_t extsymoff;
- Elf_External_Sym *external_syms;
- Elf_External_Sym *esym;
- Elf_External_Sym *esymend;
- Elf_External_Sym_Shndx *shndx_buf;
- Elf_External_Sym_Shndx *shndx;
+ Elf_Internal_Sym *isymbuf;
Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
long *pindex;
asection **ppsection;
asection *o;
@@ -6484,44 +6577,29 @@ elf_link_input_bfd (finfo, input_bfd)
}
/* Read the local symbols. */
- if (symtab_hdr->contents != NULL)
- external_syms = (Elf_External_Sym *) symtab_hdr->contents;
- else if (locsymcount == 0)
- external_syms = NULL;
- else
- {
- bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym);
- external_syms = finfo->external_syms;
- if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (external_syms, amt, input_bfd) != amt)
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL && locsymcount != 0)
+ {
+ isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
+ finfo->internal_syms,
+ finfo->external_syms,
+ finfo->locsym_shndx);
+ if (isymbuf == NULL)
return false;
}
- shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
- shndx_buf = NULL;
- if (shndx_hdr->sh_size != 0 && locsymcount != 0)
- {
- bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym_Shndx);
- shndx_buf = finfo->locsym_shndx;
- if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (shndx_buf, amt, input_bfd) != amt)
- return false;
- }
-
- /* Swap in the local symbols and write out the ones which we know
- are going into the output file. */
- for (esym = external_syms, esymend = esym + locsymcount,
- isym = finfo->internal_syms, pindex = finfo->indices,
- ppsection = finfo->sections, shndx = shndx_buf;
- esym < esymend;
- esym++, isym++, pindex++, ppsection++,
- shndx = (shndx != NULL ? shndx + 1 : NULL))
+ /* Find local symbol sections and adjust values of symbols in
+ SEC_MERGE sections. Write out those local symbols we know are
+ going into the output file. */
+ isymend = isymbuf + locsymcount;
+ for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections;
+ isym < isymend;
+ isym++, pindex++, ppsection++)
{
asection *isec;
const char *name;
Elf_Internal_Sym osym;
- elf_swap_symbol_in (input_bfd, esym, shndx, isym);
*pindex = -1;
if (elf_bad_symtab (input_bfd))
@@ -6560,7 +6638,7 @@ elf_link_input_bfd (finfo, input_bfd)
*ppsection = isec;
/* Don't output the first, undefined, symbol. */
- if (esym == external_syms)
+ if (ppsection == finfo->sections)
continue;
if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
@@ -6830,7 +6908,7 @@ elf_link_input_bfd (finfo, input_bfd)
if (! (*relocate_section) (output_bfd, finfo->info,
input_bfd, o, contents,
internal_relocs,
- finfo->internal_syms,
+ isymbuf,
finfo->sections))
return false;
@@ -6839,7 +6917,7 @@ elf_link_input_bfd (finfo, input_bfd)
Elf_Internal_Rela *irela;
Elf_Internal_Rela *irelaend;
struct elf_link_hash_entry **rel_hash;
- Elf_Internal_Shdr *input_rel_hdr;
+ Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
unsigned int next_erel;
boolean (*reloc_emitter) PARAMS ((bfd *, asection *,
Elf_Internal_Shdr *,
@@ -6862,6 +6940,7 @@ elf_link_input_bfd (finfo, input_bfd)
{
unsigned long r_symndx;
asection *sec;
+ Elf_Internal_Sym sym;
if (next_erel == bed->s->int_rels_per_ext_rel)
{
@@ -6914,9 +6993,9 @@ elf_link_input_bfd (finfo, input_bfd)
/* This is a reloc against a local symbol. */
*rel_hash = NULL;
- isym = finfo->internal_syms + r_symndx;
+ sym = isymbuf[r_symndx];
sec = finfo->sections[r_symndx];
- if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+ if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
{
/* I suppose the backend ought to fill in the
section of any STT_SECTION symbol against a
@@ -6939,7 +7018,7 @@ elf_link_input_bfd (finfo, input_bfd)
}
/* Adjust the addend according to where the
- section winds up in the output section. */
+ section winds up in the output section. */
if (rela_normal)
irela->r_addend += sec->output_offset;
}
@@ -6963,34 +7042,34 @@ elf_link_input_bfd (finfo, input_bfd)
must output it now. */
shlink = symtab_hdr->sh_link;
name = (bfd_elf_string_from_elf_section
- (input_bfd, shlink, isym->st_name));
+ (input_bfd, shlink, sym.st_name));
if (name == NULL)
return false;
osec = sec->output_section;
- isym->st_shndx =
+ sym.st_shndx =
_bfd_elf_section_from_bfd_section (output_bfd,
osec);
- if (isym->st_shndx == SHN_BAD)
+ if (sym.st_shndx == SHN_BAD)
return false;
- isym->st_value += sec->output_offset;
+ sym.st_value += sec->output_offset;
if (! finfo->info->relocateable)
{
- isym->st_value += osec->vma;
- if (ELF_ST_TYPE (isym->st_info) == STT_TLS)
+ sym.st_value += osec->vma;
+ if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
{
/* STT_TLS symbols are relative to PT_TLS
segment base. */
BFD_ASSERT (finfo->first_tls_sec != NULL);
- isym->st_value -= finfo->first_tls_sec->vma;
+ sym.st_value -= finfo->first_tls_sec->vma;
}
}
finfo->indices[r_symndx]
= bfd_get_symcount (output_bfd);
- if (! elf_link_output_sym (finfo, name, isym, sec))
+ if (! elf_link_output_sym (finfo, name, &sym, sec))
return false;
}
@@ -7009,20 +7088,20 @@ elf_link_input_bfd (finfo, input_bfd)
else
reloc_emitter = elf_link_output_relocs;
- if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
- internal_relocs))
+ if (input_rel_hdr->sh_size != 0
+ && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+ internal_relocs))
return false;
- input_rel_hdr = elf_section_data (o)->rel_hdr2;
- if (input_rel_hdr)
+ input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
+ if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
{
internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
* bed->s->int_rels_per_ext_rel);
- if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+ if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2,
internal_relocs))
return false;
}
-
}
}
@@ -7539,28 +7618,27 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h,
/* Garbage collect unused sections. */
static boolean elf_gc_mark
- PARAMS ((struct bfd_link_info *info, asection *sec,
- asection * (*gc_mark_hook)
- PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *, Elf_Internal_Sym *))));
+ PARAMS ((struct bfd_link_info *, asection *,
+ asection * (*) (asection *, struct bfd_link_info *,
+ Elf_Internal_Rela *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *)));
static boolean elf_gc_sweep
- PARAMS ((struct bfd_link_info *info,
- boolean (*gc_sweep_hook)
- PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
- const Elf_Internal_Rela *relocs))));
+ PARAMS ((struct bfd_link_info *,
+ boolean (*) (bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *)));
static boolean elf_gc_sweep_symbol
- PARAMS ((struct elf_link_hash_entry *h, PTR idxptr));
+ PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_gc_allocate_got_offsets
- PARAMS ((struct elf_link_hash_entry *h, PTR offarg));
+ PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_gc_propagate_vtable_entries_used
- PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+ PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_gc_smash_unused_vtentry_relocs
- PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+ PARAMS ((struct elf_link_hash_entry *, PTR));
/* The mark phase of garbage collection. For a given section, mark
it and any sections in this section's group, and all the sections
@@ -7570,9 +7648,10 @@ static boolean
elf_gc_mark (info, sec, gc_mark_hook)
struct bfd_link_info *info;
asection *sec;
- asection * (*gc_mark_hook)
- PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
- struct elf_link_hash_entry *, Elf_Internal_Sym *));
+ asection * (*gc_mark_hook) PARAMS ((asection *, struct bfd_link_info *,
+ Elf_Internal_Rela *,
+ struct elf_link_hash_entry *,
+ Elf_Internal_Sym *));
{
boolean ret;
asection *group_sec;
@@ -7591,17 +7670,12 @@ elf_gc_mark (info, sec, gc_mark_hook)
{
Elf_Internal_Rela *relstart, *rel, *relend;
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
struct elf_link_hash_entry **sym_hashes;
size_t nlocsyms;
size_t extsymoff;
- Elf_External_Sym *locsyms, *freesyms = NULL;
- Elf_External_Sym_Shndx *locsym_shndx;
bfd *input_bfd = sec->owner;
struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
-
- /* GCFIXME: how to arrange so that relocs and symbols are not
- reread continually? */
+ Elf_Internal_Sym *isym = NULL;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
@@ -7615,37 +7689,18 @@ elf_gc_mark (info, sec, gc_mark_hook)
else
extsymoff = nlocsyms = symtab_hdr->sh_info;
- if (symtab_hdr->contents)
- locsyms = (Elf_External_Sym *) symtab_hdr->contents;
- else if (nlocsyms == 0)
- locsyms = NULL;
- else
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isym == NULL && nlocsyms != 0)
{
- bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym);
- locsyms = freesyms = bfd_malloc (amt);
- if (freesyms == NULL
- || bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (locsyms, amt, input_bfd) != amt)
- {
- ret = false;
- goto out1;
- }
- }
-
- shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
- locsym_shndx = NULL;
- if (shndx_hdr->sh_size != 0 && nlocsyms != 0)
- {
- bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym_Shndx);
- locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (locsym_shndx, amt, input_bfd) != amt)
+ isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
+ NULL, NULL, NULL);
+ if (isym == NULL)
return false;
}
/* Read the relocations. */
relstart = (NAME(_bfd_elf,link_read_relocs)
- (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL,
+ (input_bfd, sec, NULL, (Elf_Internal_Rela *) NULL,
info->keep_memory));
if (relstart == NULL)
{
@@ -7659,38 +7714,20 @@ elf_gc_mark (info, sec, gc_mark_hook)
unsigned long r_symndx;
asection *rsec;
struct elf_link_hash_entry *h;
- Elf_Internal_Sym s;
r_symndx = ELF_R_SYM (rel->r_info);
if (r_symndx == 0)
continue;
- if (elf_bad_symtab (sec->owner))
- {
- elf_swap_symbol_in (input_bfd,
- locsyms + r_symndx,
- locsym_shndx + (locsym_shndx ? r_symndx : 0),
- &s);
- if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
- rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
- else
- {
- h = sym_hashes[r_symndx - extsymoff];
- rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
- }
- }
- else if (r_symndx >= nlocsyms)
+ if (r_symndx >= nlocsyms
+ || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
{
h = sym_hashes[r_symndx - extsymoff];
- rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
+ rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
}
else
{
- elf_swap_symbol_in (input_bfd,
- locsyms + r_symndx,
- locsym_shndx + (locsym_shndx ? r_symndx : 0),
- &s);
- rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
+ rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
}
if (rsec && !rsec->gc_mark)
@@ -7706,11 +7743,16 @@ elf_gc_mark (info, sec, gc_mark_hook)
}
out2:
- if (!info->keep_memory)
+ if (elf_section_data (sec)->relocs != relstart)
free (relstart);
out1:
- if (freesyms)
- free (freesyms);
+ if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
+ {
+ if (! info->keep_memory)
+ free (isym);
+ else
+ symtab_hdr->contents = (unsigned char *) isym;
+ }
}
return ret;
@@ -7721,9 +7763,8 @@ elf_gc_mark (info, sec, gc_mark_hook)
static boolean
elf_gc_sweep (info, gc_sweep_hook)
struct bfd_link_info *info;
- boolean (*gc_sweep_hook)
- PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
- const Elf_Internal_Rela *relocs));
+ boolean (*gc_sweep_hook) PARAMS ((bfd *, struct bfd_link_info *,
+ asection *, const Elf_Internal_Rela *));
{
bfd *sub;
@@ -7767,7 +7808,7 @@ elf_gc_sweep (info, gc_sweep_hook)
r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
- if (!info->keep_memory)
+ if (elf_section_data (o)->relocs != internal_relocs)
free (internal_relocs);
if (!r)
@@ -7938,7 +7979,7 @@ elf_gc_sections (abfd, info)
boolean ok = true;
bfd *sub;
asection * (*gc_mark_hook)
- PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+ PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *h, Elf_Internal_Sym *));
if (!get_elf_backend_data (abfd)->can_gc_sections
@@ -8265,7 +8306,6 @@ elf_reloc_symbol_deleted_p (offset, cookie)
for (; rcookie->rel < rcookie->relend; rcookie->rel++)
{
unsigned long r_symndx = ELF_R_SYM (rcookie->rel->r_info);
- Elf_Internal_Sym isym;
if (! rcookie->bad_symtab)
if (rcookie->rel->r_offset > offset)
@@ -8273,21 +8313,8 @@ elf_reloc_symbol_deleted_p (offset, cookie)
if (rcookie->rel->r_offset != offset)
continue;
- if (rcookie->locsyms && r_symndx < rcookie->locsymcount)
- {
- Elf_External_Sym *lsym;
- Elf_External_Sym_Shndx *lshndx;
-
- lsym = (Elf_External_Sym *) rcookie->locsyms + r_symndx;
- lshndx = (Elf_External_Sym_Shndx *) rcookie->locsym_shndx;
- if (lshndx != NULL)
- lshndx += r_symndx;
- elf_swap_symbol_in (rcookie->abfd, lsym, lshndx, &isym);
- }
-
if (r_symndx >= rcookie->locsymcount
- || (rcookie->locsyms
- && ELF_ST_BIND (isym.st_info) != STB_LOCAL))
+ || ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL)
{
struct elf_link_hash_entry *h;
@@ -8304,17 +8331,19 @@ elf_reloc_symbol_deleted_p (offset, cookie)
else
return false;
}
- else if (rcookie->locsyms)
+ else
{
/* It's not a relocation against a global symbol,
but it could be a relocation against a local
symbol for a discarded section. */
asection *isec;
+ Elf_Internal_Sym *isym;
/* Need to: get the symbol; get the section. */
- if (isym.st_shndx < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE)
+ isym = &rcookie->locsyms[r_symndx];
+ if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
{
- isec = section_from_elf_index (rcookie->abfd, isym.st_shndx);
+ isec = section_from_elf_index (rcookie->abfd, isym->st_shndx);
if (isec != NULL && elf_discarded_section (isec))
return true;
}
@@ -8337,8 +8366,6 @@ elf_bfd_discard_info (output_bfd, info)
struct elf_reloc_cookie cookie;
asection *stab, *eh, *ehdr;
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
- Elf_External_Sym *freesyms;
struct elf_backend_data *bed;
bfd *abfd;
boolean ret = false;
@@ -8389,8 +8416,6 @@ elf_bfd_discard_info (output_bfd, info)
continue;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-
cookie.abfd = abfd;
cookie.sym_hashes = elf_sym_hashes (abfd);
cookie.bad_symtab = elf_bad_symtab (abfd);
@@ -8406,48 +8431,20 @@ elf_bfd_discard_info (output_bfd, info)
cookie.extsymoff = symtab_hdr->sh_info;
}
- freesyms = NULL;
- if (symtab_hdr->contents)
- cookie.locsyms = (void *) symtab_hdr->contents;
- else if (cookie.locsymcount == 0)
- cookie.locsyms = NULL;
- else
+ cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (cookie.locsyms == NULL && cookie.locsymcount != 0)
{
- bfd_size_type amt = cookie.locsymcount * sizeof (Elf_External_Sym);
- cookie.locsyms = bfd_malloc (amt);
+ cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ cookie.locsymcount, 0,
+ NULL, NULL, NULL);
if (cookie.locsyms == NULL)
return false;
- freesyms = cookie.locsyms;
- if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (cookie.locsyms, amt, abfd) != amt)
- {
- error_ret_free_loc:
- free (cookie.locsyms);
- return false;
- }
- }
-
- cookie.locsym_shndx = NULL;
- if (shndx_hdr->sh_size != 0 && cookie.locsymcount != 0)
- {
- bfd_size_type amt;
- amt = cookie.locsymcount * sizeof (Elf_External_Sym_Shndx);
- cookie.locsym_shndx = bfd_malloc (amt);
- if (cookie.locsym_shndx == NULL)
- goto error_ret_free_loc;
- if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (cookie.locsym_shndx, amt, abfd) != amt)
- {
- free (cookie.locsym_shndx);
- goto error_ret_free_loc;
- }
}
if (stab)
{
cookie.rels = (NAME(_bfd_elf,link_read_relocs)
- (abfd, stab, (PTR) NULL,
- (Elf_Internal_Rela *) NULL,
+ (abfd, stab, (PTR) NULL, (Elf_Internal_Rela *) NULL,
info->keep_memory));
if (cookie.rels)
{
@@ -8459,7 +8456,7 @@ elf_bfd_discard_info (output_bfd, info)
elf_reloc_symbol_deleted_p,
&cookie))
ret = true;
- if (! info->keep_memory)
+ if (elf_section_data (stab)->relocs != cookie.rels)
free (cookie.rels);
}
}
@@ -8483,7 +8480,7 @@ elf_bfd_discard_info (output_bfd, info)
elf_reloc_symbol_deleted_p,
&cookie))
ret = true;
- if (! info->keep_memory)
+ if (cookie.rels && elf_section_data (eh)->relocs != cookie.rels)
free (cookie.rels);
}
@@ -8493,11 +8490,14 @@ elf_bfd_discard_info (output_bfd, info)
ret = true;
}
- if (cookie.locsym_shndx != NULL)
- free (cookie.locsym_shndx);
-
- if (freesyms != NULL)
- free (freesyms);
+ if (cookie.locsyms != NULL
+ && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
+ {
+ if (! info->keep_memory)
+ free (cookie.locsyms);
+ else
+ symtab_hdr->contents = (unsigned char *) cookie.locsyms;
+ }
}
if (ehdr && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info, ehdr))