diff options
author | Joseph Myers <jsm@polyomino.org.uk> | 2006-08-22 15:08:47 +0000 |
---|---|---|
committer | Joseph Myers <jsm@polyomino.org.uk> | 2006-08-22 15:08:47 +0000 |
commit | 150ddb4e15daf7b71cc7f30cbad13dfff6cd6d76 (patch) | |
tree | 2270c98b8ad371d2e747aa35fc18d76e2b13ae02 /bfd/elf64-ppc.c | |
parent | dd18ff9757a447d2ba98b72021af4533058b0d83 (diff) | |
download | gdb-150ddb4e15daf7b71cc7f30cbad13dfff6cd6d76.tar.gz |
Merge changes between binutils-csl-2_17-branchpoint and
binutils-2_17, except for the addition of generated files to CVS.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index fc8c182e83d..33327f44cba 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -2623,6 +2623,32 @@ compare_symbols (const void *ap, const void *bp) if (a->value + a->section->vma > b->value + b->section->vma) return 1; + /* For syms with the same value, prefer strong dynamic global function + syms over other syms. */ + if ((a->flags & BSF_GLOBAL) != 0 && (b->flags & BSF_GLOBAL) == 0) + return -1; + + if ((a->flags & BSF_GLOBAL) == 0 && (b->flags & BSF_GLOBAL) != 0) + return 1; + + if ((a->flags & BSF_FUNCTION) != 0 && (b->flags & BSF_FUNCTION) == 0) + return -1; + + if ((a->flags & BSF_FUNCTION) == 0 && (b->flags & BSF_FUNCTION) != 0) + return 1; + + if ((a->flags & BSF_WEAK) == 0 && (b->flags & BSF_WEAK) != 0) + return -1; + + if ((a->flags & BSF_WEAK) != 0 && (b->flags & BSF_WEAK) == 0) + return 1; + + if ((a->flags & BSF_DYNAMIC) != 0 && (b->flags & BSF_DYNAMIC) == 0) + return -1; + + if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0) + return 1; + return 0; } @@ -6696,12 +6722,22 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) { Elf_Internal_Sym *locsyms = NULL; + asection *toc = bfd_get_section_by_name (ibfd, ".toc"); + unsigned char *toc_ref = NULL; - for (sec = ibfd->sections; sec != NULL; sec = sec->next) + /* Look at all the sections for this file, with TOC last. */ + for (sec = (ibfd->sections == toc && toc && toc->next ? toc->next + : ibfd->sections); + sec != NULL; + sec = (sec == toc ? NULL + : sec->next == NULL ? toc + : sec->next == toc && toc->next ? toc->next + : sec->next)) if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) { Elf_Internal_Rela *relstart, *rel, *relend; int expecting_tls_get_addr; + long toc_ref_index = 0; /* Read the relocations. */ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, @@ -6730,6 +6766,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) err_free_rel: if (elf_section_data (sec)->relocs != relstart) free (relstart); + if (toc_ref != NULL) + free (toc_ref); if (locsyms != NULL && (elf_tdata (ibfd)->symtab_hdr.contents != (unsigned char *) locsyms)) @@ -6837,8 +6875,12 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) rel - 1, ibfd); if (retval == 0) goto err_free_rel; - if (toc_tls != NULL) - expecting_tls_get_addr = retval > 1; + if (retval > 1 && toc_tls != NULL) + { + expecting_tls_get_addr = 1; + if (toc_ref != NULL) + toc_ref[toc_ref_index] = 1; + } } if (expecting_tls_get_addr) @@ -6856,8 +6898,40 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) expecting_tls_get_addr = 0; continue; + case R_PPC64_TOC16: + case R_PPC64_TOC16_LO: + case R_PPC64_TLS: + expecting_tls_get_addr = 0; + if (sym_sec == toc && toc != NULL) + { + /* Mark this toc entry as referenced by a TLS + code sequence. We can do that now in the + case of R_PPC64_TLS, and after checking for + tls_get_addr for the TOC16 relocs. */ + if (toc_ref == NULL) + { + toc_ref = bfd_zmalloc (toc->size / 8); + if (toc_ref == NULL) + goto err_free_rel; + } + if (h != NULL) + value = h->root.u.def.value; + else + value = sym->st_value; + value += rel->r_addend; + BFD_ASSERT (value < toc->size && value % 8 == 0); + toc_ref_index = value / 8; + if (r_type == R_PPC64_TLS) + toc_ref[toc_ref_index] = 1; + } + continue; + case R_PPC64_TPREL64: expecting_tls_get_addr = 0; + if (sec != toc + || toc_ref == NULL + || !toc_ref[rel->r_offset / 8]) + continue; if (ok_tprel) { /* IE -> LE */ @@ -6870,6 +6944,10 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) case R_PPC64_DTPMOD64: expecting_tls_get_addr = 0; + if (sec != toc + || toc_ref == NULL + || !toc_ref[rel->r_offset / 8]) + continue; if (rel + 1 < relend && (rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) @@ -6948,6 +7026,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) free (relstart); } + if (toc_ref != NULL) + free (toc_ref); + if (locsyms != NULL && (elf_tdata (ibfd)->symtab_hdr.contents != (unsigned char *) locsyms)) @@ -7143,13 +7224,14 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) return FALSE; } - /* Now check all kept sections that might reference the toc. */ - for (sec = ibfd->sections; + /* Now check all kept sections that might reference the toc. + Check the toc itself last. */ + for (sec = (ibfd->sections == toc && toc->next ? toc->next + : ibfd->sections); sec != NULL; - /* Check the toc itself last. */ sec = (sec == toc ? NULL - : sec->next == toc && sec->next->next ? sec->next->next : sec->next == NULL ? toc + : sec->next == toc && toc->next ? toc->next : sec->next)) { int repeat; |