struct elf_reloc_cookie
{
- Elf_Internal_Rela *rels, *rel, *relend;
- Elf_Internal_Sym *locsyms;
bfd *abfd;
- size_t locsymcount;
- size_t extsymoff;
- struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *rels, *rel, *relend;
+ /* Number of symbols that may be local syms (all when bad_symtab). */
+ unsigned int locsymcount;
+ /* Symbol index of first possible global sym (0 when bad_symtab). */
+ unsigned int extsymoff;
int r_sym_shift;
- bool bad_symtab;
};
/* The level of IRIX compatibility we're striving for. */
minus the sh_info field of the symbol table header. */
struct elf_link_hash_entry **sym_hashes;
+ /* Section indices of local symbols, used by gc-sections. */
+ unsigned int *loc_shndx;
+
/* Track usage and final offsets of GOT entries for local symbols.
This array is indexed by symbol index. Elements are used
identically to "got" in struct elf_link_hash_entry. */
#define elf_gp(bfd) (elf_tdata(bfd) -> gp)
#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size)
#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes)
+#define elf_loc_shndx(bfd) (elf_tdata(bfd) -> loc_shndx)
#define elf_local_got_refcounts(bfd) (elf_tdata(bfd) -> local_got.refcounts)
#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets)
#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents)
extern struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry
(struct elf_link_hash_entry **, unsigned int, unsigned int);
+extern asection *_bfd_get_local_sym_section
+ (struct elf_reloc_cookie *, unsigned int);
/* Large common section. */
extern asection _bfd_elf_large_com_section;
}
else
{
- Elf_Internal_Sym *sym;
- asection *sym_sec;
-
- sym = &cookie->locsyms[r_symndx];
- sym_sec = bfd_section_from_elf_index (abfd, sym->st_shndx);
+ asection *sym_sec = _bfd_get_local_sym_section (cookie, r_symndx);
if (sym_sec == NULL)
return cie_inf;
return true;
}
-/* The same for all local symbols defined in .eh_frame. Returns true
- if any symbol was changed. */
+/* The same for all local symbols defined in .eh_frame. Returns the
+ local symbols if any symbol was changed. */
-static int
+static Elf_Internal_Sym *
adjust_eh_frame_local_symbols (const asection *sec,
struct elf_reloc_cookie *cookie)
{
- int adjusted = 0;
+ bfd *abfd = cookie->abfd;
+ unsigned int *loc_shndx = elf_loc_shndx (abfd);
+ unsigned int shndx = elf_section_data (sec)->this_idx;
- if (cookie->locsymcount > 1)
+ if (loc_shndx != NULL)
{
- unsigned int shndx = elf_section_data (sec)->this_idx;
- Elf_Internal_Sym *end_sym = cookie->locsyms + cookie->locsymcount;
- Elf_Internal_Sym *sym;
+ unsigned int i;
- for (sym = cookie->locsyms + 1; sym < end_sym; ++sym)
- if (sym->st_info <= ELF_ST_INFO (STB_LOCAL, STT_OBJECT)
- && sym->st_shndx == shndx)
- {
- bfd_signed_vma delta = offset_adjust (sym->st_value, sec);
+ for (i = 1; i < cookie->locsymcount; i++)
+ if (loc_shndx[i] == shndx)
+ break;
+ if (i >= cookie->locsymcount)
+ return NULL;
+ }
- if (delta != 0)
- {
- adjusted = 1;
- sym->st_value += delta;
- }
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
+ Elf_Internal_Sym *locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ cookie->locsymcount, 0,
+ NULL, NULL, NULL);
+ if (locsyms == NULL)
+ return NULL;
+
+ bool adjusted = false;
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Sym *end_sym = locsyms + cookie->locsymcount;
+ for (sym = locsyms + 1; sym < end_sym; ++sym)
+ if (sym->st_info <= ELF_ST_INFO (STB_LOCAL, STT_OBJECT)
+ && sym->st_shndx == shndx)
+ {
+ bfd_signed_vma delta = offset_adjust (sym->st_value, sec);
+
+ if (delta != 0)
+ {
+ adjusted = true;
+ sym->st_value += delta;
}
- }
- return adjusted;
+ }
+ if (adjusted)
+ return locsyms;
+ free (locsyms);
+ return NULL;
}
/* This function is called for each input file before the .eh_frame
if (sec->size != sec->rawsize)
changed = 1;
- if (changed && adjust_eh_frame_local_symbols (sec, cookie))
+ if (changed)
{
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- symtab_hdr->contents = (unsigned char *) cookie->locsyms;
+ Elf_Internal_Sym *locsyms = adjust_eh_frame_local_symbols (sec, cookie);
+ if (locsyms != NULL)
+ {
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
+ symtab_hdr->contents = (unsigned char *) locsyms;
+ }
}
return changed;
}
{
if (cookie == NULL)
return NULL;
-
- return _bfd_elf_get_link_hash_entry (cookie->sym_hashes, symndx,
+
+ return _bfd_elf_get_link_hash_entry (elf_sym_hashes (cookie->abfd), symndx,
cookie->extsymoff);
}
+asection *
+_bfd_get_local_sym_section (struct elf_reloc_cookie *cookie,
+ unsigned int symndx)
+{
+ if (symndx >= cookie->locsymcount)
+ return NULL;
+
+ bfd *abfd = cookie->abfd;
+ if (elf_loc_shndx (abfd) == NULL)
+ {
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ Elf_Internal_Sym *locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ cookie->locsymcount, 0,
+ NULL, NULL, NULL);
+ if (locsyms == NULL)
+ return NULL;
+ unsigned int *loc_shndx
+ = bfd_alloc (abfd, cookie->locsymcount * sizeof (*loc_shndx));
+ if (loc_shndx == NULL)
+ return NULL;
+ elf_loc_shndx (abfd) = loc_shndx;
+ for (unsigned int i = 0; i < cookie->locsymcount; i++)
+ {
+ loc_shndx[i] = locsyms[i].st_shndx;
+ if (ELF_ST_BIND (locsyms[i].st_info) != STB_LOCAL)
+ loc_shndx[i] = SHN_BAD;
+ }
+ free (locsyms);
+ }
+
+ return bfd_section_from_elf_index (abfd, elf_loc_shndx (abfd)[symndx]);
+}
+
asection *
_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie,
unsigned long r_symndx)
return NULL;
}
- Elf_Internal_Sym *isym = &cookie->locsyms[r_symndx];
- return bfd_section_from_elf_index (cookie->abfd, isym->st_shndx);
+ return _bfd_get_local_sym_section (cookie, r_symndx);
}
/* Define a symbol in a dynamic linkage section. */
{
/* We store a pointer to the hash table entry for each
external symbol. */
- size_t amt = extsymcount * sizeof (struct elf_link_hash_entry *);
- sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt);
+ sym_hash = bfd_zalloc (abfd, extsymcount * sizeof (*sym_hash));
if (sym_hash == NULL)
goto error_free_sym;
elf_sym_hashes (abfd) = sym_hash;
if ((input_bfd->flags & DYNAMIC) != 0)
return true;
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
if (elf_bad_symtab (input_bfd))
{
locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
/* Initialize COOKIE for input bfd ABFD. */
static bool
-init_reloc_cookie (struct elf_reloc_cookie *cookie,
- struct bfd_link_info *info, bfd *abfd,
- bool keep_memory)
+init_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
{
Elf_Internal_Shdr *symtab_hdr;
const struct elf_backend_data *bed;
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)
+ if (elf_bad_symtab (abfd))
{
cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
cookie->extsymoff = 0;
else
cookie->r_sym_shift = 32;
- cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (cookie->locsyms == NULL && cookie->locsymcount != 0)
- {
- cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- cookie->locsymcount, 0,
- NULL, NULL, NULL);
- if (cookie->locsyms == NULL)
- {
- info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
- return false;
- }
- if (keep_memory || _bfd_elf_link_keep_memory (info))
- {
- symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
- info->cache_size += (cookie->locsymcount
- * sizeof (Elf_Internal_Sym));
- }
- }
return true;
}
/* Free the memory allocated by init_reloc_cookie, if appropriate. */
static void
-fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
+fini_reloc_cookie (struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED,
+ bfd *abfd ATTRIBUTE_UNUSED)
{
- Elf_Internal_Shdr *symtab_hdr;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- if (symtab_hdr->contents != (unsigned char *) cookie->locsyms)
- free (cookie->locsyms);
}
/* Initialize the relocation information in COOKIE for input section SEC
struct bfd_link_info *info,
asection *sec, bool keep_memory)
{
- if (!init_reloc_cookie (cookie, info, sec->owner, keep_memory))
+ if (!init_reloc_cookie (cookie, sec->owner))
goto error1;
if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec,
keep_memory))
/* Default gc_mark_hook. */
asection *
-_bfd_elf_gc_mark_hook (asection *sec,
+_bfd_elf_gc_mark_hook (asection *sec ATTRIBUTE_UNUSED,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
struct elf_reloc_cookie *cookie,
struct elf_link_hash_entry *h,
unsigned int symndx)
{
if (h == NULL)
- {
- Elf_Internal_Sym *sym = &cookie->locsyms[symndx];
- return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
- }
+ return _bfd_get_local_sym_section (cookie, symndx);
switch (h->root.type)
{
else
{
/* Return the local debug definition section. */
- Elf_Internal_Sym *sym = &cookie->locsyms[symndx];
- asection *isec = bfd_section_from_elf_index (sec->owner,
- sym->st_shndx);
+ asection *isec = _bfd_get_local_sym_section (cookie, symndx);
if (isec != NULL && (isec->flags & SEC_DEBUGGING) != 0)
return isec;
}
if (sec == NULL || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
continue;
- if (!init_reloc_cookie (&cookie, info, ibfd, false))
+ if (!init_reloc_cookie (&cookie, ibfd))
return false;
for (sec = ibfd->sections; sec; sec = sec->next)
{
struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie;
- if (rcookie->bad_symtab)
+ if (elf_bad_symtab (rcookie->abfd))
rcookie->rel = rcookie->rels;
for (; rcookie->rel < rcookie->relend; rcookie->rel++)
{
unsigned long r_symndx;
- if (! rcookie->bad_symtab)
- if (rcookie->rel->r_offset > offset)
- return false;
+ if (!elf_bad_symtab (rcookie->abfd)
+ && rcookie->rel->r_offset > offset)
+ return false;
if (rcookie->rel->r_offset != offset)
continue;
/* 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. */
- isym = &rcookie->locsyms[r_symndx];
- isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
+ asection *isec = _bfd_get_local_sym_section (cookie, r_symndx);
if (isec != NULL
&& (isec->kept_section != NULL
|| discarded_section (isec)))
if (bed->elf_backend_discard_info != NULL)
{
- if (!init_reloc_cookie (&cookie, info, abfd, false))
+ if (!init_reloc_cookie (&cookie, abfd))
return -1;
if ((*bed->elf_backend_discard_info) (abfd, &cookie, info))