X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=95ce1dc612f505efd04b8c43acef29f6bd535bd7;hb=bb95c51a232dffb46067c402ac62f1f3303b6bbd;hp=6fb603d3aeadd7d0c87606bb870a3c7944c58fb4;hpb=6128f9cf2b2c4188145faba45596ce49dd0f08be;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 6fb603d3ae..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-2014 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 { @@ -187,8 +186,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = { /* This reloc does nothing. */ HOWTO (R_PPC_NONE, /* type */ 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ @@ -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; } @@ -2019,19 +2032,28 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, Elf_Internal_Rela *dst) { + unsigned int r_type; + /* Initialize howto table if not already done. */ if (!ppc_elf_howto_table[R_PPC_ADDR32]) ppc_elf_howto_init (); - BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); - cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; + r_type = ELF32_R_TYPE (dst->r_info); + if (r_type >= R_PPC_max) + { + (*_bfd_error_handler) (_("%B: unrecognised PPC reloc number: %d"), + abfd, r_type); + bfd_set_error (bfd_error_bad_value); + r_type = R_PPC_NONE; + } + cache_ptr->howto = ppc_elf_howto_table[r_type]; /* Just because the above assert didn't trigger doesn't mean that ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */ if (!cache_ptr->howto) { (*_bfd_error_handler) (_("%B: invalid relocation type %d"), - abfd, ELF32_R_TYPE (dst->r_info)); + abfd, r_type); bfd_set_error (bfd_error_bad_value); cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; @@ -2049,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) { @@ -2057,23 +2082,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, return bfd_reloc_ok; } - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - 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 @@ -2166,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); @@ -2183,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. */ @@ -2264,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)); } @@ -2488,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. */ @@ -2606,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. */ @@ -2919,7 +3027,6 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, } count = relplt->size / sizeof (Elf32_External_Rela); - stub_vma = glink_vma - (bfd_vma) count * 16; /* If the stubs are those for -shared/-pie then we might have multiple stubs for each plt entry. If that is the case then there is no way to associate stubs with their plt entries short @@ -2950,9 +3057,10 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, if (s == NULL) return -1; + stub_vma = glink_vma; names = (char *) (s + count + 1 + (resolv_vma != 0)); - p = relplt->relocation; - for (i = 0; i < count; i++, p++) + p = relplt->relocation + count - 1; + for (i = 0; i < count; i++) { size_t len; @@ -2963,6 +3071,9 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, s->flags |= BSF_GLOBAL; s->flags |= BSF_SYNTHETIC; s->section = glink; + stub_vma -= 16; + if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0) + stub_vma -= 32; s->value = stub_vma - glink->vma; s->name = names; s->udata.p = NULL; @@ -2979,7 +3090,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, memcpy (names, "@plt", sizeof ("@plt")); names += sizeof ("@plt"); ++s; - stub_vma += 16; + --p; } /* Add a symbol at the start of the glink branch table. */ @@ -3071,7 +3182,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - return !info->executable; + return !bfd_link_executable (info); } } @@ -3126,7 +3237,11 @@ struct ppc_elf_link_hash_entry /* Nonzero if we have seen a small data relocation referring to this symbol. */ - unsigned char has_sda_refs; + unsigned char has_sda_refs : 1; + + /* Flag use of given relocations. */ + unsigned char has_addr16_ha : 1; + unsigned char has_addr16_lo : 1; }; #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) @@ -3250,7 +3365,7 @@ static struct bfd_link_hash_table * ppc_elf_link_hash_table_create (bfd *abfd) { struct ppc_elf_link_hash_table *ret; - static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 }; + static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12, 0 }; ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); if (ret == NULL) @@ -3452,7 +3567,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (s == NULL) return FALSE; - if (! info->shared) + if (! bfd_link_pic (info)) { htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS @@ -3609,7 +3724,7 @@ ppc_elf_add_symbol_hook (bfd *abfd, bfd_vma *valp) { if (sym->st_shndx == SHN_COMMON - && !info->relocatable + && !bfd_link_relocatable (info) && is_ppc_elf (info->output_bfd) && sym->st_size <= elf_gp_size (abfd)) { @@ -3636,10 +3751,10 @@ ppc_elf_add_symbol_hook (bfd *abfd, *valp = sym->st_size; } - if ((abfd->flags & DYNAMIC) == 0 - && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)) - elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + 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_ifunc; return TRUE; } @@ -3862,7 +3977,7 @@ ppc_elf_check_relocs (bfd *abfd, asection *got2, *sreloc; struct elf_link_hash_entry *tga; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; /* Don't do anything special with non-loaded, non-alloced sections. @@ -3907,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) @@ -3939,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, @@ -3948,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); @@ -3959,14 +4074,14 @@ ppc_elf_check_relocs (bfd *abfd, /* STT_GNU_IFUNC symbols must have a PLT entry; In a non-pie executable even when there are no plt calls. */ - if (!info->shared + if (!bfd_link_pic (info) || is_branch_reloc (r_type)) { bfd_vma addend = 0; if (r_type == R_PPC_PLTREL24) { ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) + if (bfd_link_pic (info)) addend = rel->r_addend; } if (!update_plt_info (abfd, ifunc, got2, addend)) @@ -4017,7 +4132,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_GOT_TPREL16_LO: case R_PPC_GOT_TPREL16_HI: case R_PPC_GOT_TPREL16_HA: - if (info->shared) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -4056,7 +4171,7 @@ ppc_elf_check_relocs (bfd *abfd, /* We may also need a plt entry if the symbol turns out to be an ifunc. */ - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) return FALSE; @@ -4065,7 +4180,7 @@ ppc_elf_check_relocs (bfd *abfd, /* Indirect .sdata relocation. */ case R_PPC_EMB_SDAI16: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -4083,7 +4198,7 @@ ppc_elf_check_relocs (bfd *abfd, /* Indirect .sdata2 relocation. */ case R_PPC_EMB_SDA2I16: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -4128,7 +4243,7 @@ ppc_elf_check_relocs (bfd *abfd, break; case R_PPC_EMB_SDA2REL: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -4145,7 +4260,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_VLE_SDA21: case R_PPC_EMB_SDA21: case R_PPC_EMB_RELSDA: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -4162,7 +4277,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_EMB_NADDR16_LO: case R_PPC_EMB_NADDR16_HI: case R_PPC_EMB_NADDR16_HA: - if (info->shared) + if (bfd_link_pic (info)) { bad_shared_reloc (abfd, r_type); return FALSE; @@ -4183,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 { @@ -4206,7 +4320,7 @@ ppc_elf_check_relocs (bfd *abfd, if (r_type == R_PPC_PLTREL24) { ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) + if (bfd_link_pic (info)) addend = rel->r_addend; } h->needs_plt = 1; @@ -4233,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; @@ -4272,11 +4387,12 @@ ppc_elf_check_relocs (bfd *abfd, } if (h != NULL && h->type == STT_GNU_IFUNC) { - if (info->shared) + 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; } @@ -4308,7 +4424,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - if (info->shared) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -4321,7 +4437,7 @@ ppc_elf_check_relocs (bfd *abfd, if (h == NULL && got2 != NULL && (sec->flags & SEC_CODE) != 0 - && info->shared + && bfd_link_pic (info) && htab->plt_type == PLT_UNSET) { /* Old -fPIC gcc code has .long LCTOC1-LCFx just before @@ -4356,7 +4472,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_ADDR16_HA: case R_PPC_UADDR32: case R_PPC_UADDR16: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { /* We may need a plt entry if the symbol turns out to be a function defined in a dynamic object. */ @@ -4366,6 +4482,10 @@ ppc_elf_check_relocs (bfd *abfd, /* We may need a copy reloc too. */ h->non_got_ref = 1; h->pointer_equality_needed = 1; + if (r_type == R_PPC_ADDR16_HA) + ppc_elf_hash_entry (h)->has_addr16_ha = 1; + if (r_type == R_PPC_ADDR16_LO) + ppc_elf_hash_entry (h)->has_addr16_lo = 1; } goto dodyn; @@ -4390,7 +4510,7 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { /* We may need a plt entry if the symbol turns out to be a function defined in a dynamic object. */ @@ -4422,14 +4542,14 @@ ppc_elf_check_relocs (bfd *abfd, may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the symbol. */ - if ((info->shared + if ((bfd_link_pic (info) && (must_be_dyn_reloc (info, r_type) || (h != NULL && (!SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) @@ -4800,7 +4920,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->params->plt_style == PLT_OLD) htab->plt_type = PLT_OLD; - else if (info->shared + else if (bfd_link_pic (info) && htab->elf.dynamic_sections_created && (h = elf_link_hash_lookup (&htab->elf, "_mcount", FALSE, FALSE, TRUE)) != NULL @@ -4916,7 +5036,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, const Elf_Internal_Rela *rel, *relend; asection *got2; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; if ((sec->flags & SEC_ALLOC) == 0) @@ -4962,7 +5082,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, if (!htab->is_vxworks && h == NULL && local_got_refcounts != NULL - && (!info->shared + && (!bfd_link_pic (info) || is_branch_reloc (r_type))) { struct plt_entry **local_plt = (struct plt_entry **) @@ -4975,7 +5095,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (ifunc, got2, addend); if (ent->plt.refcount > 0) @@ -5010,7 +5130,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, { if (h->got.refcount > 0) h->got.refcount--; - if (!info->shared) + if (!bfd_link_pic (info)) { struct plt_entry *ent; @@ -5046,7 +5166,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, case R_PPC_ADDR14_BRNTAKEN: case R_PPC_UADDR32: case R_PPC_UADDR16: - if (info->shared) + if (bfd_link_pic (info)) break; case R_PPC_PLT32: @@ -5060,7 +5180,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (&h->plt.plist, got2, addend); if (ent != NULL && ent->plt.refcount > 0) @@ -5086,6 +5206,9 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) htab = ppc_elf_hash_table (info); htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE); + if (htab->plt_type != PLT_NEW) + htab->params->no_tls_get_addr_opt = TRUE; + if (!htab->params->no_tls_get_addr_opt) { struct elf_link_hash_entry *opt, *tga; @@ -5117,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. */ @@ -5183,7 +5307,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct ppc_elf_link_hash_table *htab; int pass; - if (info->relocatable || !info->executable) + if (!bfd_link_executable (info)) return TRUE; htab = ppc_elf_hash_table (info); @@ -5356,7 +5480,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct plt_entry *ent; bfd_vma addend = 0; - if (info->shared + if (bfd_link_pic (info) && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) addend = rel[1].r_addend; ent = find_plt_ent (&htab->tls_get_addr->plt.plist, @@ -5541,6 +5665,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, && !readonly_dynrelocs (h)) h->non_got_ref = 0; } + h->protected_def = 0; return TRUE; } else @@ -5567,13 +5692,42 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) - return TRUE; + if (bfd_link_pic (info)) + { + h->protected_def = 0; + return TRUE; + } /* If there are no references to this symbol that do not use the GOT, we don't need to generate a copy reloc. */ if (!h->non_got_ref) - return TRUE; + { + h->protected_def = 0; + return TRUE; + } + + /* Protected variables do not work with .dynbss. The copy in + .dynbss won't be used by the shared library with the protected + definition for the variable. Editing to PIC, or text relocations + are preferable to an incorrect program. */ + if (h->protected_def) + { + if (ELIMINATE_COPY_RELOCS + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup == 0 + && info->disable_target_specific_optimizations <= 1) + htab->params->pic_fixup = 1; + h->non_got_ref = 0; + return TRUE; + } + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } /* If we didn't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. @@ -5627,7 +5781,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Generate a symbol to mark plt call stubs. For non-PIC code the sym is @@ -5647,7 +5801,7 @@ add_stub_sym (struct plt_entry *ent, const char *stub; struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - if (info->shared) + if (bfd_link_pic (info)) stub = ".plt_pic32."; else stub = ".plt_call32."; @@ -5678,6 +5832,7 @@ add_stub_sym (struct plt_entry *ent, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } return TRUE; } @@ -5755,7 +5910,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } dyn = htab->elf.dynamic_sections_created; - if (info->shared + if (bfd_link_pic (info) || h->type == STT_GNU_IFUNC || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) { @@ -5773,7 +5928,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) ent->plt.offset = plt_offset; s = htab->glink; - if (!doneone || info->shared) + if (!doneone || bfd_link_pic (info)) { glink_offset = s->size; s->size += GLINK_ENTRY_SIZE; @@ -5782,7 +5937,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; } if (!doneone - && !info->shared + && !bfd_link_pic (info) && h->def_dynamic && !h->def_regular) { @@ -5821,7 +5976,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) relocations, and is required to make function pointers compare as equal between the normal executable and the shared library. */ - if (! info->shared + if (! bfd_link_pic (info) && h->def_dynamic && !h->def_regular) { @@ -5855,7 +6010,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab->plt_type == PLT_VXWORKS) { /* Allocate space for the unloaded relocations. */ - if (!info->shared + if (!bfd_link_pic (info) && htab->elf.dynamic_sections_created) { if (ent->plt.offset @@ -5898,7 +6053,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } eh = (struct ppc_elf_link_hash_entry *) h; - if (eh->elf.got.refcount > 0) + if (eh->elf.got.refcount > 0 + || (ELIMINATE_COPY_RELOCS + && !eh->elf.def_regular + && eh->elf.protected_def + && eh->has_addr16_ha + && eh->has_addr16_lo + && htab->params->pic_fixup > 0)) { bfd_boolean dyn; unsigned int need; @@ -5941,7 +6102,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { eh->elf.got.offset = allocate_got (htab, need); dyn = htab->elf.dynamic_sections_created; - if ((info->shared + if ((bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf)) && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT || eh->elf.root.type != bfd_link_hash_undefweak)) @@ -5972,7 +6133,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) space for relocs that have become local due to symbol visibility changes. */ - if (info->shared) + if (bfd_link_pic (info)) { /* Relocs that use pc_count are those that appear on a call insn, or certain REL relocs (see must_be_dyn_reloc) that can be @@ -6041,7 +6202,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) dynamic. */ if (!h->non_got_ref - && !h->def_regular) + && !h->def_regular + && !(h->protected_def + && eh->has_addr16_ha + && eh->has_addr16_lo + && htab->params->pic_fixup > 0)) { /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -6129,7 +6294,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); BFD_ASSERT (s != NULL); @@ -6229,7 +6394,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, else { *local_got = allocate_got (htab, need); - if (info->shared) + if (bfd_link_pic (info)) { asection *srel = htab->relgot; if ((*lgot_masks & PLT_IFUNC) != 0) @@ -6264,7 +6429,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, ent->plt.offset = plt_offset; s = htab->glink; - if (!doneone || info->shared) + if (!doneone || bfd_link_pic (info)) { glink_offset = s->size; s->size += GLINK_ENTRY_SIZE; @@ -6288,7 +6453,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, if (htab->tlsld_got.refcount > 0) { htab->tlsld_got.offset = allocate_got (htab, 8); - if (info->shared) + if (bfd_link_pic (info)) htab->relgot->size += sizeof (Elf32_External_Rela); } else @@ -6312,7 +6477,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, htab->elf.hgot->root.u.def.value = g_o_t; } - if (info->shared) + if (bfd_link_pic (info)) { struct elf_link_hash_entry *sda = htab->sdata[0].sym; @@ -6359,6 +6524,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", TRUE, FALSE, FALSE); @@ -6374,6 +6540,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, sh->ref_regular_nonweak = 1; sh->forced_local = 1; sh->non_elf = 0; + sh->root.linker_def = 1; } } } @@ -6386,7 +6553,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, { s = htab->glink_eh_frame; s->size = sizeof (glink_eh_frame_cie) + 20; - if (info->shared) + if (bfd_link_pic (info)) { s->size += 4; if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256) @@ -6483,7 +6650,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (info->executable) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -6562,7 +6729,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd, /* Augmentation. */ p += 1; - if (info->shared + if (bfd_link_pic (info) && htab->elf.dynamic_sections_created) { bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; @@ -6680,6 +6847,7 @@ static const int stub_entry[] = struct ppc_elf_relax_info { unsigned int workaround_size; + unsigned int picfixup_size; }; /* This function implements long branch trampolines, and the ppc476 @@ -6693,9 +6861,9 @@ ppc_elf_relax_section (bfd *abfd, struct bfd_link_info *link_info, bfd_boolean *again) { - struct one_fixup + struct one_branch_fixup { - struct one_fixup *next; + struct one_branch_fixup *next; asection *tsec; /* Final link, can use the symbol offset. For a relocatable link we use the symbol's index. */ @@ -6708,12 +6876,12 @@ ppc_elf_relax_section (bfd *abfd, Elf_Internal_Sym *isymbuf = NULL; Elf_Internal_Rela *internal_relocs = NULL; Elf_Internal_Rela *irel, *irelend = NULL; - struct one_fixup *fixups = NULL; + struct one_branch_fixup *branch_fixups = NULL; struct ppc_elf_relax_info *relax_info = NULL; unsigned changes = 0; bfd_boolean workaround_change; struct ppc_elf_link_hash_table *htab; - bfd_size_type trampbase, trampoff, newsize; + bfd_size_type trampbase, trampoff, newsize, picfixup_size; asection *got2; bfd_boolean maybe_pasted; @@ -6729,7 +6897,7 @@ ppc_elf_relax_section (bfd *abfd, /* We cannot represent the required PIC relocs in the output, so don't do anything. The linker doesn't support mixing -shared and -r anyway. */ - if (link_info->relocatable && link_info->shared) + if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info)) return TRUE; htab = ppc_elf_hash_table (link_info); @@ -6745,7 +6913,8 @@ ppc_elf_relax_section (bfd *abfd, || isec->sec_info_type == SEC_INFO_TYPE_TARGET); isec->sec_info_type = SEC_INFO_TYPE_TARGET; - if (htab->params->ppc476_workaround) + if (htab->params->ppc476_workaround + || htab->params->pic_fixup > 0) { if (elf_section_data (isec)->sec_info == NULL) { @@ -6766,8 +6935,9 @@ ppc_elf_relax_section (bfd *abfd, trampoff += 4; symtab_hdr = &elf_symtab_hdr (abfd); - - if (htab->params->branch_trampolines) + picfixup_size = 0; + if (htab->params->branch_trampolines + || htab->params->pic_fixup > 0) { /* Get a copy of the native relocations. */ if (isec->reloc_count != 0) @@ -6786,9 +6956,9 @@ ppc_elf_relax_section (bfd *abfd, unsigned long r_type = ELF32_R_TYPE (irel->r_info); bfd_vma toff, roff; asection *tsec; - struct one_fixup *f; + struct one_branch_fixup *f; size_t insn_offset = 0; - bfd_vma max_branch_offset, val; + bfd_vma max_branch_offset = 0, val; bfd_byte *hit_addr; unsigned long t0; struct elf_link_hash_entry *h; @@ -6809,6 +6979,11 @@ ppc_elf_relax_section (bfd *abfd, max_branch_offset = 1 << 15; break; + case R_PPC_ADDR16_HA: + if (htab->params->pic_fixup > 0) + break; + continue; + default: continue; } @@ -6866,7 +7041,7 @@ ppc_elf_relax_section (bfd *abfd, || h->root.type == bfd_link_hash_undefweak) { tsec = bfd_und_section_ptr; - toff = link_info->relocatable ? indx : 0; + toff = bfd_link_relocatable (link_info) ? indx : 0; } else continue; @@ -6874,8 +7049,7 @@ ppc_elf_relax_section (bfd *abfd, /* If this branch is to __tls_get_addr then we may later optimise away the call. We won't be needing a long- branch stub in that case. */ - if (link_info->executable - && !link_info->relocatable + if (bfd_link_executable (link_info) && h == htab->tls_get_addr && irel != internal_relocs) { @@ -6930,6 +7104,17 @@ ppc_elf_relax_section (bfd *abfd, sym_type = h->type; } + if (r_type == R_PPC_ADDR16_HA) + { + if (h != NULL + && !h->def_regular + && h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo) + picfixup_size += 12; + continue; + } + /* The condition here under which we call find_plt_ent must match that in relocate_section. If we call find_plt_ent here but not in relocate_section, or vice versa, then the branch @@ -6955,7 +7140,7 @@ ppc_elf_relax_section (bfd *abfd, bfd_vma addend = 0; struct plt_entry *ent; - if (r_type == R_PPC_PLTREL24 && link_info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info)) addend = irel->r_addend; ent = find_plt_ent (plist, got2, addend); if (ent != NULL) @@ -7021,7 +7206,7 @@ ppc_elf_relax_section (bfd *abfd, toff += irel->r_addend; /* Attempted -shared link of non-pic code loses. */ - if ((!link_info->relocatable + if ((!bfd_link_relocatable (link_info) && tsec == bfd_und_section_ptr) || tsec->output_section == NULL || (tsec->owner != NULL @@ -7032,7 +7217,7 @@ ppc_elf_relax_section (bfd *abfd, /* If the branch is in range, no need to do anything. */ if (tsec != bfd_und_section_ptr - && (!link_info->relocatable + && (!bfd_link_relocatable (link_info) /* A relocatable link may have sections moved during final link, so do not presume they remain in range. */ || tsec->output_section == isec->output_section)) @@ -7047,7 +7232,7 @@ ppc_elf_relax_section (bfd *abfd, } /* Look for an existing fixup to this address. */ - for (f = fixups; f ; f = f->next) + for (f = branch_fixups; f ; f = f->next) if (f->tsec == tsec && f->toff == toff) break; @@ -7062,7 +7247,7 @@ ppc_elf_relax_section (bfd *abfd, one. We'll report an error later. */ continue; - if (link_info->shared) + if (bfd_link_pic (link_info)) { size = 4 * ARRAY_SIZE (shared_stub_entry); insn_offset = 12; @@ -7092,11 +7277,11 @@ ppc_elf_relax_section (bfd *abfd, /* Record the fixup so we don't do it again this section. */ f = bfd_malloc (sizeof (*f)); - f->next = fixups; + f->next = branch_fixups; f->tsec = tsec; f->toff = toff; f->trampoff = trampoff; - fixups = f; + branch_fixups = f; trampoff += size; changes++; @@ -7146,10 +7331,10 @@ ppc_elf_relax_section (bfd *abfd, } } - while (fixups != NULL) + while (branch_fixups != NULL) { - struct one_fixup *f = fixups; - fixups = fixups->next; + struct one_branch_fixup *f = branch_fixups; + branch_fixups = branch_fixups->next; free (f); } } @@ -7157,7 +7342,7 @@ ppc_elf_relax_section (bfd *abfd, workaround_change = FALSE; newsize = trampoff; if (htab->params->ppc476_workaround - && (!link_info->relocatable + && (!bfd_link_relocatable (link_info) || isec->output_section->alignment_power >= htab->params->pagesize_p2)) { bfd_vma addr, end_addr; @@ -7173,7 +7358,7 @@ ppc_elf_relax_section (bfd *abfd, /* Keep space aligned, to ensure the patch code itself does not cross a page. Don't decrease size calculated on a previous pass as otherwise we might never settle on a layout. */ - newsize = 15 - (end_addr & 15); + newsize = 15 - ((end_addr - 1) & 15); newsize += crossings * 16; if (relax_info->workaround_size < newsize) { @@ -7186,7 +7371,15 @@ ppc_elf_relax_section (bfd *abfd, newsize = trampoff + relax_info->workaround_size; } - if (changes || workaround_change) + if (htab->params->pic_fixup > 0) + { + picfixup_size -= relax_info->picfixup_size; + if (picfixup_size != 0) + relax_info->picfixup_size += picfixup_size; + newsize += relax_info->picfixup_size; + } + + if (changes != 0 || picfixup_size != 0 || workaround_change) isec->size = newsize; if (isymbuf != NULL @@ -7213,6 +7406,7 @@ ppc_elf_relax_section (bfd *abfd, } } + changes += picfixup_size; if (changes != 0) { /* Append sufficient NOP relocs so we can write out relocation @@ -7247,10 +7441,10 @@ ppc_elf_relax_section (bfd *abfd, return TRUE; error_return: - while (fixups != NULL) + while (branch_fixups != NULL) { - struct one_fixup *f = fixups; - fixups = fixups->next; + struct one_branch_fixup *f = branch_fixups; + branch_fixups = branch_fixups->next; free (f); } if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) @@ -7356,7 +7550,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p, + plt_sec->output_section->vma + plt_sec->output_offset); - if (info->shared) + if (bfd_link_pic (info)) { bfd_vma got = 0; @@ -7513,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 @@ -7559,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; @@ -7566,13 +7763,15 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_boolean ret = TRUE; bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); bfd_boolean is_vxworks_tls; + unsigned int picfixup_size = 0; + struct ppc_elf_relax_info *relax_info = NULL; #ifdef DEBUG _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " "%ld relocations%s", input_bfd, input_section, (long) input_section->reloc_count, - (info->relocatable) ? " (relocatable)" : ""); + (bfd_link_relocatable (info)) ? " (relocatable)" : ""); #endif got2 = bfd_get_section_by_name (input_bfd, ".got2"); @@ -7587,12 +7786,14 @@ ppc_elf_relocate_section (bfd *output_bfd, sym_hashes = elf_sym_hashes (input_bfd); /* We have to handle relocations in vxworks .tls_vars sections specially, because the dynamic loader is 'weird'. */ - is_vxworks_tls = (htab->is_vxworks && info->shared + is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info) && !strcmp (input_section->output_section->name, ".tls_vars")); - rel = relocs; + if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) + relax_info = elf_section_data (input_section)->sec_info; + 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; @@ -7611,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; @@ -7647,11 +7849,25 @@ 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 (info->relocatable) + if (bfd_link_relocatable (info)) { if (got2 != NULL && r_type == R_PPC_PLTREL24 @@ -7664,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 @@ -7707,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); } @@ -7753,8 +7971,8 @@ ppc_elf_relocate_section (bfd *output_bfd, + R_PPC_GOT_TPREL16); else { - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); rel->r_offset -= d_offset; + bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); r_type = R_PPC_NONE; } rel->r_info = ELF32_R_INFO (r_symndx, r_type); @@ -7787,12 +8005,16 @@ ppc_elf_relocate_section (bfd *output_bfd, && branch_reloc_hash_match (input_bfd, rel + 1, htab->tls_get_addr)) offset = rel[1].r_offset; + /* We read the low GOT_TLS insn because we need to keep + the destination reg. It may be something other than + the usual r3, and moved to r3 before the call by + intervening code. */ + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); if ((tls_mask & tls_gd) != 0) { /* IE */ - insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - d_offset); - insn1 &= (1 << 26) - 1; + insn1 &= (0x1f << 21) | (0x1f << 16); insn1 |= 32 << 26; /* lwz */ if (offset != (bfd_vma) -1) { @@ -7807,7 +8029,8 @@ ppc_elf_relocate_section (bfd *output_bfd, else { /* LE */ - insn1 = 0x3c620000; /* addis 3,2,0 */ + insn1 &= 0x1f << 21; + insn1 |= 0x3c020000; /* addis r,2,0 */ if (tls_gd == 0) { /* Was an LD reloc. */ @@ -7841,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; @@ -7900,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; } @@ -7942,6 +8163,115 @@ ppc_elf_relocate_section (bfd *output_bfd, } } + if (ELIMINATE_COPY_RELOCS + && h != NULL + && !h->def_regular + && h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup > 0) + { + /* Convert lis;addi or lis;load/store accessing a protected + variable defined in a shared library to PIC. */ + unsigned int insn; + + if (r_type == R_PPC_ADDR16_HA) + { + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + if ((insn & (0x3f << 26)) == (15u << 26) + && (insn & (0x1f << 16)) == 0 /* lis */) + { + bfd_byte *p; + bfd_vma off; + bfd_vma got_addr; + + p = (contents + input_section->size + - relax_info->workaround_size + - relax_info->picfixup_size + + picfixup_size); + off = (p - contents) - (rel->r_offset - d_offset); + if (off > 0x1fffffc || (off & 3) != 0) + info->callbacks->einfo + (_("%P: %H: fixup branch overflow\n"), + input_bfd, input_section, rel->r_offset); + + bfd_put_32 (output_bfd, B | off, + contents + rel->r_offset - d_offset); + got_addr = (htab->got->output_section->vma + + htab->got->output_offset + + (h->got.offset & ~1)); + 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); + + /* Convert lis to lwz, loading address from GOT. */ + insn &= ~0xffff; + insn ^= (32u ^ 15u) << 26; + insn |= (insn & (0x1f << 21)) >> 5; + insn |= got_addr & 0xffff; + bfd_put_32 (output_bfd, insn, p + 4); + + bfd_put_32 (output_bfd, B | ((-4 - off) & 0x3ffffff), p + 8); + picfixup_size += 12; + + /* Use one of the spare relocs, so --emit-relocs + output is reasonable. */ + memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); + wrel++, rel++; + rel->r_offset = wrel[-1].r_offset + 4; + rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); + rel->r_addend = wrel[-1].r_addend; + + /* Continue on as if we had a got reloc, to output + dynamic reloc. */ + r_type = R_PPC_GOT16_LO; + } + else + info->callbacks->einfo + (_("%P: %H: error: %s with unexpected instruction %x\n"), + input_bfd, input_section, rel->r_offset, + "R_PPC_ADDR16_HA", insn); + } + else if (r_type == R_PPC_ADDR16_LO) + { + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); + if ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3f << 26)) == 36u << 26 /* stw */ + || (insn & (0x3f << 26)) == 38u << 26 /* stb */ + || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3f << 26)) == 42u << 26 /* lha */ + || (insn & (0x3f << 26)) == 44u << 26 /* sth */ + || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ + || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ + && (insn & 3) != 1) + || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ + && ((insn & 3) == 0 || (insn & 3) == 3))) + { + /* Arrange to apply the reloc addend, if any. */ + relocation = 0; + unresolved_reloc = FALSE; + rel->r_info = ELF32_R_INFO (0, r_type); + } + else + info->callbacks->einfo + (_("%P: %H: error: %s with unexpected instruction %x\n"), + input_bfd, input_section, rel->r_offset, + "R_PPC_ADDR16_LO", insn); + } + } + ifunc = NULL; if (!htab->is_vxworks) { @@ -7964,11 +8294,11 @@ ppc_elf_relocate_section (bfd *output_bfd, ent = NULL; if (ifunc != NULL - && (!info->shared + && (!bfd_link_pic (info) || is_branch_reloc (r_type))) { addend = 0; - if (r_type == R_PPC_PLTREL24 && info->shared) + if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) addend = rel->r_addend; ent = find_plt_ent (ifunc, got2, addend); } @@ -8028,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: @@ -8037,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 @@ -8096,8 +8426,8 @@ ppc_elf_relocate_section (bfd *output_bfd, { bfd_boolean dyn; dyn = htab->elf.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - || (info->shared + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) + || (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -8165,7 +8495,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } /* Generate relocs for the dynamic linker. */ - if ((info->shared || indx != 0) + if ((bfd_link_pic (info) || indx != 0) && (offp == &htab->tlsld_got.offset || h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT @@ -8209,7 +8539,12 @@ ppc_elf_relocate_section (bfd *output_bfd, { outrel.r_addend += relocation; if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - outrel.r_addend -= htab->elf.tls_sec->vma; + { + if (htab->elf.tls_sec == NULL) + outrel.r_addend = 0; + else + outrel.r_addend -= htab->elf.tls_sec->vma; + } } loc = rsec->contents; loc += (rsec->reloc_count++ @@ -8227,9 +8562,14 @@ ppc_elf_relocate_section (bfd *output_bfd, value = 1; else if (tls_ty != 0) { - value -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_ty == (TLS_TLS | TLS_TPREL)) - value += DTP_OFFSET - TP_OFFSET; + if (htab->elf.tls_sec == NULL) + value = 0; + else + { + value -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (tls_ty == (TLS_TLS | TLS_TPREL)) + value += DTP_OFFSET - TP_OFFSET; + } if (tls_ty == (TLS_TLS | TLS_GD)) { @@ -8276,6 +8616,10 @@ ppc_elf_relocate_section (bfd *output_bfd, } } + /* If here for a picfixup, we're done. */ + if (r_type != ELF32_R_TYPE (rel->r_info)) + goto copy_reloc; + relocation = (htab->got->output_section->vma + htab->got->output_offset + off @@ -8300,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; @@ -8315,7 +8658,8 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_DTPREL16_LO: case R_PPC_DTPREL16_HI: case R_PPC_DTPREL16_HA: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; /* Relocations that may need to be propagated if this is a shared @@ -8339,18 +8683,21 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, insn, p); break; } - addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; /* The TPREL16 relocs shouldn't really be used in shared libs as they will result in DT_TEXTREL being set, but support them anyway. */ goto dodyn; case R_PPC_TPREL32: - addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; goto dodyn; case R_PPC_DTPREL32: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; goto dodyn; case R_PPC_DTPMOD32: @@ -8362,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: @@ -8396,7 +8744,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_ADDR14: case R_PPC_ADDR14_BRTAKEN: case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) break; /* fall through */ @@ -8405,7 +8753,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || is_vxworks_tls) break; - if ((info->shared + if ((bfd_link_pic (info) && !(h != NULL && ((h->root.type == bfd_link_hash_undefined && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN @@ -8415,11 +8763,15 @@ ppc_elf_relocate_section (bfd *output_bfd, && (must_be_dyn_reloc (info, r_type) || !SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && h->dynindx != -1 && !h->non_got_ref - && !h->def_regular)) + && !h->def_regular + && !(h->protected_def + && ppc_elf_hash_entry (h)->has_addr16_ha + && ppc_elf_hash_entry (h)->has_addr16_lo + && htab->params->pic_fixup > 0))) { int skip; bfd_byte *loc; @@ -8538,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. */ @@ -8562,7 +8914,7 @@ ppc_elf_relocate_section (bfd *output_bfd, if (r_type == R_PPC_RELAX_PLTREL24) { - if (info->shared) + if (bfd_link_pic (info)) got2_addend = addend; addend = 0; } @@ -8585,7 +8937,7 @@ ppc_elf_relocate_section (bfd *output_bfd, size_t insn_offset = rel->r_offset; unsigned int insn; - if (info->shared) + if (bfd_link_pic (info)) { relocation -= (input_section->output_section->vma + input_section->output_offset @@ -8604,7 +8956,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } relocation += addend; - if (info->relocatable) + if (bfd_link_relocatable (info)) relocation = 0; /* First insn is HA, second is LO. */ @@ -8631,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; @@ -8689,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, - info->shared ? 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) { @@ -8784,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: @@ -8863,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) @@ -8901,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 @@ -8957,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) @@ -9004,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: @@ -9052,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. */ @@ -9063,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: @@ -9112,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; @@ -9120,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, @@ -9131,7 +9490,6 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; } - addend += insn & mask; } break; } @@ -9190,38 +9548,46 @@ 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) { if (r == bfd_reloc_overflow) { overflow: - if (warned) - continue; - if (h != NULL - && h->root.type == bfd_link_hash_undefweak - && howto->pc_relative) - { - /* Assume this is a call protected by other code that - detect the symbol is undefined. If this is the case, - we can safely ignore the overflow. If not, the - program is hosed anyway, and a little warning isn't - going to help. */ - - continue; - } - - 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; + /* On code like "if (foo) foo();" don't report overflow + on a branch to zero when foo is undefined. */ + if (!warned + && !(h != NULL + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined) + && is_branch_reloc (r_type))) + info->callbacks->reloc_overflow + (info, (h ? &h->root : NULL), sym_name, howto->name, + rel->r_addend, input_bfd, input_section, rel->r_offset); } else { @@ -9232,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 @@ -9250,15 +9641,13 @@ ppc_elf_relocate_section (bfd *output_bfd, if (htab->params->ppc476_workaround && input_section->sec_info_type == SEC_INFO_TYPE_TARGET - && (!info->relocatable + && (!bfd_link_relocatable (info) || (input_section->output_section->alignment_power >= htab->params->pagesize_p2))) { - struct ppc_elf_relax_info *relax_info; bfd_vma start_addr, end_addr, addr; bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; - relax_info = elf_section_data (input_section)->sec_info; if (relax_info->workaround_size != 0) { bfd_byte *p; @@ -9362,13 +9751,13 @@ ppc_elf_relocate_section (bfd *output_bfd, prevent the bad prefetch from happening in the first place: . - . lis 9,new_page@ha lis 9,new_page@ha - . addi 9,9,new_page@l addi 9,9,new_page@l - . mtctr 9 mtctr 9 - . bctr bctr + . lis 9,new_page@ha lis 9,new_page@ha + . addi 9,9,new_page@l addi 9,9,new_page@l + . mtctr 9 mtctr 9 + . bctr bctr . nop b somewhere_else - . b somewhere_else nop - . new_page: new_page: + . b somewhere_else nop + . new_page: new_page: . */ insn = bfd_get_32 (input_bfd, contents + offset); if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */ @@ -9389,6 +9778,8 @@ ppc_elf_relocate_section (bfd *output_bfd, && rel->r_offset >= offset && rel->r_offset < offset + 4) { + asection *sreloc; + /* If the insn we are patching had a reloc, adjust the reloc r_offset so that the reloc applies to the moved location. This matters for -r and --emit-relocs. */ @@ -9401,6 +9792,57 @@ ppc_elf_relocate_section (bfd *output_bfd, relend[-1] = tmp; } relend[-1].r_offset += patch_off - offset; + + /* Adjust REL16 addends too. */ + switch (ELF32_R_TYPE (relend[-1].r_info)) + { + case R_PPC_REL16: + case R_PPC_REL16_LO: + case R_PPC_REL16_HI: + case R_PPC_REL16_HA: + relend[-1].r_addend += patch_off - offset; + break; + default: + break; + } + + /* If we are building a PIE or shared library with + non-PIC objects, perhaps we had a dynamic reloc too? + If so, the dynamic reloc must move with the insn. */ + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc != NULL) + { + Elf32_External_Rela *slo, *shi, *srelend; + bfd_vma soffset; + + slo = (Elf32_External_Rela *) sreloc->contents; + shi = srelend = slo + sreloc->reloc_count; + soffset = (offset + input_section->output_section->vma + + input_section->output_offset); + while (slo < shi) + { + Elf32_External_Rela *srel = slo + (shi - slo) / 2; + bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel, + &outrel); + if (outrel.r_offset < soffset) + slo = srel + 1; + else if (outrel.r_offset > soffset + 3) + shi = srel; + else + { + if (srel + 1 != srelend) + { + memmove (srel, srel + 1, + (srelend - (srel + 1)) * sizeof (*srel)); + srel = srelend - 1; + } + outrel.r_offset += patch_off - offset; + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + (bfd_byte *) srel); + break; + } + } + } } else rel = NULL; @@ -9411,9 +9853,9 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000; delta += offset - patch_off; - if (info->relocatable && rel != NULL) + if (bfd_link_relocatable (info) && rel != NULL) delta = 0; - if (!info->relocatable && rel != NULL) + if (!bfd_link_relocatable (info) && rel != NULL) { enum elf_ppc_reloc_type r_type; @@ -9539,11 +9981,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, got_offset = (reloc_index + 3) * 4; /* Use the right PLT. */ - plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry + plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry : ppc_elf_vxworks_plt_entry; /* Fill in the .plt on VxWorks. */ - if (info->shared) + if (bfd_link_pic (info)) { bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_offset), @@ -9601,7 +10043,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, + ent->plt.offset + 16), htab->sgotplt->contents + got_offset); - if (!info->shared) + if (!bfd_link_pic (info)) { /* Fill in a couple of entries in .rela.plt.unloaded. */ loc = htab->srelplt2->contents @@ -9723,7 +10165,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, } } else if (h->type == STT_GNU_IFUNC - && !info->shared) + && !bfd_link_pic (info)) { /* Set the value of ifunc symbols in a non-pie executable to the glink entry. This is to avoid @@ -9775,7 +10217,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, write_glink_stub (ent, splt, p, info); - if (!info->shared) + if (!bfd_link_pic (info)) /* We only need one non-PIC glink stub. */ break; } @@ -9970,11 +10412,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, if (splt && splt->size > 0) { /* Use the right PLT. */ - const bfd_vma *plt_entry = (info->shared + const bfd_vma *plt_entry = (bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry); - if (!info->shared) + if (!bfd_link_pic (info)) { bfd_vma got_value = SYM_VAL (htab->elf.hgot); @@ -9995,7 +10437,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); - if (! info->shared) + if (! bfd_link_pic (info)) { Elf_Internal_Rela rela; bfd_byte *loc; @@ -10212,7 +10654,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, } /* Last comes the PLTresolve stub. */ - if (info->shared) + if (bfd_link_pic (info)) { bfd_vma bcl; @@ -10326,11 +10768,12 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define ELF_MACHINE_CODE EM_PPC #ifdef __QNXTARGET__ #define ELF_MAXPAGESIZE 0x1000 +#define ELF_COMMONPAGESIZE 0x1000 #else #define ELF_MAXPAGESIZE 0x10000 +#define ELF_COMMONPAGESIZE 0x10000 #endif #define ELF_MINPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 #define elf_info_to_howto ppc_elf_info_to_howto #ifdef EM_CYGNUS_POWERPC