static boolean elf_link_add_archive_symbols
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_merge_symbol
- PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
- asection **, bfd_vma *, struct elf_link_hash_entry **,
- boolean *, boolean *, boolean *, boolean));
+ PARAMS ((bfd *, struct bfd_link_info *, const char *,
+ Elf_Internal_Sym *, asection **, bfd_vma *,
+ struct elf_link_hash_entry **, boolean *, boolean *,
+ boolean *, boolean));
+static boolean elf_add_default_symbol
+ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+ const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
+ boolean *, boolean, boolean));
static boolean elf_export_symbol
PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_finalize_dynstr
+ PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf_fix_symbol_flags
PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *));
static boolean elf_adjust_dynamic_symbol
PARAMS ((const void *, const void *));
static size_t elf_link_sort_relocs
PARAMS ((bfd *, struct bfd_link_info *, asection **));
+static boolean elf_section_ignore_discarded_relocs
+ PARAMS ((asection *));
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
return true;
}
+/* 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
+ 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,
+ 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;
+ bfd_vma *value;
+ boolean *dynsym;
+ boolean override;
+ boolean dt_needed;
+{
+ boolean type_change_ok;
+ boolean size_change_ok;
+ char *shortname;
+ struct elf_link_hash_entry *hi;
+ struct elf_backend_data *bed;
+ boolean collect;
+ boolean dynamic;
+ char *p;
+
+ /* If this symbol has a version, and it is the default version, we
+ create an indirect symbol from the default name to the fully
+ decorated name. This will cause external references which do not
+ specify a version to be bound to this version of the symbol. */
+ p = strchr (name, ELF_VER_CHR);
+ if (p == NULL || p[1] != ELF_VER_CHR)
+ return true;
+
+ 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. */
+ hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
+ false, false);
+ BFD_ASSERT (hi != NULL);
+ if (hi == h)
+ return true;
+ while (hi->root.type == bfd_link_hash_indirect
+ || hi->root.type == bfd_link_hash_warning)
+ {
+ hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+ if (hi == h)
+ return true;
+ }
+ }
+
+ bed = get_elf_backend_data (abfd);
+ collect = bed->collect;
+ dynamic = (abfd->flags & DYNAMIC) != 0;
+
+ shortname = bfd_hash_allocate (&info->hash->table,
+ (size_t) (p - name + 1));
+ if (shortname == NULL)
+ return false;
+ strncpy (shortname, name, (size_t) (p - name));
+ shortname [p - name] = '\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
+ though we were defining the symbol we just defined, although we
+ 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,
+ &hi, &override, &type_change_ok,
+ &size_change_ok, dt_needed))
+ return false;
+
+ if (! override)
+ {
+ 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)))
+ return false;
+ }
+ else
+ {
+ /* In this case the symbol named SHORTNAME is overriding the
+ indirect symbol we want to add. We were planning on making
+ SHORTNAME an indirect symbol referring to NAME. SHORTNAME
+ is the name without a version. NAME is the fully versioned
+ name, and it is the default version.
+
+ Overriding means that we already saw a definition for the
+ symbol SHORTNAME in a regular object, and it is overriding
+ the symbol defined in the dynamic object.
+
+ When this happens, we actually want to change NAME, the
+ symbol we just added, to refer to SHORTNAME. This will cause
+ references to NAME in the shared object to become references
+ to SHORTNAME in the regular object. This is what we expect
+ when we override a function in a shared object: that the
+ references in the shared object will be mapped to the
+ definition in the regular object. */
+
+ while (hi->root.type == bfd_link_hash_indirect
+ || hi->root.type == bfd_link_hash_warning)
+ hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
+ h->root.type = bfd_link_hash_indirect;
+ h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
+ if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+ {
+ h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
+ hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+ if (hi->elf_link_hash_flags
+ & (ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_DEF_REGULAR))
+ {
+ if (! _bfd_elf_link_record_dynamic_symbol (info, hi))
+ return false;
+ }
+ }
+
+ /* Now set HI to H, so that the following code will set the
+ other fields correctly. */
+ hi = h;
+ }
+
+ /* If there is a duplicate definition somewhere, then HI may not
+ point to an indirect symbol. We will have reported an error to
+ the user in that case. */
+
+ if (hi->root.type == bfd_link_hash_indirect)
+ {
+ struct elf_link_hash_entry *ht;
+
+ /* If the symbol became indirect, then we assume that we have
+ not seen a definition before. */
+ BFD_ASSERT ((hi->elf_link_hash_flags
+ & (ELF_LINK_HASH_DEF_DYNAMIC
+ | 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);
+
+ /* See if the new flags lead us to realize that the symbol must
+ be dynamic. */
+ if (! *dynsym)
+ {
+ if (! dynamic)
+ {
+ if (info->shared
+ || ((hi->elf_link_hash_flags
+ & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ *dynsym = true;
+ }
+ else
+ {
+ if ((hi->elf_link_hash_flags
+ & ELF_LINK_HASH_REF_REGULAR) != 0)
+ *dynsym = true;
+ }
+ }
+ }
+
+ /* 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)
+ return false;
+ strncpy (shortname, name, (size_t) (p - name));
+ strcpy (shortname + (p - name), p + 1);
+
+ /* 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,
+ &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);
+ }
+ else
+ {
+ 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)))
+ return false;
+
+ /* If there is a duplicate definition somewhere, then HI may not
+ point to an indirect symbol. We will have reported an error
+ to the user in that case. */
+
+ if (hi->root.type == bfd_link_hash_indirect)
+ {
+ /* If the symbol became indirect, then we assume that we have
+ not seen a definition before. */
+ BFD_ASSERT ((hi->elf_link_hash_flags
+ & (ELF_LINK_HASH_DEF_DYNAMIC
+ | ELF_LINK_HASH_DEF_REGULAR)) == 0);
+
+ (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+
+ /* See if the new flags lead us to realize that the symbol
+ must be dynamic. */
+ if (! *dynsym)
+ {
+ if (! dynamic)
+ {
+ if (info->shared
+ || ((hi->elf_link_hash_flags
+ & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+ *dynsym = true;
+ }
+ else
+ {
+ if ((hi->elf_link_hash_flags
+ & ELF_LINK_HASH_REF_REGULAR) != 0)
+ *dynsym = true;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
/* Add symbols from an ELF object file to the linker hash table. */
static boolean
if (add_needed)
{
/* Add a DT_NEEDED entry for this dynamic object. */
- oldsize = _bfd_stringtab_size (hash_table->dynstr);
- strindex = _bfd_stringtab_add (hash_table->dynstr, name,
- true, false);
+ oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+ strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, false);
if (strindex == (bfd_size_type) -1)
goto error_return;
- if (oldsize == _bfd_stringtab_size (hash_table->dynstr))
+ if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
{
asection *sdyn;
Elf_External_Dyn *dyncon, *dynconend;
free (buf);
if (extversym != NULL)
free (extversym);
+ _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
return true;
}
}
boolean size_change_ok, type_change_ok;
boolean new_weakdef;
unsigned int old_alignment;
+ boolean override;
+
+ override = false;
elf_swap_symbol_in (abfd, esym, &sym);
{
Elf_Internal_Versym iver;
unsigned int vernum = 0;
- boolean override;
if (ever != NULL)
{
h->elf_link_hash_flags |= new_flag;
- /* If this symbol has a version, and it is the default
- version, we create an indirect symbol from the default
- name to the fully decorated name. This will cause
- external references which do not specify a version to be
- bound to this version of the symbol. */
+ /* Check to see if we need to add an indirect symbol for
+ the default name. */
if (definition || h->root.type == bfd_link_hash_common)
- {
- char *p;
-
- p = strchr (name, ELF_VER_CHR);
- if (p != NULL && p[1] == ELF_VER_CHR)
- {
- char *shortname;
- struct elf_link_hash_entry *hi;
- boolean override;
-
- shortname = bfd_hash_allocate (&info->hash->table,
- (size_t) (p - name + 1));
- if (shortname == NULL)
- goto error_return;
- strncpy (shortname, name, (size_t) (p - name));
- shortname[p - name] = '\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 though we were
- defining the symbol we just defined, although we
- 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, &hi, &override,
- &type_change_ok,
- &size_change_ok, dt_needed))
- goto error_return;
-
- if (! override)
- {
- 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;
- }
- else
- {
- /* In this case the symbol named SHORTNAME is
- overriding the indirect symbol we want to
- add. We were planning on making SHORTNAME an
- indirect symbol referring to NAME. SHORTNAME
- is the name without a version. NAME is the
- fully versioned name, and it is the default
- version.
-
- Overriding means that we already saw a
- definition for the symbol SHORTNAME in a
- regular object, and it is overriding the
- symbol defined in the dynamic object.
-
- When this happens, we actually want to change
- NAME, the symbol we just added, to refer to
- SHORTNAME. This will cause references to
- NAME in the shared object to become
- references to SHORTNAME in the regular
- object. This is what we expect when we
- override a function in a shared object: that
- the references in the shared object will be
- mapped to the definition in the regular
- object. */
-
- while (hi->root.type == bfd_link_hash_indirect
- || hi->root.type == bfd_link_hash_warning)
- hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
- h->root.type = bfd_link_hash_indirect;
- h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
- {
- h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
- hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
- if (hi->elf_link_hash_flags
- & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR))
- {
- if (! _bfd_elf_link_record_dynamic_symbol (info,
- hi))
- goto error_return;
- }
- }
-
- /* Now set HI to H, so that the following code
- will set the other fields correctly. */
- hi = h;
- }
-
- /* If there is a duplicate definition somewhere,
- then HI may not point to an indirect symbol. We
- will have reported an error to the user in that
- case. */
-
- if (hi->root.type == bfd_link_hash_indirect)
- {
- struct elf_link_hash_entry *ht;
-
- /* If the symbol became indirect, then we assume
- that we have not seen a definition before. */
- BFD_ASSERT ((hi->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_DYNAMIC
- | 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);
-
- /* See if the new flags lead us to realize that
- the symbol must be dynamic. */
- if (! dynsym)
- {
- if (! dynamic)
- {
- if (info->shared
- || ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_DYNAMIC)
- != 0))
- dynsym = true;
- }
- else
- {
- if ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0)
- dynsym = true;
- }
- }
- }
-
- /* 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, (size_t) (p - name));
- strcpy (shortname + (p - name), p + 1);
-
- /* 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, &hi, &override,
- &type_change_ok,
- &size_change_ok, dt_needed))
- goto error_return;
-
- 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);
- }
- else
- {
- 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 there is a duplicate definition somewhere,
- then HI may not point to an indirect symbol.
- We will have reported an error to the user in
- that case. */
-
- if (hi->root.type == bfd_link_hash_indirect)
- {
- /* If the symbol became indirect, then we
- assume that we have not seen a definition
- before. */
- BFD_ASSERT ((hi->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_DYNAMIC
- | ELF_LINK_HASH_DEF_REGULAR))
- == 0);
-
- (*bed->elf_backend_copy_indirect_symbol) (h, hi);
-
- /* See if the new flags lead us to realize
- that the symbol must be dynamic. */
- if (! dynsym)
- {
- if (! dynamic)
- {
- if (info->shared
- || ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_DYNAMIC)
- != 0))
- dynsym = true;
- }
- else
- {
- if ((hi->elf_link_hash_flags
- & ELF_LINK_HASH_REF_REGULAR) != 0)
- dynsym = true;
- }
- }
- }
- }
- }
- }
+ if (! elf_add_default_symbol (abfd, info, h, name, &sym,
+ &sec, &value, &dynsym,
+ override, dt_needed))
+ goto error_return;
if (dynsym && h->dynindx == -1)
{
case STV_HIDDEN:
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
(*bed->elf_backend_hide_symbol) (info, h);
+ _bfd_elf_strtab_delref (hash_table->dynstr,
+ h->dynstr_index);
break;
}
have to make sure there is a DT_NEEDED entry for it. */
dt_needed = false;
- oldsize = _bfd_stringtab_size (hash_table->dynstr);
- strindex = _bfd_stringtab_add (hash_table->dynstr,
- elf_dt_soname (abfd),
- true, false);
+ oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+ strindex = _bfd_elf_strtab_add (hash_table->dynstr,
+ elf_dt_soname (abfd), false);
if (strindex == (bfd_size_type) -1)
goto error_return;
- if (oldsize
- == _bfd_stringtab_size (hash_table->dynstr))
+ if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
{
asection *sdyn;
Elf_External_Dyn *dyncon, *dynconend;
/* Create a strtab to hold the dynamic symbol names. */
if (elf_hash_table (info)->dynstr == NULL)
{
- elf_hash_table (info)->dynstr = elf_stringtab_init ();
+ elf_hash_table (info)->dynstr = _bfd_elf_strtab_init ();
if (elf_hash_table (info)->dynstr == NULL)
return false;
}
{
struct elf_link_local_dynamic_entry *entry;
struct elf_link_hash_table *eht;
- struct bfd_strtab_hash *dynstr;
+ struct elf_strtab_hash *dynstr;
Elf_External_Sym esym;
unsigned long dynstr_index;
char *name;
if (dynstr == NULL)
{
/* Create a strtab to hold the dynamic symbol names. */
- elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+ elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
if (dynstr == NULL)
return false;
}
- dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+ dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
if (dynstr_index == (unsigned long) -1)
return false;
entry->isym.st_name = dynstr_index;
if (soname != NULL)
{
- soname_indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- soname, true, true);
+ soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ soname, true);
if (soname_indx == (bfd_size_type) -1
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_SONAME,
soname_indx))
{
bfd_size_type indx;
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
- true, true);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
+ true);
+ if (info->new_dtags)
+ _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx);
if (indx == (bfd_size_type) -1
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_RPATH, indx)
|| (info->new_dtags
{
bfd_size_type indx;
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- filter_shlib, true, true);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ filter_shlib, true);
if (indx == (bfd_size_type) -1
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_FILTER, indx))
return false;
{
bfd_size_type indx;
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- *p, true, true);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ *p, true);
if (indx == (bfd_size_type) -1
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_AUXILIARY,
indx))
{
bfd_size_type strsize;
- strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+ strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
if (! elf_add_dynamic_entry (info, (bfd_vma) DT_HASH, (bfd_vma) 0)
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRTAB, (bfd_vma) 0)
|| ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMTAB, (bfd_vma) 0)
if (soname_indx != (bfd_size_type) -1)
{
+ _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+ soname_indx);
def.vd_hash = bfd_elf_hash (soname);
defaux.vda_name = soname_indx;
}
name = basename (output_bfd->filename);
def.vd_hash = bfd_elf_hash (name);
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- name, true, false);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ name, false);
if (indx == (bfd_size_type) -1)
return false;
defaux.vda_name = indx;
p += sizeof (Elf_External_Verdef);
defaux.vda_name = h->dynstr_index;
+ _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
if (t->deps == NULL)
defaux.vda_next = 0;
else
defaux.vda_name = 0;
}
else
- defaux.vda_name = n->version_needed->name_indx;
+ {
+ defaux.vda_name = n->version_needed->name_indx;
+ _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+ defaux.vda_name);
+ }
if (n->next == NULL)
defaux.vda_next = 0;
else
t->vn_version = VER_NEED_CURRENT;
t->vn_cnt = caux;
- if (elf_dt_name (t->vn_bfd) != NULL)
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- elf_dt_name (t->vn_bfd),
- true, false);
- else
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- basename (t->vn_bfd->filename),
- true, false);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ elf_dt_name (t->vn_bfd) != NULL
+ ? elf_dt_name (t->vn_bfd)
+ : basename (t->vn_bfd->filename),
+ false);
if (indx == (bfd_size_type) -1)
return false;
t->vn_file = indx;
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
a->vna_hash = bfd_elf_hash (a->vna_nodename);
- indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
- a->vna_nodename, true, false);
+ indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+ a->vna_nodename, false);
if (indx == (bfd_size_type) -1)
return false;
a->vna_name = indx;
s = bfd_get_section_by_name (dynobj, ".dynstr");
BFD_ASSERT (s != NULL);
- s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+
+ elf_finalize_dynstr (output_bfd, info);
+
+ s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NULL, (bfd_vma) 0))
return true;
}
\f
+/* This function is used to adjust offsets into .dynstr for
+ dynamic symbols. This is called via elf_link_hash_traverse. */
+
+static boolean elf_adjust_dynstr_offsets
+PARAMS ((struct elf_link_hash_entry *, PTR));
+
+static boolean
+elf_adjust_dynstr_offsets (h, data)
+ struct elf_link_hash_entry *h;
+ PTR data;
+{
+ struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
+
+ if (h->dynindx != -1)
+ h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
+ return true;
+}
+
+/* Assign string offsets in .dynstr, update all structures referencing
+ them. */
+
+static boolean
+elf_finalize_dynstr (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ struct elf_link_local_dynamic_entry *entry;
+ struct elf_strtab_hash *dynstr = elf_hash_table (info)->dynstr;
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+ asection *sdyn;
+ bfd_size_type size;
+ Elf_External_Dyn *dyncon, *dynconend;
+
+ _bfd_elf_strtab_finalize (dynstr);
+ size = _bfd_elf_strtab_size (dynstr);
+
+ /* Update all .dynamic entries referencing .dynstr strings. */
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ BFD_ASSERT (sdyn != NULL);
+
+ dyncon = (Elf_External_Dyn *) sdyn->contents;
+ dynconend = (Elf_External_Dyn *) (sdyn->contents +
+ sdyn->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+
+ elf_swap_dyn_in (dynobj, dyncon, & dyn);
+ switch (dyn.d_tag)
+ {
+ case DT_STRSZ:
+ dyn.d_un.d_val = size;
+ elf_swap_dyn_out (dynobj, & dyn, dyncon);
+ break;
+ case DT_NEEDED:
+ case DT_SONAME:
+ case DT_RPATH:
+ case DT_RUNPATH:
+ case DT_FILTER:
+ case DT_AUXILIARY:
+ dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val);
+ elf_swap_dyn_out (dynobj, & dyn, dyncon);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Now update local dynamic symbols. */
+ for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+ entry->isym.st_name = _bfd_elf_strtab_offset (dynstr,
+ entry->isym.st_name);
+
+ /* And the rest of dynamic symbols. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_adjust_dynstr_offsets, dynstr);
+
+ /* Adjust version definitions. */
+ if (elf_tdata (output_bfd)->cverdefs)
+ {
+ asection *s;
+ bfd_byte *p;
+ bfd_size_type i;
+ Elf_Internal_Verdef def;
+ Elf_Internal_Verdaux defaux;
+
+ s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+ p = (bfd_byte *) s->contents;
+ do
+ {
+ _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p,
+ &def);
+ p += sizeof (Elf_External_Verdef);
+ for (i = 0; i < def.vd_cnt; ++i)
+ {
+ _bfd_elf_swap_verdaux_in (output_bfd,
+ (Elf_External_Verdaux *) p, &defaux);
+ defaux.vda_name = _bfd_elf_strtab_offset (dynstr,
+ defaux.vda_name);
+ _bfd_elf_swap_verdaux_out (output_bfd,
+ &defaux, (Elf_External_Verdaux *) p);
+ p += sizeof (Elf_External_Verdaux);
+ }
+ }
+ while (def.vd_next);
+ }
+
+ /* Adjust version references. */
+ if (elf_tdata (output_bfd)->verref)
+ {
+ asection *s;
+ bfd_byte *p;
+ bfd_size_type i;
+ Elf_Internal_Verneed need;
+ Elf_Internal_Vernaux needaux;
+
+ s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+ p = (bfd_byte *) s->contents;
+ do
+ {
+ _bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p,
+ &need);
+ need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file);
+ _bfd_elf_swap_verneed_out (output_bfd, &need,
+ (Elf_External_Verneed *) p);
+ p += sizeof (Elf_External_Verneed);
+ for (i = 0; i < need.vn_cnt; ++i)
+ {
+ _bfd_elf_swap_vernaux_in (output_bfd,
+ (Elf_External_Vernaux *) p, &needaux);
+ needaux.vna_name = _bfd_elf_strtab_offset (dynstr,
+ needaux.vna_name);
+ _bfd_elf_swap_vernaux_out (output_bfd,
+ &needaux,
+ (Elf_External_Vernaux *) p);
+ p += sizeof (Elf_External_Vernaux);
+ }
+ }
+ while (need.vn_next);
+ }
+
+ return true;
+}
+
/* Fix up the flags for a symbol. This handles various cases which
can only be fixed after all the input files are seen. This is
currently called by both adjust_dynamic_symbol and
bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
- h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ {
+ h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+ _bfd_elf_strtab_delref (elf_hash_table (eif->info)->dynstr,
+ h->dynstr_index);
+ }
(*bed->elf_backend_hide_symbol) (eif->info, h);
}
{
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
(*bed->elf_backend_hide_symbol) (info, h);
- /* FIXME: The name of the symbol has
- already been recorded in the dynamic
- string table section. */
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
}
break;
{
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
(*bed->elf_backend_hide_symbol) (info, h);
- /* FIXME: The name of the symbol has already
- been recorded in the dynamic string table
- section. */
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
}
break;
}
{
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
(*bed->elf_backend_hide_symbol) (info, h);
- /* FIXME: The name of the symbol has already been
- recorded in the dynamic string table section. */
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
}
}
}
}
}
- qsort (rela, count, sizeof (*rela), elf_link_sort_cmp1);
+ qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
;
for (i = ret, j = ret; i < count; i++)
j = i;
rela[i].offset = rela[j].u.rel.r_offset;
}
- qsort (rela + ret, count - ret, sizeof (*rela), elf_link_sort_cmp2);
+ qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
for (o = dynobj->sections; o != NULL; o = o->next)
if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
struct elf_link_sort_rela *s;
erel = (Elf_External_Rel *) o->contents;
- erelend = (Elf_External_Rel *) ((PTR) o->contents + o->_raw_size);
+ erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
s = rela + o->output_offset / sizeof (Elf_External_Rel);
for (; erel < erelend; erel++, s++)
{
struct elf_link_sort_rela *s;
erela = (Elf_External_Rela *) o->contents;
- erelaend = (Elf_External_Rela *) ((PTR) o->contents + o->_raw_size);
+ erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
s = rela + o->output_offset / sizeof (Elf_External_Rela);
for (; erela < erelaend; erela++, s++)
{
stringtab. */
off = elf_section_data (o->output_section)->this_hdr.sh_offset;
if (bfd_seek (abfd, off, SEEK_SET) != 0
- || ! _bfd_stringtab_emit (abfd,
- elf_hash_table (info)->dynstr))
+ || ! _bfd_elf_strtab_emit (abfd,
+ elf_hash_table (info)->dynstr))
goto error_return;
}
}
/* If a symbol is not defined locally, we clear the visibility
field. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ if (! finfo->info->relocateable
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other);
/* If this symbol should be put in the .dynsym section, then put it
asection *o;
struct elf_backend_data *bed;
boolean emit_relocs;
+ struct elf_link_hash_entry **sym_hashes;
output_bfd = finfo->output_bfd;
bed = get_elf_backend_data (output_bfd);
}
/* Relocate the contents of each section. */
+ sym_hashes = elf_sym_hashes (input_bfd);
for (o = input_bfd->sections; o != NULL; o = o->next)
{
bfd_byte *contents;
&& o->reloc_count > 0)
return false;
-#if BFD_VERSION_DATE < 20031005
- {
- Elf_Internal_Rela *rel, *relend;
- /* Run through the relocs looking for any against section
- symbols from removed link-once sections. Set any such
- relocs to be against 0. We should really complain if
- anything in the final link tries to use it, but
- DWARF-based exception handling might have an entry in
- .eh_frame to describe a routine in the linkonce section,
- and it turns out to be hard to remove the .eh_frame entry
- too. FIXME. */
- rel = internal_relocs;
- relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
- for ( ; rel < relend; rel++)
- {
- unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+ /* Run through the relocs looking for any against symbols
+ from discarded sections and section symbols from
+ removed link-once sections. Complain about relocs
+ against discarded sections. Zero relocs against removed
+ link-once sections. We should really complain if
+ anything in the final link tries to use it, but
+ DWARF-based exception handling might have an entry in
+ .eh_frame to describe a routine in the linkonce section,
+ and it turns out to be hard to remove the .eh_frame
+ entry too. FIXME. */
+ if (!finfo->info->relocateable
+ && !elf_section_ignore_discarded_relocs (o))
+ {
+ Elf_Internal_Rela *rel, *relend;
- if (r_symndx < locsymcount
- && (!elf_bad_symtab (input_bfd)
- || finfo->sections[r_symndx] != NULL))
- {
- isym = finfo->internal_syms + r_symndx;
- if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
- {
- asection *sec = finfo->sections[r_symndx];
+ rel = internal_relocs;
+ relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
+ for ( ; rel < relend; rel++)
+ {
+ unsigned long r_symndx = ELF_R_SYM (rel->r_info);
- if (sec != NULL
- && (sec->flags & SEC_LINK_ONCE) != 0
- && bfd_is_abs_section (sec->output_section))
- {
- long r_type = ELF_R_TYPE (rel->r_info);
- rel->r_info = ELF_R_INFO (0, r_type);
+ if (r_symndx >= locsymcount
+ || (elf_bad_symtab (input_bfd)
+ && finfo->sections[r_symndx] == NULL))
+ {
+ struct elf_link_hash_entry *h;
+
+ h = sym_hashes[r_symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ /* Complain if the definition comes from a
+ discarded section. */
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && ! bfd_is_abs_section (h->root.u.def.section)
+ && bfd_is_abs_section (h->root.u.def.section
+ ->output_section)
+ && elf_section_data (h->root.u.def.section)->merge_info
+ == NULL)
+ {
+#if BFD_VERSION_DATE < 20031005
+ if ((o->flags & SEC_DEBUGGING) != 0)
+ {
+#if BFD_VERSION_DATE > 20021005
+ (*finfo->info->callbacks->warning)
+ (finfo->info,
+ _("warning: relocation against removed section; zeroing"),
+ NULL, input_bfd, o, rel->r_offset);
+#endif
+ BFD_ASSERT (r_symndx != 0);
+ memset (rel, 0, sizeof (*rel));
+ }
+ else
+#endif
+ {
+ if (! ((*finfo->info->callbacks->undefined_symbol)
+ (finfo->info, h->root.root.string,
+ input_bfd, o, rel->r_offset,
+ true)))
+ return false;
+ }
+ }
+ }
+ else
+ {
+ asection *sec = finfo->sections[r_symndx];
+ if (sec != NULL
+ && ! bfd_is_abs_section (sec)
+ && bfd_is_abs_section (sec->output_section)
+ && elf_section_data (sec)->merge_info == NULL)
+ {
+#if BFD_VERSION_DATE < 20031005
+ if ((o->flags & SEC_DEBUGGING) != 0
+ || (sec->flags & SEC_LINK_ONCE) != 0)
+ {
#if BFD_VERSION_DATE > 20021005
- (*finfo->info->callbacks->warning)
- (finfo->info,
- _("warning: relocation against removed section; zeroing"),
- NULL, input_bfd, o, rel->r_offset);
+ (*finfo->info->callbacks->warning)
+ (finfo->info,
+ _("warning: relocation against removed section"),
+ NULL, input_bfd, o, rel->r_offset);
#endif
- }
- }
- }
- }
- }
-#else
-#error "This kludge ought to be fixed properly in gcc by now"
+ BFD_ASSERT (r_symndx != 0);
+ rel->r_info
+ = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
+ rel->r_addend = 0;
+ }
+ else
#endif
+ {
+ boolean ok;
+ const char *msg
+ = _("local symbols in discarded section %s");
+ bfd_size_type amt
+ = strlen (sec->name) + strlen (msg) - 1;
+ char *buf = (char *) bfd_malloc (amt);
+
+ if (buf != NULL)
+ sprintf (buf, msg, sec->name);
+ else
+ buf = (char *) sec->name;
+ ok = (*finfo->info->callbacks
+ ->undefined_symbol) (finfo->info, buf,
+ input_bfd, o,
+ rel->r_offset,
+ true);
+ if (buf != sec->name)
+ free (buf);
+ if (!ok)
+ return false;
+ }
+ }
+ }
+ }
+ }
/* Relocate the section by invoking a back end routine.
}
/* Write out the modified section contents. */
- if (elf_section_data (o)->stab_info)
+ if (bed->elf_backend_write_section
+ && (*bed->elf_backend_write_section) (output_bfd, o, contents))
+ {
+ /* Section written out. */
+ }
+ else if (elf_section_data (o)->stab_info)
{
if (! (_bfd_write_section_stabs
(output_bfd, &elf_hash_table (finfo->info)->stab_info,
return true;
}
+
+boolean
+elf_reloc_symbol_deleted_p (offset, cookie)
+ bfd_vma offset;
+ PTR cookie;
+{
+ struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *)cookie;
+
+ if (rcookie->bad_symtab)
+ rcookie->rel = rcookie->rels;
+
+ 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)
+ return false;
+ if (rcookie->rel->r_offset != offset)
+ continue;
+
+ if (rcookie->locsyms && r_symndx < rcookie->locsymcount)
+ elf_swap_symbol_in (rcookie->abfd,
+ (Elf_External_Sym *) rcookie->locsyms + r_symndx,
+ &isym);
+
+ if (r_symndx >= rcookie->locsymcount
+ || (rcookie->locsyms
+ && ELF_ST_BIND (isym.st_info) != STB_LOCAL))
+ {
+ struct elf_link_hash_entry *h;
+
+ h = rcookie->sym_hashes[r_symndx - rcookie->extsymoff];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && ! bfd_is_abs_section (h->root.u.def.section)
+ && bfd_is_abs_section (h->root.u.def.section
+ ->output_section))
+ return true;
+ else
+ return false;
+ }
+ else if (rcookie->locsyms)
+ {
+ /* 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;
+
+ /* Need to: get the symbol; get the section. */
+ if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
+ {
+ isec = section_from_elf_index (rcookie->abfd, isym.st_shndx);
+ if (isec != NULL
+ && ! bfd_is_abs_section (isec)
+ && bfd_is_abs_section (isec->output_section))
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+}
+
+/* Discard unneeded references to discarded sections.
+ Returns true if any section's size was changed. */
+/* This function assumes that the relocations are in sorted order,
+ which is true for all known assemblers. */
+
+boolean
+elf_bfd_discard_info (info)
+ struct bfd_link_info *info;
+{
+ struct elf_reloc_cookie cookie;
+ asection *o;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_External_Sym *freesyms;
+ struct elf_backend_data *bed;
+ bfd *abfd;
+ boolean ret = false;
+
+ if (info->relocateable
+ || info->traditional_format
+ || info->hash->creator->flavour != bfd_target_elf_flavour
+ || ! is_elf_hash_table (info)
+ || info->strip == strip_all
+ || info->strip == strip_debugger)
+ return false;
+ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ {
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ continue;
+
+ bed = get_elf_backend_data (abfd);
+
+ if ((abfd->flags & DYNAMIC) != 0)
+ continue;
+
+ o = bfd_get_section_by_name (abfd, ".stab");
+ if (! o && ! bed->elf_backend_discard_info)
+ continue;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ cookie.abfd = abfd;
+ cookie.sym_hashes = elf_sym_hashes (abfd);
+ cookie.bad_symtab = elf_bad_symtab (abfd);
+ if (cookie.bad_symtab)
+ {
+ cookie.locsymcount =
+ symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+ cookie.extsymoff = 0;
+ }
+ else
+ {
+ cookie.locsymcount = symtab_hdr->sh_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
+ {
+ bfd_size_type amt = cookie.locsymcount * sizeof (Elf_External_Sym);
+ cookie.locsyms = bfd_malloc (amt);
+ if (cookie.locsyms == NULL
+ || bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread (cookie.locsyms, amt, abfd) != amt)
+ {
+ /* Something is very wrong - but we can still do our job for
+ global symbols, so don't give up. */
+ if (cookie.locsyms)
+ free (cookie.locsyms);
+ cookie.locsyms = NULL;
+ }
+ else
+ {
+ freesyms = cookie.locsyms;
+ }
+ }
+
+ if (o)
+ {
+ cookie.rels = (NAME(_bfd_elf,link_read_relocs)
+ (abfd, o, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory));
+ if (cookie.rels)
+ {
+ cookie.rel = cookie.rels;
+ cookie.relend =
+ cookie.rels + o->reloc_count * bed->s->int_rels_per_ext_rel;
+ if (_bfd_discard_section_stabs (abfd, o,
+ elf_section_data (o)->stab_info,
+ elf_reloc_symbol_deleted_p,
+ &cookie))
+ ret = true;
+ if (! info->keep_memory)
+ free (cookie.rels);
+ }
+ }
+
+ if (bed->elf_backend_discard_info)
+ {
+ if (bed->elf_backend_discard_info (abfd, &cookie, info))
+ ret = true;
+ }
+
+ if (freesyms)
+ free (freesyms);
+ }
+ return ret;
+}
+
+static boolean
+elf_section_ignore_discarded_relocs (sec)
+ asection *sec;
+{
+ if (strcmp (sec->name, ".stab") == 0)
+ return true;
+ else if ((get_elf_backend_data (sec->owner)
+ ->elf_backend_ignore_discarded_relocs != NULL)
+ && (*get_elf_backend_data (sec->owner)
+ ->elf_backend_ignore_discarded_relocs) (sec))
+ return true;
+ else
+ return false;
+}