diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 11 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 117 |
2 files changed, 94 insertions, 34 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 732db98..48aae37 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +2003-10-23 Alan Modra <amodra@bigpond.net.au> + + * elf64-ppc.c (get_tls_mask): Add toc_symndx param, save toc + reloc symbol index to it. Don't allow gd syms in shared libs + to be optimized. + (ppc64_elf_tls_optimize): Adjust get_tls_mask call. + (ppc64_elf_size_stubs): Likewise. + (ppc64_elf_relocate_section): Check that tls relocs are only used + with tls syms, and similarly for non-tls. Correct symbol used + when optimizing toc tls code. + 2003-10-22 Nick Clifton <nickc@redhat.com> * peicode.h (coff_swap_scnhdr_in): Only remove padding when diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 820f808..564a616 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -4791,11 +4791,12 @@ get_sym_h (struct elf_link_hash_entry **hp, Elf_Internal_Sym **symp, type suitable for optimization, and 1 otherwise. */ static int -get_tls_mask (char **tls_maskp, Elf_Internal_Sym **locsymsp, +get_tls_mask (char **tls_maskp, unsigned long *toc_symndx, + Elf_Internal_Sym **locsymsp, const Elf_Internal_Rela *rel, bfd *ibfd) { unsigned long r_symndx; - unsigned int next_r; + int next_r; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; @@ -4824,17 +4825,14 @@ get_tls_mask (char **tls_maskp, Elf_Internal_Sym **locsymsp, next_r = ppc64_elf_section_data (sec)->t_symndx[off / 8 + 1]; 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) - { - if (next_r == (unsigned) -1) - return 2; - if (next_r == (unsigned) -2 - && (h == NULL - || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))) - return 3; - } + if (toc_symndx != NULL) + *toc_symndx = r_symndx; + if ((h == NULL + || ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))) + && (next_r == -1 || next_r == -2)) + return 1 - next_r; return 1; } @@ -5318,7 +5316,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) char *toc_tls; int retval; - retval = get_tls_mask (&toc_tls, &locsyms, + retval = get_tls_mask (&toc_tls, NULL, &locsyms, rel - 1, ibfd); if (retval == 0) goto err_free_rel; @@ -6902,7 +6900,7 @@ ppc64_elf_size_stubs (bfd *output_bfd, /* Get tls info. */ char *tls_mask; - if (!get_tls_mask (&tls_mask, &local_syms, + if (!get_tls_mask (&tls_mask, NULL, &local_syms, irela - 1, input_bfd)) goto error_ret_free_internal; if (*tls_mask != 0) @@ -7308,8 +7306,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, struct elf_link_hash_entry *h; struct elf_link_hash_entry *fdh; const char *sym_name; - unsigned long r_symndx; + unsigned long r_symndx, toc_symndx; char tls_mask, tls_gd, tls_type; + char sym_type; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_boolean warned; @@ -7343,6 +7342,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, sym = local_syms + r_symndx; sec = local_sections[r_symndx]; sym_name = bfd_elf_local_sym_name (input_bfd, sym); + sym_type = ELF64_ST_TYPE (sym->st_info); relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); if (elf_section_data (sec) != NULL) { @@ -7360,6 +7360,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, unresolved_reloc, info, warned); sym_name = h->root.root.string; + sym_type = h->type; } /* TLS optimizations. Replace instruction sequences and relocs @@ -7368,6 +7369,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, for the final instruction stream. */ tls_mask = 0; tls_gd = 0; + toc_symndx = 0; if (IS_PPC64_TLS_RELOC (r_type)) { if (h != NULL) @@ -7378,6 +7380,42 @@ ppc64_elf_relocate_section (bfd *output_bfd, lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info); tls_mask = lgot_masks[r_symndx]; } + if (tls_mask == 0 && r_type == R_PPC64_TLS) + { + /* Check for toc tls entries. */ + char *toc_tls; + + if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms, + rel, input_bfd)) + return FALSE; + + if (toc_tls) + tls_mask = *toc_tls; + } + } + + /* Check that tls relocs are used with tls syms, and non-tls + relocs are used with non-tls syms. */ + if (r_symndx != 0 + && r_type != R_PPC64_NONE + && (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS)) + { + if (r_type == R_PPC64_TLS && tls_mask != 0) + /* R_PPC64_TLS is OK against a symbol in the TOC. */ + ; + else + (*_bfd_error_handler) + (sym_type == STT_TLS + ? _("%s(%s+0x%lx): %s used with TLS symbol %s") + : _("%s(%s+0x%lx): %s used with non-TLS symbol %s"), + bfd_archive_filename (input_bfd), + input_section->name, + (long) rel->r_offset, + ppc64_elf_howto_table[r_type]->name, + sym_name); } /* Ensure reloc mapping code below stays sane. */ @@ -7392,6 +7430,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3) || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3)) abort (); + switch (r_type) { default: @@ -7406,7 +7445,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, char *toc_tls; int retval; - retval = get_tls_mask (&toc_tls, &local_syms, rel, input_bfd); + retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms, + rel, input_bfd); if (retval == 0) return FALSE; @@ -7451,22 +7491,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn |= 0x3c0d0000; /* addis 0,13,0 */ bfd_put_32 (output_bfd, insn, contents + rel->r_offset - 2); r_type = R_PPC64_TPREL16_HA; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); + if (toc_symndx != 0) + { + rel->r_info = ELF64_R_INFO (toc_symndx, r_type); + /* We changed the symbol. Start over in order to + get h, sym, sec etc. right. */ + rel--; + continue; + } + else + rel->r_info = ELF64_R_INFO (r_symndx, r_type); } break; case R_PPC64_TLS: - if (tls_mask == 0) - { - /* Check for toc tls entries. */ - char *toc_tls; - - if (!get_tls_mask (&toc_tls, &local_syms, rel, input_bfd)) - return FALSE; - - if (toc_tls) - tls_mask = *toc_tls; - } if (tls_mask != 0 && (tls_mask & TLS_TPREL) == 0) { @@ -7502,11 +7540,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, abort (); insn |= rtra; bfd_put_32 (output_bfd, insn, contents + rel->r_offset); - r_type = R_PPC64_TPREL16_LO; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); /* Was PPC64_TLS which sits on insn boundary, now PPC64_TPREL16_LO which is at insn+2. */ rel->r_offset += 2; + r_type = R_PPC64_TPREL16_LO; + if (toc_symndx != 0) + { + rel->r_info = ELF64_R_INFO (toc_symndx, r_type); + /* We changed the symbol. Start over in order to + get h, sym, sec etc. right. */ + rel--; + continue; + } + else + rel->r_info = ELF64_R_INFO (r_symndx, r_type); } break; @@ -7605,6 +7652,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = htab->tls_sec->vma + DTP_OFFSET; rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET; } + else if (toc_symndx != 0) + r_symndx = toc_symndx; r_type = R_PPC64_TPREL16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel[1].r_info = ELF64_R_INFO (r_symndx, @@ -7621,10 +7670,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2); bfd_put_32 (output_bfd, insn2, contents + offset); bfd_put_32 (output_bfd, insn3, contents + offset + 4); - if (tls_gd == 0) + if (tls_gd == 0 || toc_symndx != 0) { - /* We changed the symbol on an LD reloc. Start over - in order to get h, sym, sec etc. right. */ + /* We changed the symbol. Start over in order + to get h, sym, sec etc. right. */ rel--; continue; } |