* elf-bfd.h (_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): Declare.
	(_bfd_elf_gc_mark): Use elf_gc_mark_hook_fn.
	* elflink.c (init_reloc_cookie, fini_reloc_cookie)
	(init_reloc_cookie_rels, fini_reloc_cookie_rels): New functions,
	split out from...
	(bfd_elf_discard_info): ...here.
	(init_reloc_cookie_for_section): New function.
	(fini_reloc_cookie_for_section): Likewise.
	(_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): New functions,
	split out from...
	(_bfd_elf_gc_mark): ...here.  Use init_reloc_cookie_for_section
	and fini_reloc_cookie_for_section.
This commit is contained in:
Richard Sandiford
2007-12-15 09:31:41 +00:00
parent 281b8327ae
commit 5241d85325
3 changed files with 241 additions and 172 deletions

View File

@ -1,3 +1,18 @@
2007-12-15 Richard Sandiford <rsandifo@nildram.co.uk>
* elf-bfd.h (_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): Declare.
(_bfd_elf_gc_mark): Use elf_gc_mark_hook_fn.
* elflink.c (init_reloc_cookie, fini_reloc_cookie)
(init_reloc_cookie_rels, fini_reloc_cookie_rels): New functions,
split out from...
(bfd_elf_discard_info): ...here.
(init_reloc_cookie_for_section): New function.
(fini_reloc_cookie_for_section): Likewise.
(_bfd_elf_gc_mark_rsec, _bfd_elf_gc_mark_reloc): New functions,
split out from...
(_bfd_elf_gc_mark): ...here. Use init_reloc_cookie_for_section
and fini_reloc_cookie_for_section.
2007-12-12 Bob Wilson <bob.wilson@acm.org> 2007-12-12 Bob Wilson <bob.wilson@acm.org>
* elf32-xtensa.c (elf_xtensa_do_reloc): Update self_address along with * elf32-xtensa.c (elf_xtensa_do_reloc): Update self_address along with

View File

@ -1971,10 +1971,16 @@ extern asection *_bfd_elf_gc_mark_hook
(asection *, struct bfd_link_info *, Elf_Internal_Rela *, (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *); struct elf_link_hash_entry *, Elf_Internal_Sym *);
extern asection *_bfd_elf_gc_mark_rsec
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
struct elf_reloc_cookie *);
extern bfd_boolean _bfd_elf_gc_mark_reloc
(struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
struct elf_reloc_cookie *, bfd_boolean);
extern bfd_boolean _bfd_elf_gc_mark extern bfd_boolean _bfd_elf_gc_mark
(struct bfd_link_info *, asection *, (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn);
asection * (*) (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
struct elf_link_hash_entry *, Elf_Internal_Sym *));
extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets
(bfd *, struct bfd_link_info *); (bfd *, struct bfd_link_info *);

View File

@ -10940,6 +10940,139 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
return FALSE; return FALSE;
} }
/* Initialize COOKIE for input bfd ABFD. */
static bfd_boolean
init_reloc_cookie (struct elf_reloc_cookie *cookie,
struct bfd_link_info *info, bfd *abfd)
{
Elf_Internal_Shdr *symtab_hdr;
const struct elf_backend_data *bed;
bed = get_elf_backend_data (abfd);
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 / bed->s->sizeof_sym;
cookie->extsymoff = 0;
}
else
{
cookie->locsymcount = symtab_hdr->sh_info;
cookie->extsymoff = symtab_hdr->sh_info;
}
if (bed->s->arch_size == 32)
cookie->r_sym_shift = 8;
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 (info->keep_memory)
symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
}
return TRUE;
}
/* Free the memory allocated by init_reloc_cookie, if appropriate. */
static void
fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
{
Elf_Internal_Shdr *symtab_hdr;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
if (cookie->locsyms != NULL
&& symtab_hdr->contents != (unsigned char *) cookie->locsyms)
free (cookie->locsyms);
}
/* Initialize the relocation information in COOKIE for input section SEC
of input bfd ABFD. */
static bfd_boolean
init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
struct bfd_link_info *info, bfd *abfd,
asection *sec)
{
const struct elf_backend_data *bed;
if (sec->reloc_count == 0)
{
cookie->rels = NULL;
cookie->relend = NULL;
}
else
{
bed = get_elf_backend_data (abfd);
cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
info->keep_memory);
if (cookie->rels == NULL)
return FALSE;
cookie->rel = cookie->rels;
cookie->relend = (cookie->rels
+ sec->reloc_count * bed->s->int_rels_per_ext_rel);
}
cookie->rel = cookie->rels;
return TRUE;
}
/* Free the memory allocated by init_reloc_cookie_rels,
if appropriate. */
static void
fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
asection *sec)
{
if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
free (cookie->rels);
}
/* Initialize the whole of COOKIE for input section SEC. */
static bfd_boolean
init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
struct bfd_link_info *info,
asection *sec)
{
if (!init_reloc_cookie (cookie, info, sec->owner))
goto error1;
if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
goto error2;
return TRUE;
error2:
fini_reloc_cookie (cookie, sec->owner);
error1:
return FALSE;
}
/* Free the memory allocated by init_reloc_cookie_for_section,
if appropriate. */
static void
fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
asection *sec)
{
fini_reloc_cookie_rels (cookie, sec);
fini_reloc_cookie (cookie, sec->owner);
}
/* Garbage collect unused sections. */ /* Garbage collect unused sections. */
/* Default gc_mark_hook. */ /* Default gc_mark_hook. */
@ -10972,6 +11105,63 @@ _bfd_elf_gc_mark_hook (asection *sec,
return NULL; return NULL;
} }
/* COOKIE->rel describes a relocation against section SEC, which is
a section we've decided to keep. Return the section that contains
the relocation symbol, or NULL if no section contains it. */
asection *
_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
elf_gc_mark_hook_fn gc_mark_hook,
struct elf_reloc_cookie *cookie)
{
unsigned long r_symndx;
struct elf_link_hash_entry *h;
r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
if (r_symndx == 0)
return NULL;
if (r_symndx >= cookie->locsymcount
|| ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
{
h = cookie->sym_hashes[r_symndx - cookie->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;
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
}
return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
&cookie->locsyms[r_symndx]);
}
/* COOKIE->rel describes a relocation against section SEC, which is
a section we've decided to keep. Mark the section that contains
the relocation symbol. IS_EH is true if the mark comes from
.eh_frame. */
bfd_boolean
_bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
asection *sec,
elf_gc_mark_hook_fn gc_mark_hook,
struct elf_reloc_cookie *cookie,
bfd_boolean is_eh)
{
asection *rsec;
rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
if (rsec && !rsec->gc_mark)
{
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
rsec->gc_mark = 1;
else if (is_eh)
rsec->gc_mark_from_eh = 1;
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
return FALSE;
}
return TRUE;
}
/* The mark phase of garbage collection. For a given section, mark /* The mark phase of garbage collection. For a given section, mark
it and any sections in this section's group, and all the sections it and any sections in this section's group, and all the sections
which define symbols to which it refers. */ which define symbols to which it refers. */
@ -10998,103 +11188,22 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
is_eh = strcmp (sec->name, ".eh_frame") == 0; is_eh = strcmp (sec->name, ".eh_frame") == 0;
if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0) if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
{ {
Elf_Internal_Rela *relstart, *rel, *relend; struct elf_reloc_cookie cookie;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
size_t nlocsyms;
size_t extsymoff;
bfd *input_bfd = sec->owner;
const struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
Elf_Internal_Sym *isym = NULL;
int r_sym_shift;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; if (!init_reloc_cookie_for_section (&cookie, info, sec))
sym_hashes = elf_sym_hashes (input_bfd); ret = FALSE;
/* Read the local symbols. */
if (elf_bad_symtab (input_bfd))
{
nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
extsymoff = 0;
}
else else
extsymoff = nlocsyms = symtab_hdr->sh_info;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isym == NULL && nlocsyms != 0)
{ {
isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0, for (; cookie.rel < cookie.relend; cookie.rel++)
NULL, NULL, NULL); if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook,
if (isym == NULL) &cookie, is_eh))
return FALSE;
}
/* Read the relocations. */
relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL,
info->keep_memory);
if (relstart == NULL)
{ {
ret = FALSE; ret = FALSE;
goto out1; break;
} }
relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; fini_reloc_cookie_for_section (&cookie, sec);
if (bed->s->arch_size == 32)
r_sym_shift = 8;
else
r_sym_shift = 32;
for (rel = relstart; rel < relend; rel++)
{
unsigned long r_symndx;
asection *rsec;
struct elf_link_hash_entry *h;
r_symndx = rel->r_info >> r_sym_shift;
if (r_symndx == 0)
continue;
if (r_symndx >= nlocsyms
|| ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
{
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;
rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
}
else
{
rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
}
if (rsec && !rsec->gc_mark)
{
if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
rsec->gc_mark = 1;
else if (is_eh)
rsec->gc_mark_from_eh = 1;
else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
{
ret = FALSE;
goto out2;
} }
} }
}
out2:
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
out1:
if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
{
if (! info->keep_memory)
free (isym);
else
symtab_hdr->contents = (unsigned char *) isym;
}
}
return ret; return ret;
} }
@ -11777,10 +11886,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
{ {
struct elf_reloc_cookie cookie; struct elf_reloc_cookie cookie;
asection *stab, *eh; asection *stab, *eh;
Elf_Internal_Shdr *symtab_hdr;
const struct elf_backend_data *bed; const struct elf_backend_data *bed;
bfd *abfd; bfd *abfd;
unsigned int count;
bfd_boolean ret = FALSE; bfd_boolean ret = FALSE;
if (info->traditional_format if (info->traditional_format
@ -11819,95 +11926,36 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
&& bed->elf_backend_discard_info == NULL) && bed->elf_backend_discard_info == NULL)
continue; continue;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr; if (!init_reloc_cookie (&cookie, info, abfd))
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 / bed->s->sizeof_sym;
cookie.extsymoff = 0;
}
else
{
cookie.locsymcount = symtab_hdr->sh_info;
cookie.extsymoff = symtab_hdr->sh_info;
}
if (bed->s->arch_size == 32)
cookie.r_sym_shift = 8;
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; return FALSE;
}
}
if (stab != NULL) if (stab != NULL
&& stab->reloc_count > 0
&& init_reloc_cookie_rels (&cookie, info, abfd, stab))
{ {
cookie.rels = NULL;
count = stab->reloc_count;
if (count != 0)
cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL,
info->keep_memory);
if (cookie.rels != NULL)
{
cookie.rel = cookie.rels;
cookie.relend = cookie.rels;
cookie.relend += count * bed->s->int_rels_per_ext_rel;
if (_bfd_discard_section_stabs (abfd, stab, if (_bfd_discard_section_stabs (abfd, stab,
elf_section_data (stab)->sec_info, elf_section_data (stab)->sec_info,
bfd_elf_reloc_symbol_deleted_p, bfd_elf_reloc_symbol_deleted_p,
&cookie)) &cookie))
ret = TRUE; ret = TRUE;
if (elf_section_data (stab)->relocs != cookie.rels) fini_reloc_cookie_rels (&cookie, stab);
free (cookie.rels);
}
} }
if (eh != NULL) if (eh != NULL
&& init_reloc_cookie_rels (&cookie, info, abfd, eh))
{ {
cookie.rels = NULL;
count = eh->reloc_count;
if (count != 0)
cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL,
info->keep_memory);
cookie.rel = cookie.rels;
cookie.relend = cookie.rels;
if (cookie.rels != NULL)
cookie.relend += count * bed->s->int_rels_per_ext_rel;
if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
bfd_elf_reloc_symbol_deleted_p, bfd_elf_reloc_symbol_deleted_p,
&cookie)) &cookie))
ret = TRUE; ret = TRUE;
fini_reloc_cookie_rels (&cookie, eh);
if (cookie.rels != NULL
&& elf_section_data (eh)->relocs != cookie.rels)
free (cookie.rels);
} }
if (bed->elf_backend_discard_info != NULL if (bed->elf_backend_discard_info != NULL
&& (*bed->elf_backend_discard_info) (abfd, &cookie, info)) && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
ret = TRUE; ret = TRUE;
if (cookie.locsyms != NULL fini_reloc_cookie (&cookie, abfd);
&& symtab_hdr->contents != (unsigned char *) cookie.locsyms)
{
if (! info->keep_memory)
free (cookie.locsyms);
else
symtab_hdr->contents = (unsigned char *) cookie.locsyms;
}
} }
if (info->eh_frame_hdr if (info->eh_frame_hdr