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 ((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. */
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;
/* Select the appropriate symbol table. */
if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
- hdr = &elf_tdata (abfd)->symtab_hdr;
+ {
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+ }
else
- hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ {
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ shndx_hdr = NULL;
+ }
symcount = hdr->sh_size / sizeof (Elf_External_Sym);
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)
{
- free (buf);
- return false;
+ 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;
}
/* Scan the symbol table looking for SYMDEF. */
esymend = buf + extsymcount;
- for (esym = buf;
+ for (esym = buf, shndx = shndx_buf;
esym < esymend;
- esym++)
+ esym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
{
Elf_Internal_Sym sym;
const char * name;
- elf_swap_symbol_in (abfd, esym, & sym);
+ elf_swap_symbol_in (abfd, esym, shndx, &sym);
name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
if (name == (const char *) NULL)
}
}
- free (buf);
+ error_exit:
+ if (shndx_buf != NULL)
+ free (shndx_buf);
+ if (buf != NULL)
+ free (buf);
return result;
}
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
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;
look at .symtab for a dynamic object. */
if (! dynamic || elf_dynsymtab (abfd) == 0)
- hdr = &elf_tdata (abfd)->symtab_hdr;
+ {
+ hdr = &elf_tdata (abfd)->symtab_hdr;
+ shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+ }
else
- hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ {
+ hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ shndx_hdr = NULL;
+ }
if (dynamic)
{
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 *);
SEC_NEVER_LOAD flag is not the one we want, because that one
still implies that the section takes up space in the output
file. */
- abfd->sections = NULL;
- abfd->section_count = 0;
+ bfd_section_list_clear (abfd);
/* If this is the first dynamic object found in the link, create
the special sections required for dynamic linking. */
|| bfd_bread ((PTR) buf, amt, abfd) != amt)
goto error_return;
+ if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
+ {
+ 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)
+ goto error_return;
+ }
+
weaks = NULL;
ever = extversym != NULL ? extversym + extsymoff : NULL;
esymend = buf + extsymcount;
- for (esym = buf;
+ for (esym = buf, shndx = shndx_buf;
esym < esymend;
- esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
+ esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL),
+ shndx = (shndx != NULL ? shndx + 1 : NULL))
{
Elf_Internal_Sym sym;
int bind;
boolean size_change_ok, type_change_ok;
boolean new_weakdef;
unsigned int old_alignment;
+ boolean override;
- elf_swap_symbol_in (abfd, esym, &sym);
+ override = false;
+
+ elf_swap_symbol_in (abfd, esym, shndx, &sym);
flags = BSF_NO_FLAGS;
sec = NULL;
if (sym.st_shndx == SHN_UNDEF)
sec = bfd_und_section_ptr;
- else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE)
+ else if (sym.st_shndx < SHN_LORESERVE || sym.st_shndx > SHN_HIRESERVE)
{
sec = section_from_elf_index (abfd, sym.st_shndx);
if (sec == NULL)
{
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_INTERNAL:
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);
+ (*bed->elf_backend_hide_symbol) (info, h, true);
break;
}
asection *stab, *stabstr;
stab = bfd_get_section_by_name (abfd, ".stab");
- if (stab != NULL)
+ if (stab != NULL && !(stab->flags & SEC_MERGE))
{
stabstr = bfd_get_section_by_name (abfd, ".stabstr");
if (! _bfd_link_section_stabs (abfd,
& hash_table->stab_info,
stab, stabstr,
- &secdata->stab_info))
+ &secdata->sec_info))
goto error_return;
+ if (secdata->sec_info)
+ secdata->sec_info_type = ELF_INFO_TYPE_STABS;
}
}
}
asection *s;
for (s = abfd->sections; s != NULL; s = s->next)
- if ((s->flags & SEC_MERGE)
- && ! _bfd_merge_section (abfd, & hash_table->merge_info, s,
- & elf_section_data (s)->merge_info))
- goto error_return;
+ if (s->flags & SEC_MERGE)
+ {
+ struct bfd_elf_section_data *secdata;
+
+ secdata = elf_section_data (s);
+ if (! _bfd_merge_section (abfd,
+ & hash_table->merge_info,
+ s, &secdata->sec_info))
+ goto error_return;
+ else if (secdata->sec_info)
+ secdata->sec_info_type = ELF_INFO_TYPE_MERGE;
+ }
}
return true;
return false;
}
+ if (! info->traditional_format
+ && info->hash->creator->flavour == bfd_target_elf_flavour)
+ {
+ s = bfd_make_section (abfd, ".eh_frame_hdr");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+ }
+
/* Create sections to hold version informations. These are removed
if they are not needed. */
s = bfd_make_section (abfd, ".gnu.version_d");
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;
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 (&esym, amt, input_bfd) != amt)
+ || bfd_bread ((PTR) &esym, amt, input_bfd) != amt)
return false;
- elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+ 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,
if (dynobj == NULL)
return true;
+ if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+ return false;
+
if (elf_hash_table (info)->dynamic_sections_created)
{
struct elf_info_failed eif;
just linking a regular application. */
verdefs = asvinfo.verdefs;
+ /* Skip anonymous version tag. */
+ if (verdefs != NULL && verdefs->vernum == 0)
+ verdefs = verdefs->next;
+
if (verdefs == NULL)
_bfd_strip_section_from_output (info, s);
else
isym.st_info = 0;
isym.st_other = 0;
isym.st_shndx = 0;
- elf_swap_symbol_out (output_bfd, &isym,
- (PTR) (Elf_External_Sym *) s->contents);
+ elf_swap_symbol_out (output_bfd, &isym, (PTR) s->contents, (PTR) 0);
}
/* Compute the size of the hashing table. As a side effect this
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
{
struct elf_backend_data *bed;
+ boolean force_local;
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;
- _bfd_elf_strtab_delref (elf_hash_table (eif->info)->dynstr,
- h->dynstr_index);
- }
- (*bed->elf_backend_hide_symbol) (eif->info, h);
+
+ force_local = (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+ || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN);
+ (*bed->elf_backend_hide_symbol) (eif->info, h, force_local);
}
/* If this is a weak defined symbol in a dynamic object, and we know
struct bfd_elf_version_expr *d;
len = p - h->root.root.string;
- alc = bfd_alloc (sinfo->output_bfd, (bfd_size_type) len);
+ alc = bfd_malloc ((bfd_size_type) len);
if (alc == NULL)
return false;
strncpy (alc, h->root.root.string, len - 1);
&& info->shared
&& ! info->export_dynamic)
{
- h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- (*bed->elf_backend_hide_symbol) (info, h);
- _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
- h->dynstr_index);
+ (*bed->elf_backend_hide_symbol) (info, h, true);
}
break;
}
}
- bfd_release (sinfo->output_bfd, alc);
+ free (alc);
break;
}
}
t->used = true;
version_index = 1;
+ /* Don't count anonymous version tag. */
+ if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+ version_index = 0;
for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
++version_index;
t->vernum = version_index;
&& info->shared
&& ! info->export_dynamic)
{
- h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- (*bed->elf_backend_hide_symbol) (info, h);
- _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
- h->dynstr_index);
+ (*bed->elf_backend_hide_symbol) (info, h, true);
}
break;
}
&& info->shared
&& ! info->export_dynamic)
{
- h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
- (*bed->elf_backend_hide_symbol) (info, h);
- _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
- h->dynstr_index);
+ (*bed->elf_backend_hide_symbol) (info, h, true);
}
}
}
/* Buffer large enough to hold external local symbols of any input
BFD. */
Elf_External_Sym *external_syms;
+ /* And a buffer for symbol section indices. */
+ Elf_External_Sym_Shndx *locsym_shndx;
/* Buffer large enough to hold internal local symbols of any input
BFD. */
Elf_Internal_Sym *internal_syms;
asection **sections;
/* Buffer to hold swapped out symbols. */
Elf_External_Sym *symbuf;
+ /* And one for symbol section indices. */
+ Elf_External_Sym_Shndx *symshndxbuf;
/* Number of swapped out symbols in buffer. */
size_t symbuf_count;
/* Number of symbols which fit in symbuf. */
bfd_size_type max_external_reloc_size;
bfd_size_type max_internal_reloc_count;
bfd_size_type max_sym_count;
+ bfd_size_type max_sym_shndx_count;
file_ptr off;
Elf_Internal_Sym elfsym;
unsigned int i;
finfo.external_relocs = NULL;
finfo.internal_relocs = NULL;
finfo.external_syms = NULL;
+ finfo.locsym_shndx = NULL;
finfo.internal_syms = NULL;
finfo.indices = NULL;
finfo.sections = NULL;
finfo.symbuf = NULL;
+ finfo.symshndxbuf = NULL;
finfo.symbuf_count = 0;
/* Count up the number of relocations we will output for each output
max_external_reloc_size = 0;
max_internal_reloc_count = 0;
max_sym_count = 0;
+ max_sym_shndx_count = 0;
merged = false;
for (o = abfd->sections; o != (asection *) NULL; o = o->next)
{
if (sym_count > max_sym_count)
max_sym_count = sym_count;
+ if (sym_count > max_sym_shndx_count
+ && elf_symtab_shndx (sec->owner) != 0)
+ max_sym_shndx_count = sym_count;
+
if ((sec->flags & SEC_RELOC) != 0)
{
size_t ext_size;
finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt);
if (finfo.symbuf == NULL)
goto error_return;
+ if (elf_numsections (abfd) > SHN_LORESERVE)
+ {
+ amt = finfo.symbuf_size;
+ amt *= sizeof (Elf_External_Sym_Shndx);
+ finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ if (finfo.symshndxbuf == NULL)
+ goto error_return;
+ }
/* Start writing out the symbol table. The first symbol is always a
dummy symbol. */
elfsym.st_size = 0;
elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
elfsym.st_other = 0;
- for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+ for (i = 1; i < elf_numsections (abfd); i++)
{
o = section_from_elf_index (abfd, i);
if (o != NULL)
if (! elf_link_output_sym (&finfo, (const char *) NULL,
&elfsym, o))
goto error_return;
+ if (i == SHN_LORESERVE)
+ i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
}
}
/* Allocate some memory to hold information read in from the input
files. */
- finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
- finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
- finfo.internal_relocs = ((Elf_Internal_Rela *)
- bfd_malloc (max_internal_reloc_count
- * sizeof (Elf_Internal_Rela)
- * bed->s->int_rels_per_ext_rel));
- finfo.external_syms = ((Elf_External_Sym *)
- bfd_malloc (max_sym_count
- * sizeof (Elf_External_Sym)));
- finfo.internal_syms = ((Elf_Internal_Sym *)
- bfd_malloc (max_sym_count
- * sizeof (Elf_Internal_Sym)));
- finfo.indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
- finfo.sections = ((asection **)
- bfd_malloc (max_sym_count * sizeof (asection *)));
- if ((finfo.contents == NULL && max_contents_size != 0)
- || (finfo.external_relocs == NULL && max_external_reloc_size != 0)
- || (finfo.internal_relocs == NULL && max_internal_reloc_count != 0)
- || (finfo.external_syms == NULL && max_sym_count != 0)
- || (finfo.internal_syms == NULL && max_sym_count != 0)
- || (finfo.indices == NULL && max_sym_count != 0)
- || (finfo.sections == NULL && max_sym_count != 0))
- goto error_return;
+ if (max_contents_size != 0)
+ {
+ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+ if (finfo.contents == NULL)
+ goto error_return;
+ }
+
+ if (max_external_reloc_size != 0)
+ {
+ finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
+ if (finfo.external_relocs == NULL)
+ goto error_return;
+ }
+
+ if (max_internal_reloc_count != 0)
+ {
+ amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
+ amt *= sizeof (Elf_Internal_Rela);
+ finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+ if (finfo.internal_relocs == NULL)
+ goto error_return;
+ }
+
+ if (max_sym_count != 0)
+ {
+ amt = max_sym_count * sizeof (Elf_External_Sym);
+ finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt);
+ if (finfo.external_syms == NULL)
+ goto error_return;
+
+ amt = max_sym_count * sizeof (Elf_Internal_Sym);
+ finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+ if (finfo.internal_syms == NULL)
+ goto error_return;
+
+ amt = max_sym_count * sizeof (long);
+ finfo.indices = (long *) bfd_malloc (amt);
+ if (finfo.indices == NULL)
+ goto error_return;
+
+ amt = max_sym_count * sizeof (asection *);
+ finfo.sections = (asection **) bfd_malloc (amt);
+ if (finfo.sections == NULL)
+ goto error_return;
+ }
+
+ if (max_sym_shndx_count != 0)
+ {
+ amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
+ finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ if (finfo.locsym_shndx == NULL)
+ goto error_return;
+ }
/* Since ELF permits relocations to be against local symbols, we
must have the local symbols available when we do the relocations.
for (s = abfd->sections; s != NULL; s = s->next)
{
int indx;
+ Elf_External_Sym *dest;
+
indx = elf_section_data (s)->this_idx;
BFD_ASSERT (indx > 0);
sym.st_shndx = indx;
sym.st_value = s->vma;
-
- elf_swap_symbol_out (abfd, &sym,
- dynsym + elf_section_data (s)->dynindx);
+ dest = dynsym + elf_section_data (s)->dynindx;
+ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
}
last_local = bfd_count_sections (abfd);
for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
{
asection *s;
+ Elf_External_Sym *dest;
sym.st_size = e->isym.st_size;
sym.st_other = e->isym.st_other;
the original st_name with the dynstr_index. */
sym = e->isym;
- if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE)
+ if (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);
if (last_local < e->dynindx)
last_local = e->dynindx;
- elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+ dest = dynsym + e->dynindx;
+ elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
}
}
else
type = SHT_RELA;
dyn.d_un.d_val = 0;
- for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+ for (i = 1; i < elf_numsections (abfd); i++)
{
Elf_Internal_Shdr *hdr;
goto error_return;
}
+ if (info->eh_frame_hdr && elf_hash_table (info)->dynobj)
+ {
+ o = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+ ".eh_frame_hdr");
+ if (o
+ && (elf_section_data (o)->sec_info_type
+ == ELF_INFO_TYPE_EH_FRAME_HDR))
+ {
+ if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o))
+ goto error_return;
+ }
+ }
+
if (finfo.symstrtab != NULL)
_bfd_stringtab_free (finfo.symstrtab);
if (finfo.contents != NULL)
free (finfo.internal_relocs);
if (finfo.external_syms != NULL)
free (finfo.external_syms);
+ if (finfo.locsym_shndx != NULL)
+ free (finfo.locsym_shndx);
if (finfo.internal_syms != NULL)
free (finfo.internal_syms);
if (finfo.indices != NULL)
free (finfo.sections);
if (finfo.symbuf != NULL)
free (finfo.symbuf);
+ if (finfo.symshndxbuf != NULL)
+ free (finfo.symbuf);
for (o = abfd->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_RELOC) != 0
free (finfo.internal_relocs);
if (finfo.external_syms != NULL)
free (finfo.external_syms);
+ if (finfo.locsym_shndx != NULL)
+ free (finfo.locsym_shndx);
if (finfo.internal_syms != NULL)
free (finfo.internal_syms);
if (finfo.indices != NULL)
free (finfo.sections);
if (finfo.symbuf != NULL)
free (finfo.symbuf);
+ if (finfo.symshndxbuf != NULL)
+ free (finfo.symbuf);
for (o = abfd->sections; o != NULL; o = o->next)
{
if ((o->flags & SEC_RELOC) != 0
Elf_Internal_Sym *elfsym;
asection *input_sec;
{
+ Elf_External_Sym *dest;
+ Elf_External_Sym_Shndx *destshndx;
+
boolean (*output_symbol_hook) PARAMS ((bfd *,
struct bfd_link_info *info,
const char *,
return false;
}
- elf_swap_symbol_out (finfo->output_bfd, elfsym,
- (PTR) (finfo->symbuf + finfo->symbuf_count));
+ dest = finfo->symbuf + finfo->symbuf_count;
+ destshndx = finfo->symshndxbuf;
+ if (destshndx != NULL)
+ destshndx += finfo->symbuf_count;
+ elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
++finfo->symbuf_count;
++ bfd_get_symcount (finfo->output_bfd);
{
if (finfo->symbuf_count > 0)
{
- Elf_Internal_Shdr *symtab;
+ Elf_Internal_Shdr *hdr;
file_ptr pos;
bfd_size_type amt;
- symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr;
- pos = symtab->sh_offset + symtab->sh_size;
+ hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+ pos = hdr->sh_offset + hdr->sh_size;
amt = finfo->symbuf_count * sizeof (Elf_External_Sym);
if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
|| bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt)
return false;
- symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym);
+ hdr->sh_size += amt;
+
+ if (finfo->symshndxbuf != NULL)
+ {
+ hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr;
+ pos = hdr->sh_offset + hdr->sh_size;
+ amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx);
+ if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
+ || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd)
+ != amt))
+ return false;
+
+ hdr->sh_size += amt;
+ }
finfo->symbuf_count = 0;
}
if ((h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
&& ((sec = h->root.u.def.section)->flags & SEC_MERGE)
- && elf_section_data (sec)->merge_info)
+ && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE)
{
bfd *output_bfd = (bfd *) data;
h->root.u.def.value =
_bfd_merged_section_offset (output_bfd,
&h->root.u.def.section,
- elf_section_data (sec)->merge_info,
+ elf_section_data (sec)->sec_info,
h->root.u.def.value, (bfd_vma) 0);
}
sym.st_shndx =
_bfd_elf_section_from_bfd_section (finfo->output_bfd,
input_sec->output_section);
- if (sym.st_shndx == (unsigned short) -1)
+ if (sym.st_shndx == SHN_BAD)
{
(*_bfd_error_handler)
(_("%s: could not find output section %s for input section %s"),
sym.st_name = h->dynstr_index;
esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx;
- elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym);
+ elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0);
bucketcount = elf_hash_table (finfo->info)->bucketcount;
bucket = h->elf_hash_value % bucketcount;
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 *isym;
long *pindex;
asection **ppsection;
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. */
- esym = external_syms;
- esymend = esym + locsymcount;
- isym = finfo->internal_syms;
- pindex = finfo->indices;
- ppsection = finfo->sections;
- for (; esym < esymend; esym++, isym++, pindex++, ppsection++)
+ 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))
{
asection *isec;
const char *name;
Elf_Internal_Sym osym;
- elf_swap_symbol_in (input_bfd, esym, isym);
+ elf_swap_symbol_in (input_bfd, esym, shndx, isym);
*pindex = -1;
if (elf_bad_symtab (input_bfd))
if (isym->st_shndx == SHN_UNDEF)
isec = bfd_und_section_ptr;
- else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
+ else if (isym->st_shndx < SHN_LORESERVE
+ || isym->st_shndx > SHN_HIRESERVE)
{
isec = section_from_elf_index (input_bfd, isym->st_shndx);
- if (isec && elf_section_data (isec)->merge_info
+ if (isec
+ && elf_section_data (isec)->sec_info_type == ELF_INFO_TYPE_MERGE
&& ELF_ST_TYPE (isym->st_info) != STT_SECTION)
isym->st_value =
_bfd_merged_section_offset (output_bfd, &isec,
- elf_section_data (isec)->merge_info,
+ elf_section_data (isec)->sec_info,
isym->st_value, (bfd_vma) 0);
}
else if (isym->st_shndx == SHN_ABS)
linker_mark is only reliable for sections that have contents.
For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE
as well as linker_mark. */
- if (isym->st_shndx > 0
- && isym->st_shndx < SHN_LORESERVE
+ if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
&& isec != NULL
&& ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0)
|| (! finfo->info->relocateable
/* Adjust the section index for the output file. */
osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
isec->output_section);
- if (osym.st_shndx == (unsigned short) -1)
+ if (osym.st_shndx == SHN_BAD)
return false;
*pindex = bfd_get_symcount (output_bfd);
.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)
+ if (!finfo->info->relocateable
+ && !elf_section_ignore_discarded_relocs (o))
{
Elf_Internal_Rela *rel, *relend;
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_discarded_section (h->root.u.def.section))
{
#if BFD_VERSION_DATE < 20031005
if ((o->flags & SEC_DEBUGGING) != 0)
_("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
}
else
{
- isym = finfo->internal_syms + r_symndx;
- if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
- {
- asection *sec = finfo->sections[r_symndx];
+ asection *sec = finfo->sections[r_symndx];
- if (sec != NULL
- && ! bfd_is_abs_section (sec)
- && bfd_is_abs_section (sec->output_section))
- {
+ if (sec != NULL && elf_discarded_section (sec))
+ {
#if BFD_VERSION_DATE < 20031005
- if ((o->flags & SEC_DEBUGGING) != 0
- || (sec->flags & SEC_LINK_ONCE) != 0)
- {
+ 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"),
- 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
- rel->r_info
- = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
- rel->r_addend = 0;
- }
- else
+ 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;
- }
+ {
+ 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;
}
}
}
isym->st_shndx =
_bfd_elf_section_from_bfd_section (output_bfd,
osec);
- if (isym->st_shndx == (unsigned short) -1)
+ if (isym->st_shndx == SHN_BAD)
return false;
isym->st_value += sec->output_offset;
}
/* 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))
{
- if (! (_bfd_write_section_stabs
- (output_bfd, &elf_hash_table (finfo->info)->stab_info,
- o, &elf_section_data (o)->stab_info, contents)))
- return false;
+ /* Section written out. */
}
- else if (elf_section_data (o)->merge_info)
+ else switch (elf_section_data (o)->sec_info_type)
{
- if (! (_bfd_write_merged_section
- (output_bfd, o, elf_section_data (o)->merge_info)))
+ case ELF_INFO_TYPE_STABS:
+ if (! (_bfd_write_section_stabs
+ (output_bfd,
+ &elf_hash_table (finfo->info)->stab_info,
+ o, &elf_section_data (o)->sec_info, contents)))
return false;
- }
- else
- {
- bfd_size_type sec_size;
-
- sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
- if (! (o->flags & SEC_EXCLUDE)
- && ! bfd_set_section_contents (output_bfd, o->output_section,
- contents,
- (file_ptr) o->output_offset,
- sec_size))
+ break;
+ case ELF_INFO_TYPE_MERGE:
+ if (! (_bfd_write_merged_section
+ (output_bfd, o, elf_section_data (o)->sec_info)))
return false;
+ break;
+ case ELF_INFO_TYPE_EH_FRAME:
+ {
+ asection *ehdrsec;
+
+ ehdrsec
+ = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj,
+ ".eh_frame_hdr");
+ if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec,
+ contents)))
+ return false;
+ }
+ break;
+ default:
+ {
+ bfd_size_type sec_size;
+
+ sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
+ if (! (o->flags & SEC_EXCLUDE)
+ && ! bfd_set_section_contents (output_bfd, o->output_section,
+ contents,
+ (file_ptr) o->output_offset,
+ sec_size))
+ return false;
+ }
+ break;
}
}
{
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);
}
else
extsymoff = nlocsyms = symtab_hdr->sh_info;
+
if (symtab_hdr->contents)
locsyms = (Elf_External_Sym *) symtab_hdr->contents;
else if (nlocsyms == 0)
}
}
+ 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)
+ return false;
+ }
+
/* Read the relocations. */
relstart = (NAME(_bfd_elf,link_read_relocs)
(sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL,
if (elf_bad_symtab (sec->owner))
{
- elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+ 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
}
else
{
- elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+ 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);
}
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_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))
+ {
+ 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)
+ && elf_discarded_section (h->root.u.def.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 < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE)
+ {
+ isec = section_from_elf_index (rcookie->abfd, isym.st_shndx);
+ if (isec != NULL && elf_discarded_section (isec))
+ 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 (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *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;
+ boolean strip = info->strip == strip_all || info->strip == strip_debugger;
+
+ if (info->relocateable
+ || info->traditional_format
+ || info->hash->creator->flavour != bfd_target_elf_flavour
+ || ! is_elf_hash_table (info))
+ return false;
+
+ ehdr = NULL;
+ if (elf_hash_table (info)->dynobj != NULL)
+ ehdr = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+ ".eh_frame_hdr");
+
+ 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;
+
+ eh = NULL;
+ if (ehdr)
+ {
+ eh = bfd_get_section_by_name (abfd, ".eh_frame");
+ if (eh && eh->_raw_size == 0)
+ eh = NULL;
+ }
+
+ stab = strip ? NULL : bfd_get_section_by_name (abfd, ".stab");
+ if ((! stab || elf_section_data(stab)->sec_info_type != ELF_INFO_TYPE_STABS)
+ && ! eh
+ && (strip || ! bed->elf_backend_discard_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);
+ 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)
+ 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,
+ info->keep_memory));
+ if (cookie.rels)
+ {
+ cookie.rel = cookie.rels;
+ cookie.relend =
+ cookie.rels + stab->reloc_count * bed->s->int_rels_per_ext_rel;
+ if (_bfd_discard_section_stabs (abfd, stab,
+ elf_section_data (stab)->sec_info,
+ elf_reloc_symbol_deleted_p,
+ &cookie))
+ ret = true;
+ if (! info->keep_memory)
+ free (cookie.rels);
+ }
+ }
+
+ if (eh)
+ {
+ cookie.rels = NULL;
+ cookie.rel = NULL;
+ cookie.relend = NULL;
+ if (eh->reloc_count)
+ cookie.rels = (NAME(_bfd_elf,link_read_relocs)
+ (abfd, eh, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory));
+ if (cookie.rels)
+ {
+ cookie.rel = cookie.rels;
+ cookie.relend =
+ cookie.rels + eh->reloc_count * bed->s->int_rels_per_ext_rel;
+ }
+ if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, ehdr,
+ 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 (cookie.locsym_shndx != NULL)
+ free (cookie.locsym_shndx);
+
+ if (freesyms != NULL)
+ free (freesyms);
+ }
+
+ if (ehdr
+ && _bfd_elf_discard_section_eh_frame_hdr (output_bfd,
+ info, ehdr))
+ ret = true;
+ return ret;
+}
+
+static boolean
+elf_section_ignore_discarded_relocs (sec)
+ asection *sec;
+{
+ switch (elf_section_data (sec)->sec_info_type)
+ {
+ case ELF_INFO_TYPE_STABS:
+ case ELF_INFO_TYPE_EH_FRAME:
+ return true;
+ default:
+ break;
+ }
+ 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;
+
+ return false;
+}