X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=543a7272b286e4c48d273dda03f9cc38b44584a2;hb=fbd9ad907dc6a283dc1bec51ecd91355ac866949;hp=f17402fad27374246c40a62bbd9c6238bacf8984;hpb=e11840f950f6459e8a28198d4268cdb7e5e1c6a9;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index f17402fad2..543a7272b2 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3317,8 +3317,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, { if (sec->vma > ent) break; - if ((sec->flags & SEC_ALLOC) == 0 - || (sec->flags & SEC_LOAD) == 0) + /* SEC_LOAD may not be set if SEC is from a separate debug + info file. */ + if ((sec->flags & SEC_ALLOC) == 0) break; if ((sec->flags & SEC_CODE) != 0) s->section = sec; @@ -4569,10 +4570,14 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, asection **sec, bfd_vma *value ATTRIBUTE_UNUSED) { + if ((ibfd->flags & DYNAMIC) == 0 + && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE) + elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { if ((ibfd->flags & DYNAMIC) == 0) - elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE; + elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; } else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC) ; @@ -7473,6 +7478,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) bfd *ibfd; asection *sec; struct ppc_link_hash_table *htab; + unsigned char *toc_ref; int pass; if (info->relocatable || !info->executable) @@ -7482,23 +7488,25 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (htab == NULL) return FALSE; - 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; - - /* Look at all the sections for this file. Make two passes over - the relocs. On the first pass, mark toc entries involved - with tls relocs, and check that tls relocs involved in - setting up a tls_get_addr call are indeed followed by such a - call. If they are not, exclude them from the optimizations - done on the second pass. */ - for (pass = 0; pass < 2; ++pass) + /* Make two passes over the relocs. On the first pass, mark toc + entries involved with tls relocs, and check that tls relocs + involved in setting up a tls_get_addr call are indeed followed by + such a call. If they are not, we can't do any tls optimization. + On the second pass twiddle tls_mask flags to notify + relocate_section that optimization can be done, and adjust got + and plt refcounts. */ + toc_ref = NULL; + for (pass = 0; pass < 2; ++pass) + 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"); + for (sec = ibfd->sections; sec != NULL; sec = sec->next) if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) { Elf_Internal_Rela *relstart, *rel, *relend; + bfd_boolean found_tls_get_addr_arg = 0; /* Read the relocations. */ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, @@ -7520,6 +7528,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) bfd_boolean ok_tprel, is_local; long toc_ref_index = 0; int expecting_tls_get_addr = 0; + bfd_boolean ret = FALSE; r_symndx = ELF64_R_SYM (rel->r_info); if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, @@ -7534,7 +7543,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms)) free (locsyms); - return FALSE; + return ret; } if (h != NULL) @@ -7545,7 +7554,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) else if (h->root.type == bfd_link_hash_undefweak) value = 0; else - continue; + { + found_tls_get_addr_arg = 0; + continue; + } } else /* Symbols referenced by TLS relocs must be of type @@ -7572,11 +7584,34 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } r_type = ELF64_R_TYPE (rel->r_info); + /* If this section has old-style __tls_get_addr calls + without marker relocs, then check that each + __tls_get_addr call reloc is preceded by a reloc + that conceivably belongs to the __tls_get_addr arg + setup insn. If we don't find matching arg setup + relocs, don't do any tls optimization. */ + if (pass == 0 + && sec->has_tls_get_addr_call + && h != NULL + && (h == &htab->tls_get_addr->elf + || h == &htab->tls_get_addr_fd->elf) + && !found_tls_get_addr_arg + && is_branch_reloc (r_type)) + { + info->callbacks->minfo (_("%C __tls_get_addr lost arg, " + "TLS optimization disabled\n"), + ibfd, sec, rel->r_offset); + ret = TRUE; + goto err_free_rel; + } + + found_tls_get_addr_arg = 0; switch (r_type) { case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_LO: expecting_tls_get_addr = 1; + found_tls_get_addr_arg = 1; /* Fall thru */ case R_PPC64_GOT_TLSLD16_HI: @@ -7596,6 +7631,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: expecting_tls_get_addr = 1; + found_tls_get_addr_arg = 1; /* Fall thru */ case R_PPC64_GOT_TLSGD16_HI: @@ -7624,11 +7660,14 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } continue; - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TLS: case R_PPC64_TLSGD: case R_PPC64_TLSLD: + found_tls_get_addr_arg = 1; + /* Fall thru */ + + case R_PPC64_TLS: + case R_PPC64_TOC16: + case R_PPC64_TOC16_LO: if (sym_sec == NULL || sym_sec != toc) continue; @@ -7637,18 +7676,17 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) 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; - } + toc_ref = bfd_zmalloc (toc->output_section->rawsize / 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; + toc_ref_index = (value + toc->output_offset) / 8; if (r_type == R_PPC64_TLS || r_type == R_PPC64_TLSGD || r_type == R_PPC64_TLSLD) @@ -7669,7 +7707,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (pass == 0 || sec != toc || toc_ref == NULL - || !toc_ref[rel->r_offset / 8]) + || !toc_ref[(rel->r_offset + toc->output_offset) / 8]) continue; if (ok_tprel) { @@ -7684,7 +7722,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (pass == 0 || sec != toc || toc_ref == NULL - || !toc_ref[rel->r_offset / 8]) + || !toc_ref[(rel->r_offset + toc->output_offset) / 8]) continue; if (rel + 1 < relend && (rel[1].r_info @@ -7736,8 +7774,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) rel, ibfd); if (retval == 0) goto err_free_rel; - if (retval > 1 && toc_tls != NULL) - toc_ref[toc_ref_index] = 1; + if (toc_tls != NULL) + { + if ((*toc_tls & (TLS_GD | TLS_LD)) != 0) + found_tls_get_addr_arg = 1; + if (retval > 1) + toc_ref[toc_ref_index] = 1; + } } continue; } @@ -7748,9 +7791,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) /* Uh oh, we didn't find the expected call. We could just mark this symbol to exclude it from tls optimization but it's safer to skip - the entire section. */ - sec->has_tls_reloc = 0; - break; + the entire optimization. */ + info->callbacks->minfo (_("%C arg lost __tls_get_addr, " + "TLS optimization disabled\n"), + ibfd, sec, rel->r_offset); + ret = TRUE; + goto err_free_rel; } if (expecting_tls_get_addr && htab->tls_get_addr != NULL) @@ -7836,18 +7882,18 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) free (relstart); } - if (toc_ref != NULL) - free (toc_ref); + if (locsyms != NULL + && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms)) + { + if (!info->keep_memory) + free (locsyms); + else + elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms; + } + } - if (locsyms != NULL - && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms)) - { - if (!info->keep_memory) - free (locsyms); - else - elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms; - } - } + if (toc_ref != NULL) + free (toc_ref); return TRUE; } @@ -9743,6 +9789,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) these checks could now disappear. */ if (fh->elf.root.type == bfd_link_hash_undefined) fh->elf.root.type = bfd_link_hash_undefweak; + /* Stop undo_symbol_twiddle changing it back to undefined. */ + fh->was_undefined = 0; } /* Now build the stub. */