diff options
author | Alan Modra <amodra@bigpond.net.au> | 2010-06-25 03:46:04 +0000 |
---|---|---|
committer | Alan Modra <amodra@bigpond.net.au> | 2010-06-25 03:46:04 +0000 |
commit | a2271ca85c97f541761304b2961775e21fe725cc (patch) | |
tree | fd22639802beaeaa32efd8015c3f4a9b86dba133 | |
parent | f2a0c9f14b8dd0d48ba85c6fa58c5af423547404 (diff) | |
download | binutils-redhat-a2271ca85c97f541761304b2961775e21fe725cc.tar.gz |
* elf64-ppc.c (is_static_defined): New function.
(get_tls_mask, ppc_type_of_stub): Use it here.
(ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input.
(ppc64_elf_tls_setup): Typo fix.
(adjust_toc_syms): Correctly handle symbols defined past the end
of the toc. Move syms on removed entries to next entry rather
than to start of toc.
(ppc64_elf_edit_toc): Likewise. Ensure we only attempt to
edit ppc64 input. Allocate one extra word in skip array.
Honour info->keep_memory when reading relocs if we can.
Adjust toc relocs after adjusting symbols.
-rw-r--r-- | bfd/ChangeLog | 16 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 160 |
2 files changed, 115 insertions, 61 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 41b6cb9714..f1365e553d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2010-06-25 Alan Modra <amodra@gmail.com> + + * elf64-ppc.c (is_static_defined): New function. + (get_tls_mask, ppc_type_of_stub): Use it here. + (ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input. + (ppc64_elf_tls_setup): Typo fix. + (adjust_toc_syms): Correctly handle symbols defined past the end + of the toc. Move syms on removed entries to next entry rather + than to start of toc. + (ppc64_elf_edit_toc): Likewise. Ensure we only attempt to + edit ppc64 input. Allocate one extra word in skip array. + Honour info->keep_memory when reading relocs if we can. + Adjust toc relocs after adjusting symbols. + 2010-06-23 Nathan Sidwell <nathan@codesourcery.com> * archive64.c (bfd_elf64_archive_write_armap): Fix buffer overrun @@ -559,7 +573,7 @@ * pe-x86_64.c (TARGET_UNDERSCORE): Set value dependent to USE_MINGW64_LEADING_UNDERSCORES. - * pei-x86_64.c (TARGET_UNDERSCORE): Likewise. + * pei-x86_64.c (TARGET_UNDERSCORE): Likewise. * config.bfd: Change underscoring default for x64 mingw to false. * coffcode.h (coff_write_relocs): Add check that dereferenced diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 769b0a4361..fbc76002e9 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -5566,6 +5566,17 @@ opd_entry_value (asection *opd_sec, return val; } +/* Return true if symbol is defined in a regular object file. */ + +static bfd_boolean +is_static_defined (struct elf_link_hash_entry *h) +{ + return ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->output_section != NULL); +} + /* If FDH is a function descriptor symbol, return the associated code entry symbol if it is defined. Return NULL otherwise. */ @@ -6704,10 +6715,7 @@ get_tls_mask (unsigned char **tls_maskp, *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8]; if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) return 0; - if ((h == NULL - || ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !h->def_dynamic)) + if ((h == NULL || is_static_defined (h)) && (next_r == -1 || next_r == -2)) return 1 - next_r; return 1; @@ -6924,6 +6932,9 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) bfd_boolean need_edit, add_aux_fields; bfd_size_type cnt_16b = 0; + if (!is_ppc64_elf (ibfd)) + continue; + sec = bfd_get_section_by_name (ibfd, ".opd"); if (sec == NULL || sec->size == 0) continue; @@ -7375,7 +7386,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info, _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, opt_fd->dynstr_index); if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd)) - return FALSE; + return NULL; } htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd; tga = &htab->tls_get_addr->elf; @@ -7840,6 +7851,7 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) { struct ppc_link_hash_entry *eh; struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf; + unsigned long i; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -7857,16 +7869,22 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) if (eh->elf.root.u.def.section == toc_inf->toc) { - unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3]; - if (skip != (unsigned long) -1) - eh->elf.root.u.def.value -= skip; + if (eh->elf.root.u.def.value > toc_inf->toc->rawsize) + i = toc_inf->toc->rawsize >> 3; else + i = eh->elf.root.u.def.value >> 3; + + if (toc_inf->skip[i] == (unsigned long) -1) { (*_bfd_error_handler) - (_("%s defined in removed toc entry"), eh->elf.root.root.string); - eh->elf.root.u.def.section = &bfd_abs_section; - eh->elf.root.u.def.value = 0; + (_("%s defined on removed toc entry"), eh->elf.root.root.string); + do + ++i; + while (toc_inf->skip[i] == (unsigned long) -1); + eh->elf.root.u.def.value = (bfd_vma) i << 3; } + + eh->elf.root.u.def.value -= toc_inf->skip[i]; eh->adjust_done = 1; } else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0) @@ -7898,6 +7916,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) unsigned char *used; unsigned char *keep, last, some_unused; + if (!is_ppc64_elf (ibfd)) + continue; + toc = bfd_get_section_by_name (ibfd, ".toc"); if (toc == NULL || toc->size == 0 @@ -7975,7 +7996,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (skip == NULL) { - skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8); + skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8); if (skip == NULL) goto error_ret; } @@ -8025,7 +8046,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) || (sec->flags & SEC_DEBUGGING) != 0) continue; - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE); + relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, + info->keep_memory); if (relstart == NULL) goto error_ret; @@ -8091,6 +8113,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) used[val >> 3] = 1; } while (repeat); + + if (elf_section_data (sec)->relocs != relstart) + free (relstart); } /* Merge the used and skip arrays. Assume that TOC @@ -8143,40 +8168,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) memcpy (src - off, src, 8); } } + *drop = off; toc->rawsize = toc->size; toc->size = src - contents - off; - if (toc->reloc_count != 0) - { - Elf_Internal_Rela *wrel; - bfd_size_type sz; - - /* Read toc relocs. */ - relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, - TRUE); - if (relstart == NULL) - goto error_ret; - - /* Remove unused toc relocs, and adjust those we keep. */ - wrel = relstart; - for (rel = relstart; rel < relstart + toc->reloc_count; ++rel) - if (skip[rel->r_offset >> 3] != (unsigned long) -1) - { - wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3]; - wrel->r_info = rel->r_info; - wrel->r_addend = rel->r_addend; - ++wrel; - } - else if (!dec_dynrel_count (rel->r_info, toc, info, - &local_syms, NULL, NULL)) - goto error_ret; - - toc->reloc_count = wrel - relstart; - sz = elf_section_data (toc)->rel_hdr.sh_entsize; - elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz; - BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL); - } - /* Adjust addends for relocs against the toc section sym. */ for (sec = ibfd->sections; sec != NULL; sec = sec->next) { @@ -8185,7 +8180,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) continue; relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - TRUE); + info->keep_memory); if (relstart == NULL) goto error_ret; @@ -8196,6 +8191,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) asection *sym_sec; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; + bfd_vma val; r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) @@ -8221,8 +8217,17 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (sym_sec != toc || h != NULL || sym->st_value != 0) continue; - rel->r_addend -= skip[rel->r_addend >> 3]; + val = rel->r_addend; + + if (val > toc->rawsize) + val = toc->rawsize; + + rel->r_addend -= skip[val >> 3]; + elf_section_data (sec)->relocs = relstart; } + + if (elf_section_data (sec)->relocs != relstart) + free (relstart); } /* We shouldn't have local or global symbols defined in the TOC, @@ -8237,22 +8242,30 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (sym->st_value != 0 && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc) { - if (skip[sym->st_value >> 3] != (unsigned long) -1) - sym->st_value -= skip[sym->st_value >> 3]; + unsigned long i; + + if (sym->st_value > toc->rawsize) + i = toc->rawsize >> 3; else + i = sym->st_value >> 3; + + if (skip[sym->st_value >> 3] == (unsigned long) -1) { (*_bfd_error_handler) - (_("%s defined in removed toc entry"), - bfd_elf_sym_name (ibfd, symtab_hdr, sym, - NULL)); - sym->st_value = 0; - sym->st_shndx = SHN_ABS; + (_("%s defined on removed toc entry"), + bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL)); + do + ++i; + while (skip[i] == (unsigned long) -1); + sym->st_value = (bfd_vma) i << 3; } + + sym->st_value -= skip[i]; symtab_hdr->contents = (unsigned char *) local_syms; } } - /* Finally, adjust any global syms defined in the toc. */ + /* Adjust any global syms defined in this toc input section. */ if (toc_inf.global_toc_syms) { toc_inf.toc = toc; @@ -8261,6 +8274,37 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms, &toc_inf); } + + if (toc->reloc_count != 0) + { + Elf_Internal_Rela *wrel; + bfd_size_type sz; + + /* Read toc relocs. */ + relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, + TRUE); + if (relstart == NULL) + goto error_ret; + + /* Remove unused toc relocs, and adjust those we keep. */ + wrel = relstart; + for (rel = relstart; rel < relstart + toc->reloc_count; ++rel) + if (skip[rel->r_offset >> 3] != (unsigned long) -1) + { + wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3]; + wrel->r_info = rel->r_info; + wrel->r_addend = rel->r_addend; + ++wrel; + } + else if (!dec_dynrel_count (rel->r_info, toc, info, + &local_syms, NULL, NULL)) + goto error_ret; + + toc->reloc_count = wrel - relstart; + sz = elf_section_data (toc)->rel_hdr.sh_entsize; + elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz; + BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL); + } } if (local_syms != NULL @@ -9007,12 +9051,8 @@ ppc_type_of_stub (asection *input_sec, either a defined function descriptor or a defined entry symbol in a regular object file, then it is pointless trying to make any other type of stub. */ - if (!((fdh->elf.root.type == bfd_link_hash_defined - || fdh->elf.root.type == bfd_link_hash_defweak) - && fdh->elf.root.u.def.section->output_section != NULL) - && !((h->elf.root.type == bfd_link_hash_defined - || h->elf.root.type == bfd_link_hash_defweak) - && h->elf.root.u.def.section->output_section != NULL)) + if (!is_static_defined (&fdh->elf) + && !is_static_defined (&h->elf)) return ppc_stub_none; } else if (elf_local_got_ents (input_sec->owner) != NULL) |