diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2007-12-15 09:31:41 +0000 |
---|---|---|
committer | Richard Sandiford <rdsandiford@googlemail.com> | 2007-12-15 09:31:41 +0000 |
commit | 5241d85325456acf1c190f10e54e87cb11a624a1 (patch) | |
tree | 61a16480f1d5fc014e70578e1a3bc462e9a3e360 /bfd/elflink.c | |
parent | 281b8327ae1f49929a1f7a3c0bba5dec54eeeec2 (diff) | |
download | gdb-5241d85325456acf1c190f10e54e87cb11a624a1.zip gdb-5241d85325456acf1c190f10e54e87cb11a624a1.tar.gz gdb-5241d85325456acf1c190f10e54e87cb11a624a1.tar.bz2 |
bfd/
* 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.
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 384 |
1 files changed, 216 insertions, 168 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index 48072f8..a73f6c8 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -10940,6 +10940,139 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) 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. */ /* Default gc_mark_hook. */ @@ -10972,6 +11105,63 @@ _bfd_elf_gc_mark_hook (asection *sec, 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 it and any sections in this section's group, and all the sections 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; if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0) { - Elf_Internal_Rela *relstart, *rel, *relend; - 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; - sym_hashes = elf_sym_hashes (input_bfd); - - /* Read the local symbols. */ - if (elf_bad_symtab (input_bfd)) - { - nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym; - extsymoff = 0; - } - 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, - NULL, NULL, NULL); - if (isym == NULL) - return FALSE; - } + struct elf_reloc_cookie cookie; - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - { - ret = FALSE; - goto out1; - } - relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; - - if (bed->s->arch_size == 32) - r_sym_shift = 8; + if (!init_reloc_cookie_for_section (&cookie, info, sec)) + ret = FALSE; 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; + for (; cookie.rel < cookie.relend; cookie.rel++) + if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, + &cookie, is_eh)) + { + ret = FALSE; + break; + } + fini_reloc_cookie_for_section (&cookie, sec); } } - return ret; } @@ -11777,10 +11886,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) { struct elf_reloc_cookie cookie; asection *stab, *eh; - Elf_Internal_Shdr *symtab_hdr; const struct elf_backend_data *bed; bfd *abfd; - unsigned int count; bfd_boolean ret = FALSE; 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) 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 / 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 (!init_reloc_cookie (&cookie, info, abfd)) + 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, - elf_section_data (stab)->sec_info, - bfd_elf_reloc_symbol_deleted_p, - &cookie)) - ret = TRUE; - if (elf_section_data (stab)->relocs != cookie.rels) - free (cookie.rels); - } + if (_bfd_discard_section_stabs (abfd, stab, + elf_section_data (stab)->sec_info, + bfd_elf_reloc_symbol_deleted_p, + &cookie)) + ret = TRUE; + fini_reloc_cookie_rels (&cookie, stab); } - 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, bfd_elf_reloc_symbol_deleted_p, &cookie)) ret = TRUE; - - if (cookie.rels != NULL - && elf_section_data (eh)->relocs != cookie.rels) - free (cookie.rels); + fini_reloc_cookie_rels (&cookie, eh); } if (bed->elf_backend_discard_info != NULL && (*bed->elf_backend_discard_info) (abfd, &cookie, info)) ret = TRUE; - if (cookie.locsyms != NULL - && symtab_hdr->contents != (unsigned char *) cookie.locsyms) - { - if (! info->keep_memory) - free (cookie.locsyms); - else - symtab_hdr->contents = (unsigned char *) cookie.locsyms; - } + fini_reloc_cookie (&cookie, abfd); } if (info->eh_frame_hdr |