X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=95ce1dc612f505efd04b8c43acef29f6bd535bd7;hb=bb95c51a232dffb46067c402ac62f1f3303b6bbd;hp=708076d65e8d74515d992c033d92d7cf6764610a;hpb=9b8b325a1f4cdaf235e7d803849dde6ededec865;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 708076d65e..95ce1dc612 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -1,5 +1,5 @@ /* PowerPC-specific support for 32-bit ELF - Copyright (C) 1994-2015 Free Software Foundation, Inc. + Copyright (C) 1994-2016 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -35,7 +35,6 @@ #include "elf32-ppc.h" #include "elf-vxworks.h" #include "dwarf2.h" -#include "elf-linux-psinfo.h" typedef enum split16_format_type { @@ -1731,6 +1730,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ + /* Like R_PPC_REL16_HA but for split field in addpcis. */ + HOWTO (R_PPC_REL16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc_elf_addr16_ha_reloc, /* special_function */ + "R_PPC_REL16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -1804,30 +1818,28 @@ struct elf_external_ppc_linux_prpsinfo32 char pr_psargs[80]; /* Initial part of arg list. */ }; -/* Helper macro to swap (properly handling endianess) things from the - `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32' - structure. - - Note that FROM should be a pointer, and TO should be the explicit type. */ - -#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \ - do \ - { \ - H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ - H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ - H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ - H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ - H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \ - H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \ - H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \ - H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ - H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ - H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ - H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \ - strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \ - strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \ - } while (0) +/* Helper function to copy an elf_internal_linux_prpsinfo in host + endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */ +static inline void +swap_ppc_linux_prpsinfo32_out (bfd *obfd, + const struct elf_internal_linux_prpsinfo *from, + struct elf_external_ppc_linux_prpsinfo32 *to) +{ + bfd_put_8 (obfd, from->pr_state, &to->pr_state); + bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); + bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); + bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); + bfd_put_32 (obfd, from->pr_flag, to->pr_flag); + bfd_put_32 (obfd, from->pr_uid, to->pr_uid); + bfd_put_32 (obfd, from->pr_gid, to->pr_gid); + bfd_put_32 (obfd, from->pr_pid, to->pr_pid); + bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); + bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); + bfd_put_32 (obfd, from->pr_sid, to->pr_sid); + strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); + strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); +} /* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ @@ -1989,6 +2001,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; + case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; } @@ -2058,7 +2071,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { - bfd_vma relocation; + enum elf_ppc_reloc_type r_type; + long insn; + bfd_size_type octets; + bfd_vma value; if (output_bfd != NULL) { @@ -2066,20 +2082,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, return bfd_reloc_ok; } - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - if (reloc_entry->howto->pc_relative) - relocation -= reloc_entry->address; - - reloc_entry->addend += (relocation & 0x8000) << 1; - - return bfd_reloc_continue; + reloc_entry->addend += 0x8000; + r_type = reloc_entry->howto->type; + if (r_type != R_PPC_REL16DX_HA) + return bfd_reloc_continue; + + value = 0; + if (!bfd_is_com_section (symbol->section)) + value = symbol->value; + value += (reloc_entry->addend + + symbol->section->output_offset + + symbol->section->output_section->vma); + value -= (reloc_entry->address + + input_section->output_offset + + input_section->output_section->vma); + value >>= 16; + + octets = reloc_entry->address * bfd_octets_per_byte (abfd); + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); + insn &= ~0x1fffc1; + insn |= (value & 0xffc1) | ((value & 0x3e) << 15); + bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); + return bfd_reloc_ok; } static bfd_reloc_status_type @@ -2172,13 +2196,93 @@ ppc_elf_mkobject (bfd *abfd) PPC32_ELF_DATA); } +/* When defaulting arch/mach, decode apuinfo to find a better match. */ + +bfd_boolean +_bfd_elf_ppc_set_arch (bfd *abfd) +{ + unsigned long mach = 0; + asection *s; + unsigned char *contents; + + if (abfd->arch_info->bits_per_word == 32 + && bfd_big_endian (abfd)) + { + + for (s = abfd->sections; s != NULL; s = s->next) + if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0) + break; + if (s != NULL) + mach = bfd_mach_ppc_vle; + } + + if (mach == 0) + { + s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents)) + { + unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4); + unsigned int i; + + for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4) + { + unsigned int val = bfd_get_32 (abfd, contents + i); + switch (val >> 16) + { + case PPC_APUINFO_PMR: + case PPC_APUINFO_RFMCI: + if (mach == 0) + mach = bfd_mach_ppc_titan; + break; + + case PPC_APUINFO_ISEL: + case PPC_APUINFO_CACHELCK: + if (mach == bfd_mach_ppc_titan) + mach = bfd_mach_ppc_e500mc; + break; + + case PPC_APUINFO_SPE: + case PPC_APUINFO_EFS: + case PPC_APUINFO_BRLOCK: + if (mach != bfd_mach_ppc_vle) + mach = bfd_mach_ppc_e500; + + case PPC_APUINFO_VLE: + mach = bfd_mach_ppc_vle; + break; + + default: + mach = -1ul; + } + } + free (contents); + } + } + + if (mach != 0 && mach != -1ul) + { + const bfd_arch_info_type *arch; + + for (arch = abfd->arch_info->next; arch; arch = arch->next) + if (arch->mach == mach) + { + abfd->arch_info = arch; + break; + } + } + return TRUE; +} + /* Fix bad default arch selected for a 32 bit input bfd when the - default is 64 bit. */ + default is 64 bit. Also select arch based on apuinfo. */ static bfd_boolean ppc_elf_object_p (bfd *abfd) { - if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) + if (!abfd->arch_info->the_default) + return TRUE; + + if (abfd->arch_info->bits_per_word == 64) { Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); @@ -2189,7 +2293,7 @@ ppc_elf_object_p (bfd *abfd) BFD_ASSERT (abfd->arch_info->bits_per_word == 32); } } - return TRUE; + return _bfd_elf_ppc_set_arch (abfd); } /* Function to set whether a module needs the -mrelocatable bit set. */ @@ -2270,14 +2374,15 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) } char * -elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz, - const struct elf_internal_linux_prpsinfo *prpsinfo) +elfcore_write_ppc_linux_prpsinfo32 + (bfd *abfd, + char *buf, + int *bufsiz, + const struct elf_internal_linux_prpsinfo *prpsinfo) { struct elf_external_ppc_linux_prpsinfo32 data; - memset (&data, 0, sizeof (data)); - PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data); - + swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data); return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO, &data, sizeof (data)); } @@ -2494,16 +2599,16 @@ ppc_elf_modify_segment_map (bfd *abfd, static const struct bfd_elf_special_section ppc_elf_special_sections[] = { - { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, - { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 }, - { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, + { STRING_COMMA_LEN (APUINFO_SECTION_NAME), 0, SHT_NOTE, 0 }, + { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } }; /* This is what we want for new plt/got. */ @@ -2612,9 +2717,6 @@ apuinfo_list_finish (void) head = NULL; } -#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" -#define APUINFO_LABEL "APUinfo" - /* Scan the input BFDs and create a linked list of the APUinfo values that will need to be emitted. */ @@ -3649,11 +3751,10 @@ ppc_elf_add_symbol_hook (bfd *abfd, *valp = sym->st_size; } - if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC && (abfd->flags & DYNAMIC) == 0 && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any; + elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; return TRUE; } @@ -3921,6 +4022,7 @@ ppc_elf_check_relocs (bfd *abfd, enum elf_ppc_reloc_type r_type; struct elf_link_hash_entry *h; int tls_type; + struct plt_entry **ifunc; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -3953,6 +4055,7 @@ ppc_elf_check_relocs (bfd *abfd, tls_type = 0; r_type = ELF32_R_TYPE (rel->r_info); + ifunc = NULL; if (h == NULL && !htab->is_vxworks) { Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, @@ -3962,8 +4065,6 @@ ppc_elf_check_relocs (bfd *abfd, if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { - struct plt_entry **ifunc; - /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, PLT_IFUNC); @@ -4197,21 +4298,20 @@ ppc_elf_check_relocs (bfd *abfd, #ifdef DEBUG fprintf (stderr, "Reloc requires a PLT entry\n"); #endif - /* This symbol requires a procedure linkage table entry. We - actually build the entry in finish_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - + /* This symbol requires a procedure linkage table entry. */ if (h == NULL) { - /* It does not make sense to have a procedure linkage - table entry for a local symbol. */ - info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"), - abfd, sec, rel->r_offset, - ppc_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; + if (ifunc == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a non-ifunc local symbol. */ + info->callbacks->einfo + (_("%P: %H: %s reloc against local symbol\n"), + abfd, sec, rel->r_offset, + ppc_elf_howto_table[r_type]->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } else { @@ -4247,6 +4347,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_REL16_LO: case R_PPC_REL16_HI: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: ppc_elf_tdata (abfd)->has_rel16 = 1; break; @@ -4288,9 +4389,10 @@ ppc_elf_check_relocs (bfd *abfd, { if (bfd_link_pic (info)) { - info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"), - abfd, sec, rel->r_offset, - h->root.root.string); + info->callbacks->einfo + (_("%P: %H: @local call to ifunc %s\n"), + abfd, sec, rel->r_offset, + h->root.root.string); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -5138,6 +5240,7 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) tga->root.type = bfd_link_hash_indirect; tga->root.u.i.link = &opt->root; ppc_elf_copy_indirect_symbol (info, opt, tga); + opt->forced_local = 0; if (opt->dynindx != -1) { /* Use __tls_get_addr_opt in dynamic relocations. */ @@ -7604,7 +7707,9 @@ is_insn_ds_form (unsigned int insn) static bfd_boolean is_insn_dq_form (unsigned int insn) { - return (insn & (0x3f << 26)) == 56u << 26; /* lq */ + return ((insn & (0x3f << 26)) == 56u << 26 /* lq */ + || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */ + && (insn & 3) == 1)); } /* The RELOCATE_SECTION function is called by the ELF backend linker @@ -7650,6 +7755,7 @@ ppc_elf_relocate_section (bfd *output_bfd, struct elf_link_hash_entry **sym_hashes; struct ppc_elf_link_hash_table *htab; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; asection *got2; @@ -7685,9 +7791,9 @@ ppc_elf_relocate_section (bfd *output_bfd, ".tls_vars")); if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) relax_info = elf_section_data (input_section)->sec_info; - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc_reloc_type r_type; bfd_vma addend; @@ -7706,6 +7812,7 @@ ppc_elf_relocate_section (bfd *output_bfd, struct plt_entry **ifunc; struct reloc_howto_struct alt_howto; + again: r_type = ELF32_R_TYPE (rel->r_info); sym = NULL; sec = NULL; @@ -7742,8 +7849,22 @@ ppc_elf_relocate_section (bfd *output_bfd, howto = NULL; if (r_type < R_PPC_max) howto = ppc_elf_howto_table[r_type]; - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); + + _bfd_clear_contents (howto, input_bfd, input_section, + contents + rel->r_offset); + wrel->r_offset = rel->r_offset; + wrel->r_info = 0; + wrel->r_addend = 0; + + /* For ld -r, remove relocations in debug sections against + sections defined in discarded sections. Not done for + non-debug to preserve relocs in .eh_frame which the + eh_frame editing code expects to be present. */ + if (bfd_link_relocatable (info) + && (input_section->flags & SEC_DEBUGGING)) + wrel--; + + continue; } if (bfd_link_relocatable (info)) @@ -7759,7 +7880,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type != R_PPC_RELAX_PLT && r_type != R_PPC_RELAX_PLTREL24 && r_type != R_PPC_RELAX) - continue; + goto copy_reloc; } /* TLS optimizations. Replace instruction sequences and relocs @@ -7802,10 +7923,12 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_vma insn; - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c020000; /* addis 0,2,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset - d_offset); r_type = R_PPC_TPREL16_HA; rel->r_info = ELF32_R_INFO (r_symndx, r_type); } @@ -7941,8 +8064,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol on an LD reloc. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -8000,8 +8122,7 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - rel--; - continue; + goto again; } break; } @@ -8080,9 +8201,9 @@ ppc_elf_relocate_section (bfd *output_bfd, got_addr = (htab->got->output_section->vma + htab->got->output_offset + (h->got.offset & ~1)); - rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); - rel->r_addend = got_addr; - rel->r_offset = (p - contents) + d_offset; + wrel->r_offset = (p - contents) + d_offset; + wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); + wrel->r_addend = got_addr; insn &= ~0xffff; insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff; bfd_put_32 (output_bfd, insn, p); @@ -8100,9 +8221,10 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Use one of the spare relocs, so --emit-relocs output is reasonable. */ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - rel++; + wrel++, rel++; + rel->r_offset = wrel[-1].r_offset + 4; rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); - rel->r_offset += 4; + rel->r_addend = wrel[-1].r_addend; /* Continue on as if we had a got reloc, to output dynamic reloc. */ @@ -8236,7 +8358,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC_NONE: case R_PPC_TLS: @@ -8245,7 +8367,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_EMB_MRKREF: case R_PPC_GNU_VTINHERIT: case R_PPC_GNU_VTENTRY: - continue; + goto copy_reloc; /* GOT16 relocations. Like an ADDR16 using the symbol's address in the GOT as relocation value instead of the @@ -8496,7 +8618,7 @@ ppc_elf_relocate_section (bfd *output_bfd, /* If here for a picfixup, we're done. */ if (r_type != ELF32_R_TYPE (rel->r_info)) - continue; + goto copy_reloc; relocation = (htab->got->output_section->vma + htab->got->output_offset @@ -8522,14 +8644,13 @@ ppc_elf_relocate_section (bfd *output_bfd, at a symbol not in this object. */ if (unresolved_reloc) { - if (! (*info->callbacks->undefined_symbol) (info, - h->root.root.string, - input_bfd, - input_section, - rel->r_offset, - TRUE)) - return FALSE; - continue; + (*info->callbacks->undefined_symbol) (info, + h->root.root.string, + input_bfd, + input_section, + rel->r_offset, + TRUE); + goto copy_reloc; } break; @@ -8588,6 +8709,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_REL16_LO: case R_PPC_REL16_HI: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: break; case R_PPC_REL32: @@ -8768,7 +8890,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); if (skip == -1) - continue; + goto copy_reloc; /* This reloc will be computed at runtime. We clear the memory so that it contains predictable value. */ @@ -8861,12 +8983,13 @@ ppc_elf_relocate_section (bfd *output_bfd, relocs to describe this relocation. */ BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); /* The relocs are at the bottom 2 bytes */ - rel[0].r_offset += d_offset; - memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - rel[1].r_offset += 4; - rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - rel++; + wrel->r_offset = rel->r_offset + d_offset; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); + wrel->r_addend = rel->r_addend; + memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel)); + wrel++, rel++; + wrel->r_offset += 4; + wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); } continue; @@ -8919,8 +9042,10 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_PLTREL24: if (h != NULL && ifunc == NULL) { - struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, - bfd_link_pic (info) ? addend : 0); + struct plt_entry *ent; + + ent = find_plt_ent (&h->plt.plist, got2, + bfd_link_pic (info) ? addend : 0); if (ent == NULL || htab->plt == NULL) { @@ -9014,37 +9139,37 @@ ppc_elf_relocate_section (bfd *output_bfd, relocation = relocation + addend; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_LO16D: relocation = relocation + addend; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; case R_PPC_VLE_HI16A: relocation = (relocation + addend) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_HI16D: relocation = (relocation + addend) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; case R_PPC_VLE_HA16A: relocation = (relocation + addend + 0x8000) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16a_type); - continue; + goto copy_reloc; case R_PPC_VLE_HA16D: relocation = (relocation + addend + 0x8000) >> 16; ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset, relocation, split16d_type); - continue; + goto copy_reloc; /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ case R_PPC_EMB_SDA21: @@ -9093,7 +9218,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } if (sda != NULL) @@ -9131,7 +9256,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type == R_PPC_VLE_SDA21 && ((relocation + 0x80000) & 0xffffffff) > 0x100000) goto overflow; - continue; + goto copy_reloc; } else if (r_type == R_PPC_EMB_SDA21 || r_type == R_PPC_VLE_SDA21 @@ -9187,7 +9312,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } if (sda != NULL) @@ -9234,7 +9359,7 @@ ppc_elf_relocate_section (bfd *output_bfd, value, split16d_type); } } - continue; + goto copy_reloc; /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: @@ -9282,7 +9407,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Do any further special processing. */ @@ -9293,6 +9418,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_ADDR16_HA: case R_PPC_REL16_HA: + case R_PPC_REL16DX_HA: case R_PPC_SECTOFF_HA: case R_PPC_TPREL16_HA: case R_PPC_DTPREL16_HA: @@ -9342,7 +9468,8 @@ ppc_elf_relocate_section (bfd *output_bfd, that make up part of the insn opcode. */ unsigned int insn, mask, lobit; - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); mask = 0; if (is_insn_ds_form (insn)) mask = 3; @@ -9350,10 +9477,12 @@ ppc_elf_relocate_section (bfd *output_bfd, mask = 15; else break; - lobit = mask & (relocation + addend); + relocation += addend; + addend = insn & mask; + lobit = mask & relocation; if (lobit != 0) { - addend -= lobit; + relocation ^= lobit; info->callbacks->einfo (_("%P: %H: error: %s against `%s' not a multiple of %u\n"), input_bfd, input_section, rel->r_offset, @@ -9361,7 +9490,6 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; } - addend += insn & mask; } break; } @@ -9420,8 +9548,30 @@ ppc_elf_relocate_section (bfd *output_bfd, } } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, addend); + if (r_type == R_PPC_REL16DX_HA) + { + /* Split field reloc isn't handled by _bfd_final_link_relocate. */ + if (rel->r_offset + 4 > input_section->size) + r = bfd_reloc_outofrange; + else + { + unsigned int insn; + + relocation += addend; + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + relocation >>= 16; + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn &= ~0x1fffc1; + insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + r = bfd_reloc_ok; + } + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, addend); if (r != bfd_reloc_ok) { @@ -9435,13 +9585,9 @@ ppc_elf_relocate_section (bfd *output_bfd, && (h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_undefined) && is_branch_reloc (r_type))) - { - if (!((*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), sym_name, - howto->name, rel->r_addend, - input_bfd, input_section, rel->r_offset))) - return FALSE; - } + info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), sym_name, howto->name, + rel->r_addend, input_bfd, input_section, rel->r_offset); } else { @@ -9452,6 +9598,31 @@ ppc_elf_relocate_section (bfd *output_bfd, ret = FALSE; } } + copy_reloc: + if (wrel != rel) + *wrel = *rel; + } + + if (wrel != rel) + { + Elf_Internal_Shdr *rel_hdr; + size_t deleted = rel - wrel; + + rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + if (rel_hdr->sh_size == 0) + { + /* It is too late to remove an empty reloc section. Leave + one NONE reloc. + ??? What is wrong with an empty section??? */ + rel_hdr->sh_size = rel_hdr->sh_entsize; + deleted -= 1; + wrel++; + } + relend = wrel; + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } #ifdef DEBUG