X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=2cdb0a265a14bb0f44eb1ae4eee7b9d166daafc6;hb=d4730f921aed32ae4f01e10b8dc399f09b64435b;hp=116d4196b682dc47649c696389f2d46cf3ddfe32;hpb=ba761f19f5658feaff39b69c0bdc84b8716cd3f9;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 116d4196b6..2cdb0a265a 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -61,6 +61,7 @@ static bfd_vma opd_entry_value #define TARGET_BIG_SYM bfd_elf64_powerpc_vec #define TARGET_BIG_NAME "elf64-powerpc" #define ELF_ARCH bfd_arch_powerpc +#define ELF_TARGET_ID PPC64_ELF_DATA #define ELF_MACHINE_CODE EM_PPC64 #define ELF_MAXPAGESIZE 0x10000 #define ELF_COMMONPAGESIZE 0x1000 @@ -2651,7 +2652,7 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 32); + elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32); /* pr_reg */ offset = 112; @@ -4844,7 +4845,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, { struct ppc_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; @@ -4874,12 +4875,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", FALSE, FALSE, TRUE); symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = (sym_hashes - + symtab_hdr->sh_size / sizeof (Elf64_External_Sym) - - symtab_hdr->sh_info); - sreloc = NULL; opd_sym_map = NULL; if (strcmp (sec->name, ".opd") == 0) @@ -6694,6 +6690,7 @@ get_tls_mask (unsigned char **tls_maskp, if ((*tls_maskp != NULL && **tls_maskp != 0) || sec == NULL + || ppc64_elf_section_data (sec) == NULL || ppc64_elf_section_data (sec)->sec_type != sec_toc) return 1; @@ -6926,7 +6923,6 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) Elf_Internal_Rela *relstart, *rel, *relend; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Sym *local_syms; - struct elf_link_hash_entry **sym_hashes; bfd_vma offset; struct _opd_sec_data *opd; bfd_boolean need_edit, add_aux_fields; @@ -6951,7 +6947,6 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) local_syms = NULL; symtab_hdr = &elf_symtab_hdr (ibfd); - sym_hashes = elf_sym_hashes (ibfd); /* Read the relocations. */ relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, @@ -7078,6 +7073,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) if (need_edit || add_aux_fields) { Elf_Internal_Rela *write_rel; + Elf_Internal_Shdr *rel_hdr; bfd_byte *rptr, *wptr; bfd_byte *new_contents; bfd_boolean skip; @@ -7257,9 +7253,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) /* Fudge the header size too, as this is used later in elf_bfd_final_link if we are emitting relocs. */ - elf_section_data (sec)->rel_hdr.sh_size - = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize; - BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL); + rel_hdr = _bfd_elf_single_rel_hdr (sec); + rel_hdr->sh_size = sec->reloc_count * rel_hdr->sh_entsize; some_edited = TRUE; } else if (elf_section_data (sec)->relocs != relstart) @@ -7912,7 +7907,6 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) asection *toc, *sec; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Sym *local_syms; - struct elf_link_hash_entry **sym_hashes; Elf_Internal_Rela *relstart, *rel; unsigned long *skip, *drop; unsigned char *used; @@ -7930,7 +7924,6 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) local_syms = NULL; symtab_hdr = &elf_symtab_hdr (ibfd); - sym_hashes = elf_sym_hashes (ibfd); /* Look at sections dropped from the final link. */ skip = NULL; @@ -8047,13 +8040,21 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) r_symndx, ibfd)) goto error_ret; - if (!SYMBOL_REFERENCES_LOCAL (info, h)) + if (!SYMBOL_CALLS_LOCAL (info, h)) continue; if (h != NULL) - val = h->root.u.def.value; + { + if (h->type == STT_GNU_IFUNC) + continue; + val = h->root.u.def.value; + } else - val = sym->st_value; + { + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + continue; + val = sym->st_value; + } val += rel->r_addend; val += sym_sec->output_section->vma + sym_sec->output_offset; @@ -8248,6 +8249,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) { bfd_byte *contents, *src; unsigned long off; + Elf_Internal_Sym *sym; bfd_boolean local_toc_syms = FALSE; /* Shuffle the toc contents, and at the same time convert the @@ -8292,7 +8294,6 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) unsigned long r_symndx; asection *sym_sec; struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; bfd_vma val; r_type = ELF64_R_TYPE (rel->r_info); @@ -8371,38 +8372,34 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) /* We shouldn't have local or global symbols defined in the TOC, but handle them anyway. */ - if (local_toc_syms) - { - Elf_Internal_Sym *sym; - - for (sym = local_syms; - sym < local_syms + symtab_hdr->sh_info; - ++sym) - if (sym->st_value != 0 - && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc) - { - unsigned long i; - - if (sym->st_value > toc->rawsize) - i = toc->rawsize >> 3; - else - i = sym->st_value >> 3; + for (sym = local_syms; + sym < local_syms + symtab_hdr->sh_info; + ++sym) + if (sym->st_value != 0 + && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc) + { + unsigned long i; - if ((skip[i] & (ref_from_discarded | can_optimize)) != 0) - { - (*_bfd_error_handler) - (_("%s defined on removed toc entry"), - bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL)); - do - ++i; - while ((skip[i] & (ref_from_discarded | can_optimize))); - sym->st_value = (bfd_vma) i << 3; - } + if (sym->st_value > toc->rawsize) + i = toc->rawsize >> 3; + else + i = sym->st_value >> 3; - sym->st_value -= skip[i]; - symtab_hdr->contents = (unsigned char *) local_syms; + if ((skip[i] & (ref_from_discarded | can_optimize)) != 0) + { + if (local_toc_syms) + (*_bfd_error_handler) + (_("%s defined on removed toc entry"), + bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL)); + do + ++i; + while ((skip[i] & (ref_from_discarded | can_optimize))); + sym->st_value = (bfd_vma) i << 3; } - } + + sym->st_value -= skip[i]; + symtab_hdr->contents = (unsigned char *) local_syms; + } /* Adjust any global syms defined in this toc input section. */ if (toc_inf.global_toc_syms) @@ -8416,6 +8413,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (toc->reloc_count != 0) { + Elf_Internal_Shdr *rel_hdr; Elf_Internal_Rela *wrel; bfd_size_type sz; @@ -8441,9 +8439,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) 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); + rel_hdr = _bfd_elf_single_rel_hdr (toc); + sz = rel_hdr->sh_entsize; + rel_hdr->sh_size = toc->reloc_count * sz; } } @@ -9379,9 +9377,13 @@ get_relocs (asection *sec, int count) if (relocs == NULL) return NULL; elfsec_data->relocs = relocs; - elfsec_data->rel_hdr.sh_size = (sec->reloc_count - * sizeof (Elf64_External_Rela)); - elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela); + elfsec_data->rela.hdr = bfd_zalloc (sec->owner, + sizeof (Elf_Internal_Shdr)); + if (elfsec_data->rela.hdr == NULL) + return NULL; + elfsec_data->rela.hdr->sh_size = (sec->reloc_count + * sizeof (Elf64_External_Rela)); + elfsec_data->rela.hdr->sh_entsize = sizeof (Elf64_External_Rela); sec->reloc_count = 0; } relocs += sec->reloc_count; @@ -10675,7 +10677,8 @@ group_sections (struct ppc_link_hash_table *htab, curr = tail; total = tail->size; - big_sec = total > (ppc64_elf_section_data (tail)->has_14bit_branch + big_sec = total > (ppc64_elf_section_data (tail) != NULL + && ppc64_elf_section_data (tail)->has_14bit_branch ? stub14_group_size : stub_group_size); if (big_sec && !suppress_size_errors) (*_bfd_error_handler) (_("%B section %A exceeds stub group size"), @@ -10684,7 +10687,8 @@ group_sections (struct ppc_link_hash_table *htab, while ((prev = PREV_SEC (curr)) != NULL && ((total += curr->output_offset - prev->output_offset) - < (ppc64_elf_section_data (prev)->has_14bit_branch + < (ppc64_elf_section_data (prev) != NULL + && ppc64_elf_section_data (prev)->has_14bit_branch ? stub14_group_size : stub_group_size)) && htab->stub_group[prev->id].toc_off == curr_toc) curr = prev; @@ -10717,7 +10721,8 @@ group_sections (struct ppc_link_hash_table *htab, total = 0; while (prev != NULL && ((total += tail->output_offset - prev->output_offset) - < (ppc64_elf_section_data (prev)->has_14bit_branch + < (ppc64_elf_section_data (prev) != NULL + && ppc64_elf_section_data (prev)->has_14bit_branch ? stub14_group_size : stub_group_size)) && htab->stub_group[prev->id].toc_off == curr_toc) { @@ -11398,12 +11403,14 @@ ppc64_elf_action_discarded (asection *sec) /* REL points to a low-part reloc on a largetoc instruction sequence. Find the matching high-part reloc instruction and verify that it - is addis REG,r2,x. If so, return a pointer to the high-part reloc. */ + is addis REG,x,imm. If so, set *REG to x and return a pointer to + the high-part reloc. */ static const Elf_Internal_Rela * ha_reloc_match (const Elf_Internal_Rela *relocs, const Elf_Internal_Rela *rel, - unsigned int reg, + unsigned int *reg, + bfd_boolean match_addend, const bfd *input_bfd, const bfd_byte *contents) { @@ -11435,14 +11442,17 @@ ha_reloc_match (const Elf_Internal_Rela *relocs, while (--rel >= relocs) if (rel->r_info == r_info_ha - && rel->r_addend == r_addend) + && (!match_addend + || rel->r_addend == r_addend)) { const bfd_byte *p = contents + (rel->r_offset & ~3); unsigned int insn = bfd_get_32 (input_bfd, p); - if ((insn & ((0x3f << 26) | (0x1f << 16))) - == ((15u << 26) | (2 << 16)) /* addis rt,r2,x */ - && (insn & (0x1f << 21)) == (reg << 21)) - return rel; + if ((insn & (0x3f << 26)) == (15u << 26) /* addis rt,x,imm */ + && (insn & (0x1f << 21)) == (*reg << 21)) + { + *reg = (insn >> 16) & 0x1f; + return rel; + } break; } return NULL; @@ -11495,7 +11505,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, Elf_Internal_Rela outrel; bfd_byte *loc; struct got_entry **local_got_ents; + unsigned char *ha_opt; bfd_vma TOCstart; + bfd_boolean no_ha_opt; bfd_boolean ret = TRUE; bfd_boolean is_opd; /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ @@ -11521,6 +11533,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; + ha_opt = NULL; + no_ha_opt = FALSE; rel = relocs; relend = relocs + input_section->reloc_count; @@ -11659,7 +11673,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Check that tls relocs are used with tls syms, and non-tls relocs are used with non-tls syms. */ - if (r_symndx != 0 + if (r_symndx != STN_UNDEF && r_type != R_PPC64_NONE && (h == NULL || h->elf.root.type == bfd_link_hash_defined @@ -11908,9 +11922,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (local_sections[r_symndx] == sec) break; if (r_symndx >= symtab_hdr->sh_info) - r_symndx = 0; + r_symndx = STN_UNDEF; rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != 0) + if (r_symndx != STN_UNDEF) rel->r_addend -= (local_syms[r_symndx].st_value + sec->output_offset + sec->output_section->vma); @@ -12016,9 +12030,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (local_sections[r_symndx] == sec) break; if (r_symndx >= symtab_hdr->sh_info) - r_symndx = 0; + r_symndx = STN_UNDEF; rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != 0) + if (r_symndx != STN_UNDEF) rel->r_addend -= (local_syms[r_symndx].st_value + sec->output_offset + sec->output_section->vma); @@ -12372,7 +12386,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->elf) || (info->shared - && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) + && SYMBOL_CALLS_LOCAL (info, &h->elf))) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined locally, or the symbol was forced to be local @@ -12560,7 +12574,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOC: /* Relocation value is TOC base. */ relocation = TOCstart; - if (r_symndx == 0) + if (r_symndx == STN_UNDEF) relocation += htab->stub_group[input_section->id].toc_off; else if (unresolved_reloc) ; @@ -12749,7 +12763,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (skip) memset (&outrel, 0, sizeof outrel); - else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf) + else if (!SYMBOL_CALLS_LOCAL (info, &h->elf) && !is_opd && r_type != R_PPC64_TOC) outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type); @@ -12810,7 +12824,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, sym_name); ret = FALSE; } - else if (r_symndx == 0 || bfd_is_abs_section (sec)) + else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) ; else if (sec == NULL || sec->owner == NULL) { @@ -12946,7 +12960,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_GOT16_HA: case R_PPC64_TOC16_HA: - /* For now we don't nop out the first instruction. */ + /* nop is done later. */ break; case R_PPC64_GOT_TLSLD16_LO: @@ -12981,12 +12995,31 @@ ppc64_elf_relocate_section (bfd *output_bfd, && ((insn & 3) == 0 || (insn & 3) == 3))) { unsigned int reg = (insn >> 16) & 0x1f; - if (ha_reloc_match (relocs, rel, reg, input_bfd, contents)) + const Elf_Internal_Rela *ha; + bfd_boolean match_addend; + + match_addend = (sym != NULL + && ELF_ST_TYPE (sym->st_info) == STT_SECTION); + ha = ha_reloc_match (relocs, rel, ®, match_addend, + input_bfd, contents); + if (ha != NULL) { insn &= ~(0x1f << 16); - insn |= 2 << 16; + insn |= reg << 16; bfd_put_32 (input_bfd, insn, p); + if (ha_opt == NULL) + { + ha_opt = bfd_zmalloc (input_section->reloc_count); + if (ha_opt == NULL) + return FALSE; + } + ha_opt[ha - relocs] = 1; } + else + /* If we don't find a matching high part insn, + something is fishy. Refuse to nop any high + part insn in this section. */ + no_ha_opt = TRUE; } } break; @@ -13144,6 +13177,23 @@ ppc64_elf_relocate_section (bfd *output_bfd, } } + if (ha_opt != NULL) + { + if (!no_ha_opt) + { + unsigned char *opt = ha_opt; + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; opt++, rel++) + if (*opt != 0) + { + bfd_byte *p = contents + (rel->r_offset & ~3); + bfd_put_32 (input_bfd, NOP, p); + } + } + free (ha_opt); + } + /* If we're emitting relocations, then shortly after this function returns, reloc offsets and addends for this section will be adjusted. Worse, reloc symbol indices will be for the output @@ -13427,7 +13477,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, && htab->brlt->reloc_count != 0 && !_bfd_elf_link_output_relocs (output_bfd, htab->brlt, - &elf_section_data (htab->brlt)->rel_hdr, + elf_section_data (htab->brlt)->rela.hdr, elf_section_data (htab->brlt)->relocs, NULL)) return FALSE; @@ -13436,7 +13486,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, && htab->glink->reloc_count != 0 && !_bfd_elf_link_output_relocs (output_bfd, htab->glink, - &elf_section_data (htab->glink)->rel_hdr, + elf_section_data (htab->glink)->rela.hdr, elf_section_data (htab->glink)->relocs, NULL)) return FALSE;