X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=a451c4753ac9eb7e87ee5dda960081f384c8e998;hb=f3c469b95b9f1f635668660c5041df9513a47a02;hp=c5c18d08233d075f6ceac8fcd0fb2eb9594ad2fc;hpb=bb22a41815facfaa3de621aad5d055eb8e477082;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index c5c18d0823..a451c4753a 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 1999-2019 Free Software Foundation, Inc. + Copyright (C) 1999-2020 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -35,6 +35,9 @@ #include "elf64-ppc.h" #include "dwarf2.h" +/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ +#define OCTETS_PER_BYTE(ABFD, SEC) 1 + static bfd_reloc_status_type ppc64_elf_ha_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); static bfd_reloc_status_type ppc64_elf_branch_reloc @@ -920,6 +923,24 @@ static reloc_howto_type ppc64_elf_howto_raw[] = HOW (R_PPC64_PLT_PCREL34_NOTOC, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, ppc64_elf_unhandled_reloc), + HOW (R_PPC64_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed, + ppc64_elf_unhandled_reloc), + + HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed, + ppc64_elf_unhandled_reloc), + + HOW (R_PPC64_GOT_TLSGD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + ppc64_elf_unhandled_reloc), + + HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + ppc64_elf_unhandled_reloc), + + HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + ppc64_elf_unhandled_reloc), + + HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed, + ppc64_elf_unhandled_reloc), + HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont, bfd_elf_generic_reloc), @@ -1119,6 +1140,7 @@ ppc64_elf_reloc_type_lookup (bfd *abfd, break; case BFD_RELOC_PPC64_PLTGOT16_LO_DS: r = R_PPC64_PLTGOT16_LO_DS; break; + case BFD_RELOC_PPC64_TLS_PCREL: case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS; break; case BFD_RELOC_PPC_TLSGD: r = R_PPC64_TLSGD; @@ -1253,6 +1275,18 @@ ppc64_elf_reloc_type_lookup (bfd *abfd, break; case BFD_RELOC_PPC64_PLT_PCREL34: r = R_PPC64_PLT_PCREL34; break; + case BFD_RELOC_PPC64_TPREL34: r = R_PPC64_TPREL34; + break; + case BFD_RELOC_PPC64_DTPREL34: r = R_PPC64_DTPREL34; + break; + case BFD_RELOC_PPC64_GOT_TLSGD34: r = R_PPC64_GOT_TLSGD34; + break; + case BFD_RELOC_PPC64_GOT_TLSLD34: r = R_PPC64_GOT_TLSLD34; + break; + case BFD_RELOC_PPC64_GOT_TPREL34: r = R_PPC64_GOT_TPREL34; + break; + case BFD_RELOC_PPC64_GOT_DTPREL34: r = R_PPC64_GOT_DTPREL34; + break; case BFD_RELOC_PPC64_ADDR16_HIGHER34: r = R_PPC64_ADDR16_HIGHER34; break; case BFD_RELOC_PPC64_ADDR16_HIGHERA34: r = R_PPC64_ADDR16_HIGHERA34; @@ -1374,7 +1408,7 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + input_section->output_section->vma); value = (bfd_signed_vma) value >> 16; - octets = reloc_entry->address * bfd_octets_per_byte (abfd); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~0x1fffc1; insn |= (value & 0xffc1) | ((value & 0x3e) << 15); @@ -1449,7 +1483,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); - octets = reloc_entry->address * bfd_octets_per_byte (abfd); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~(0x01 << 21); r_type = reloc_entry->howto->type; @@ -1599,7 +1633,7 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, if (TOCstart == 0) TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - octets = reloc_entry->address * bfd_octets_per_byte (abfd); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets); return bfd_reloc_ok; } @@ -1749,8 +1783,9 @@ struct ppc64_elf_obj_tdata instruction not one we handle. */ unsigned int unexpected_toc_insn : 1; - /* Set if got relocs that can be optimised are present in this file. */ - unsigned int has_gotrel : 1; + /* Set if PLT/GOT/TOC relocs that can be optimised are present in + this file. */ + unsigned int has_optrel : 1; }; #define ppc64_elf_tdata(bfd) \ @@ -1951,8 +1986,9 @@ struct _ppc64_elf_section_data /* Flag set when PLTCALL relocs are detected. */ unsigned int has_pltcall:1; - /* Flag set when section has GOT relocations that can be optimised. */ - unsigned int has_gotrel:1; + /* Flag set when section has PLT/GOT/TOC relocations that can be + optimised. */ + unsigned int has_optrel:1; }; #define ppc64_elf_section_data(sec) \ @@ -2068,15 +2104,26 @@ compare_symbols (const void *ap, const void *bp) if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0) return 1; - return a > b; + /* Finally, sort on where the symbol is in memory. The symbols will + be in at most two malloc'd blocks, one for static syms, one for + dynamic syms, and we distinguish the two blocks above by testing + BSF_DYNAMIC. Since we are sorting the symbol pointers which were + originally in the same order as the symbols (and we're not + sorting the symbols themselves), this ensures a stable sort. */ + if (a < b) + return -1; + if (a > b) + return 1; + return 0; } /* Search SYMS for a symbol of the given VALUE. */ static asymbol * -sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value) +sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id, + bfd_vma value) { - long mid; + size_t mid; if (id == (unsigned) -1) { @@ -2712,6 +2759,12 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC64_REL32: case R_PPC64_REL64: case R_PPC64_REL30: + case R_PPC64_TOC16: + case R_PPC64_TOC16_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_HI: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_LO_DS: return 0; case R_PPC64_TPREL16: @@ -2727,6 +2780,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: case R_PPC64_TPREL64: + case R_PPC64_TPREL34: /* These relocations are relative but in a shared library the linker doesn't know the thread pointer base. */ return bfd_link_dll (info); @@ -3039,9 +3093,7 @@ struct ppc_link_hash_entry of the other TLS bits are set. tls_optimize clears bits when optimizing to indicate the corresponding GOT entry type is not needed. If set, TLS_TLS is never cleared. tls_optimize may also - set TLS_TPRELGD when a GD reloc turns into a TPREL one. We use a - separate flag rather than setting TPREL just for convenience in - distinguishing the two cases. + set TLS_GDIE when a GD reloc turns into an IE one. These flags are also kept for local symbols. */ #define TLS_TLS 1 /* Any TLS reloc. */ #define TLS_GD 2 /* GD reloc. */ @@ -3049,8 +3101,8 @@ struct ppc_link_hash_entry #define TLS_TPREL 8 /* TPREL reloc, => IE. */ #define TLS_DTPREL 16 /* DTPREL reloc, => LD. */ #define TLS_MARK 32 /* __tls_get_addr call marked. */ -#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */ -#define TLS_EXPLICIT 128 /* Marks TOC section TLS relocs. */ +#define TLS_GDIE 64 /* GOT TPREL reloc resulting from GD->IE. */ +#define TLS_EXPLICIT 256 /* TOC section TLS reloc, not stored. */ unsigned char tls_mask; /* The above field is also used to mark function symbols. In which @@ -3180,8 +3232,9 @@ struct ppc_link_hash_table /* Nonzero if this section has TLS related relocations. */ #define has_tls_reloc sec_flg0 -/* Nonzero if this section has an old-style call to __tls_get_addr. */ -#define has_tls_get_addr_call sec_flg1 +/* Nonzero if this section has a call to __tls_get_addr lacking marker + relocations. */ +#define nomark_tls_get_addr sec_flg1 /* Nonzero if this section has any toc or got relocs. */ #define has_toc_reloc sec_flg2 @@ -3449,7 +3502,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", flags); if (htab->sfpr == NULL - || !bfd_set_section_alignment (dynobj, htab->sfpr, 2)) + || !bfd_set_section_alignment (htab->sfpr, 2)) return FALSE; } @@ -3460,7 +3513,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", flags); if (htab->glink == NULL - || !bfd_set_section_alignment (dynobj, htab->glink, 3)) + || !bfd_set_section_alignment (htab->glink, 3)) return FALSE; /* The part of .glink used by global entry stubs, separate so that @@ -3468,7 +3521,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink", flags); if (htab->global_entry == NULL - || !bfd_set_section_alignment (dynobj, htab->global_entry, 2)) + || !bfd_set_section_alignment (htab->global_entry, 2)) return FALSE; if (!info->no_ld_generated_unwind_info) @@ -3479,14 +3532,14 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) ".eh_frame", flags); if (htab->glink_eh_frame == NULL - || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2)) + || !bfd_set_section_alignment (htab->glink_eh_frame, 2)) return FALSE; } flags = SEC_ALLOC | SEC_LINKER_CREATED; htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags); if (htab->elf.iplt == NULL - || !bfd_set_section_alignment (dynobj, htab->elf.iplt, 3)) + || !bfd_set_section_alignment (htab->elf.iplt, 3)) return FALSE; flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY @@ -3494,7 +3547,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->elf.irelplt = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags); if (htab->elf.irelplt == NULL - || !bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3)) + || !bfd_set_section_alignment (htab->elf.irelplt, 3)) return FALSE; /* Create branch lookup table for plt_branch stubs. */ @@ -3503,7 +3556,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", flags); if (htab->brlt == NULL - || !bfd_set_section_alignment (dynobj, htab->brlt, 3)) + || !bfd_set_section_alignment (htab->brlt, 3)) return FALSE; /* Local plt entries, put in .branch_lt but a separate section for @@ -3511,7 +3564,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", flags); if (htab->pltlocal == NULL - || !bfd_set_section_alignment (dynobj, htab->pltlocal, 3)) + || !bfd_set_section_alignment (htab->pltlocal, 3)) return FALSE; if (!bfd_link_pic (info)) @@ -3522,13 +3575,13 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags); if (htab->relbrlt == NULL - || !bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) + || !bfd_set_section_alignment (htab->relbrlt, 3)) return FALSE; htab->relpltlocal = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags); if (htab->relpltlocal == NULL - || !bfd_set_section_alignment (dynobj, htab->relpltlocal, 3)) + || !bfd_set_section_alignment (htab->relpltlocal, 3)) return FALSE; return TRUE; @@ -3724,13 +3777,13 @@ create_got_section (bfd *abfd, struct bfd_link_info *info) got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); if (!got - || !bfd_set_section_alignment (abfd, got, 3)) + || !bfd_set_section_alignment (got, 3)) return FALSE; relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got", flags | SEC_READONLY); if (!relgot - || !bfd_set_section_alignment (abfd, relgot, 3)) + || !bfd_set_section_alignment (relgot, 3)) return FALSE; ppc64_elf_tdata (abfd)->got = got; @@ -4492,7 +4545,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, int tls_type; struct _ppc64_elf_section_data *ppc64_sec; struct plt_entry **ifunc, **plt_list; - bfd_vma sym_addend; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -4506,8 +4558,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sec->has_toc_reloc = 1; } - tls_type = 0; - ifunc = NULL; r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { @@ -4516,27 +4566,51 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_D34_HI30: case R_PPC64_D34_HA30: case R_PPC64_D28: - htab->powerxx_stubs = 1; - /* Fall through. */ - default: - /* Somewhat foolishly, because the ABIs don't specifically - allow it, ppc64 gas and ld support GOT and PLT relocs - with non-zero addends where the addend results in - sym+addend being stored in the GOT or PLT entry. This - can't be supported for pcrel relocs because the addend is - used to specify the pcrel offset. */ - sym_addend = rel->r_addend; - break; - + case R_PPC64_TPREL34: + case R_PPC64_DTPREL34: case R_PPC64_PCREL34: case R_PPC64_GOT_PCREL34: + case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_DTPREL34: case R_PPC64_PLT_PCREL34: case R_PPC64_PLT_PCREL34_NOTOC: case R_PPC64_PCREL28: htab->powerxx_stubs = 1; - sym_addend = 0; + break; + default: break; } + + switch (r_type) + { + case R_PPC64_PLT16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT16_HA: + case R_PPC64_TOC16_HA: + case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: + case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + case R_PPC64_GOT_PCREL34: + ppc64_elf_tdata (abfd)->has_optrel = 1; + ppc64_elf_section_data (sec)->has_optrel = 1; + break; + default: + break; + } + + ifunc = NULL; if (h != NULL) { if (h->type == STT_GNU_IFUNC) @@ -4555,13 +4629,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, - sym_addend, + rel->r_addend, NON_GOT | PLT_IFUNC); if (ifunc == NULL) return FALSE; } } + tls_type = 0; switch (r_type) { case R_PPC64_TLSGD: @@ -4572,7 +4647,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, ((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK; else if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, - sym_addend, + rel->r_addend, NON_GOT | TLS_TLS | TLS_MARK)) return FALSE; sec->has_tls_reloc = 1; @@ -4582,6 +4657,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD34: tls_type = TLS_TLS | TLS_LD; goto dogottls; @@ -4589,6 +4665,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD34: tls_type = TLS_TLS | TLS_GD; goto dogottls; @@ -4596,6 +4673,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_TPREL34: if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; @@ -4605,22 +4683,19 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_DTPREL16_LO_DS: case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL34: tls_type = TLS_TLS | TLS_DTPREL; dogottls: sec->has_tls_reloc = 1; goto dogot; + case R_PPC64_GOT16: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_HI: case R_PPC64_GOT16_HA: + case R_PPC64_GOT16_DS: case R_PPC64_GOT16_LO_DS: case R_PPC64_GOT_PCREL34: - ppc64_elf_tdata (abfd)->has_gotrel = 1; - ppc64_elf_section_data (sec)->has_gotrel = 1; - /* Fall through. */ - - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16: - case R_PPC64_GOT16_HI: - case R_PPC64_GOT16_LO: dogot: /* This symbol requires a global offset table entry. */ sec->has_toc_reloc = 1; @@ -4646,7 +4721,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, eh = (struct ppc_link_hash_entry *) h; for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next) - if (ent->addend == sym_addend + if (ent->addend == rel->r_addend && ent->owner == abfd && ent->tls_type == tls_type) break; @@ -4657,7 +4732,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (ent == NULL) return FALSE; ent->next = eh->elf.got.glist; - ent->addend = sym_addend; + ent->addend = rel->r_addend; ent->owner = abfd; ent->tls_type = tls_type; ent->is_indirect = FALSE; @@ -4670,14 +4745,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, else /* This is a global offset table entry for a local symbol. */ if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, - sym_addend, tls_type)) + rel->r_addend, tls_type)) return FALSE; /* We may also need a plt entry if the symbol turns out to be an ifunc. */ if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) { - if (!update_plt_info (abfd, &h->plt.plist, sym_addend)) + if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) return FALSE; } break; @@ -4703,9 +4778,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } if (plt_list == NULL) plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx, - sym_addend, + rel->r_addend, NON_GOT | PLT_KEEP); - if (!update_plt_info (abfd, plt_list, sym_addend)) + if (!update_plt_info (abfd, plt_list, rel->r_addend)) return FALSE; break; @@ -4776,6 +4851,16 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TOC16_HA: case R_PPC64_TOC16_LO_DS: sec->has_toc_reloc = 1; + if (h != NULL && bfd_link_executable (info)) + { + /* We may need a copy reloc. */ + h->non_got_ref = 1; + /* Strongly prefer a copy reloc over a dynamic reloc. + glibc ld.so as of 2019-08 will error out if one of + these relocations is emitted. */ + h->needs_copy = 1; + goto dodyn; + } break; /* Marker reloc. */ @@ -4855,7 +4940,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, ; else /* Mark this section as having an old-style call. */ - sec->has_tls_get_addr_call = 1; + sec->nomark_tls_get_addr = 1; } plt_list = &h->plt.plist; } @@ -4863,7 +4948,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* We may need a .plt entry if the function this reloc refers to is in a shared lib. */ if (plt_list - && !update_plt_info (abfd, plt_list, sym_addend)) + && !update_plt_info (abfd, plt_list, rel->r_addend)) return FALSE; break; @@ -4903,11 +4988,11 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, { struct ppc_link_hash_entry *eh; eh = (struct ppc_link_hash_entry *) h; - eh->tls_mask |= tls_type; + eh->tls_mask |= tls_type & 0xff; } else if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, - sym_addend, tls_type)) + rel->r_addend, tls_type)) return FALSE; ppc64_sec = ppc64_elf_section_data (sec); @@ -4929,7 +5014,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } BFD_ASSERT (rel->r_offset % 8 == 0); ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx; - ppc64_sec->u.toc.add[rel->r_offset / 8] = sym_addend; + ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend; /* Mark the second slot of a GD or LD entry. -1 to indicate GD and -2 to indicate LD. */ @@ -4951,6 +5036,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: + case R_PPC64_TPREL34: if (bfd_link_dll (info)) info->flags |= DF_STATIC_TLS; goto dodyn; @@ -5005,7 +5091,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_UADDR32: case R_PPC64_UADDR64: case R_PPC64_TOC: - if (h != NULL && !bfd_link_pic (info)) + if (h != NULL && bfd_link_executable (info)) /* We may need a copy reloc. */ h->non_got_ref = 1; @@ -5035,17 +5121,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, dynamic library if we manage to avoid copy relocs for the symbol. */ dodyn: - 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 - && !bfd_link_pic (info) - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular)) + if ((h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular)) + || (h != NULL + && !bfd_link_executable (info) + && !SYMBOLIC_BIND (info, h)) + || (bfd_link_pic (info) + && must_be_dyn_reloc (info, r_type)) || (!bfd_link_pic (info) && ifunc != NULL)) { @@ -5758,9 +5841,7 @@ sfpr_define (struct bfd_link_info *info, s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE); if (s == NULL) return FALSE; - if (s->root.type == bfd_link_hash_new - || (s->root.type = bfd_link_hash_defined - && s->root.u.def.section == stub_sec)) + if (s->root.type == bfd_link_hash_new) { s->root.type = bfd_link_hash_defined; s->root.u.def.section = stub_sec; @@ -6354,7 +6435,7 @@ ppc64_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 (bfd_link_pic (info)) + if (!bfd_link_executable (info)) return TRUE; /* If there are no references to this symbol that do not use the @@ -6370,7 +6451,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* If we don't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h)) + || (ELIMINATE_COPY_RELOCS + && !h->needs_copy + && !alias_readonly_dynrelocs (h)) /* Protected variables do not work with .dynbss. The copy in .dynbss won't be used by the shared library with the protected @@ -6758,6 +6841,16 @@ dec_dynrel_count (bfd_vma r_info, default: return TRUE; + case R_PPC64_TOC16: + case R_PPC64_TOC16_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_HI: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_LO_DS: + if (h == NULL) + return TRUE; + break; + case R_PPC64_TPREL16: case R_PPC64_TPREL16_LO: case R_PPC64_TPREL16_HI: @@ -6771,6 +6864,7 @@ dec_dynrel_count (bfd_vma r_info, case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: case R_PPC64_TPREL64: + case R_PPC64_TPREL34: case R_PPC64_DTPMOD64: case R_PPC64_DTPREL64: case R_PPC64_ADDR64: @@ -6820,17 +6914,18 @@ dec_dynrel_count (bfd_vma r_info, return FALSE; } - 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 - && !bfd_link_pic (info) - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) + if ((h != NULL + && (h->root.type == bfd_link_hash_defweak + || !h->def_regular)) + || (h != NULL + && !bfd_link_executable (info) + && !SYMBOLIC_BIND (info, h)) + || (bfd_link_pic (info) + && must_be_dyn_reloc (info, r_type)) + || (!bfd_link_pic (info) + && (h != NULL + ? h->type == STT_GNU_IFUNC + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))) ; else return TRUE; @@ -7679,7 +7774,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) Elf_Internal_Sym *sym; asection *sym_sec; unsigned char *tls_mask; - unsigned char tls_set, tls_clear, tls_type = 0; + unsigned int tls_set, tls_clear, tls_type = 0; bfd_vma value; bfd_boolean ok_tprel, is_local; long toc_ref_index = 0; @@ -7721,11 +7816,9 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) value = sym->st_value; ok_tprel = FALSE; - is_local = FALSE; - if (h == NULL - || !h->def_dynamic) + is_local = SYMBOL_REFERENCES_LOCAL (info, h); + if (is_local) { - is_local = TRUE; if (h != NULL && h->root.type == bfd_link_hash_undefweak) ok_tprel = TRUE; @@ -7734,9 +7827,14 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) { value += sym_sec->output_offset; value += sym_sec->output_section->vma; - value -= htab->elf.tls_sec->vma; - ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) - < (bfd_vma) 1 << 32); + value -= htab->elf.tls_sec->vma + TP_OFFSET; + /* Note that even though the prefix insns + allow a 1<<33 offset we use the same test + as for addis;addi. There may be a mix of + pcrel and non-pcrel code and the decision + to optimise is per symbol, not per TLS + sequence. */ + ok_tprel = value + 0x80008000ULL < 1ULL << 32; } } @@ -7748,7 +7846,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) setup insn. If we don't find matching arg setup relocs, don't do any tls optimization. */ if (pass == 0 - && sec->has_tls_get_addr_call + && sec->nomark_tls_get_addr && h != NULL && (h == &htab->tls_get_addr->elf || h == &htab->tls_get_addr_fd->elf) @@ -7767,6 +7865,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) { case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSLD34: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; /* Fall through. */ @@ -7787,6 +7886,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TLSGD34: expecting_tls_get_addr = 1; found_tls_get_addr_arg = 1; /* Fall through. */ @@ -7798,11 +7898,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) tls_set = 0; else /* GD -> IE */ - tls_set = TLS_TLS | TLS_TPRELGD; + tls_set = TLS_TLS | TLS_GDIE; tls_clear = TLS_GD; tls_type = TLS_TLS | TLS_GD; break; + case R_PPC64_GOT_TPREL34: case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: @@ -7817,8 +7918,11 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } continue; - case R_PPC64_TLSGD: case R_PPC64_TLSLD: + if (!is_local) + continue; + /* Fall through. */ + case R_PPC64_TLSGD: if (rel + 1 < relend && is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info))) { @@ -7925,7 +8029,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) tls_set = TLS_EXPLICIT | TLS_GD; else /* GD -> IE */ - tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; + tls_set = TLS_EXPLICIT | TLS_GD | TLS_GDIE; tls_clear = TLS_GD; } else @@ -7946,7 +8050,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (pass == 0) { if (!expecting_tls_get_addr - || !sec->has_tls_get_addr_call) + || !sec->nomark_tls_get_addr) continue; if (rel + 1 < relend @@ -7998,12 +8102,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) Disable optimization in this case. */ if ((tls_clear & (TLS_GD | TLS_LD)) != 0 && (tls_set & TLS_EXPLICIT) == 0 - && !sec->has_tls_get_addr_call + && !sec->nomark_tls_get_addr && ((*tls_mask & (TLS_TLS | TLS_MARK)) != (TLS_TLS | TLS_MARK))) continue; - if (expecting_tls_get_addr) + if (expecting_tls_get_addr == 1 + !sec->nomark_tls_get_addr) { struct plt_entry *ent = NULL; @@ -8070,7 +8174,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) } } - *tls_mask |= tls_set; + *tls_mask |= tls_set & 0xff; *tls_mask &= ~tls_clear; } @@ -8156,61 +8260,81 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) static bfd_boolean ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) { - return ((insn & (0x3f << 26)) == 12u << 26 /* addic */ - || (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)) == 56u << 26 /* lq,lfq */ - || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ + return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */ + || (insn & (0x3fu << 26)) == 14u << 26 /* addi */ + || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3fu << 26)) == 36u << 26 /* stw */ + || (insn & (0x3fu << 26)) == 38u << 26 /* stb */ + || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3fu << 26)) == 42u << 26 /* lha */ + || (insn & (0x3fu << 26)) == 44u << 26 /* sth */ + || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */ + || (insn & (0x3fu << 26)) == 56u << 26 /* lq,lfq */ + || ((insn & (0x3fu << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ /* Exclude lfqu by testing reloc. If relocs are ever defined for the reduced D field in psq_lu then those will need testing too. */ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */ + || ((insn & (0x3fu << 26)) == 58u << 26 /* ld,lwa */ && (insn & 1) == 0) - || (insn & (0x3f << 26)) == 60u << 26 /* stfq */ - || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ + || (insn & (0x3fu << 26)) == 60u << 26 /* stfq */ + || ((insn & (0x3fu << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ /* Exclude stfqu. psq_stu as above for psq_lu. */ && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */ + || ((insn & (0x3fu << 26)) == 62u << 26 /* std,stq */ && (insn & 1) == 0)); } /* PCREL_OPT in one instance flags to the linker that a pair of insns: pld ra,symbol@got@pcrel - load/store rt,0(ra) + load/store rt,off(ra) or pla ra,symbol@pcrel - load/store rt,0(ra) + load/store rt,off(ra) may be translated to - pload/pstore rt,symbol@pcrel + pload/pstore rt,symbol+off@pcrel nop. This function returns true if the optimization is possible, placing - the prefix insn in *PINSN1 and a NOP in *PINSN2. + the prefix insn in *PINSN1, a NOP in *PINSN2 and the offset in *POFF. On entry to this function, the linker has already determined that the pld can be replaced with pla: *PINSN1 is that pla insn, while *PINSN2 is the second instruction. */ static bfd_boolean -xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) +xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff) { - uint32_t insn2 = *pinsn2 >> 32; - uint64_t i1new; + uint64_t insn1 = *pinsn1; + uint64_t insn2 = *pinsn2; + bfd_signed_vma off; + + if ((insn2 & (63ULL << 58)) == 1ULL << 58) + { + /* Check that regs match. */ + if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31)) + return FALSE; + + /* P8LS or PMLS form, non-pcrel. */ + if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58)) + return FALSE; + + *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52); + *pinsn2 = PNOP; + off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff); + *poff = (off ^ 0x200000000ULL) - 0x200000000ULL; + return TRUE; + } + + insn2 >>= 32; /* Check that regs match. */ - if (((insn2 >> 16) & 31) != ((*pinsn1 >> 21) & 31)) + if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31)) return FALSE; switch ((insn2 >> 26) & 63) @@ -8230,27 +8354,28 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) case 52: /* stfs */ case 54: /* stfd */ /* These are the PMLS cases, where we just need to tack a prefix - on the insn. Check that the D field is zero. */ - if ((insn2 & 0xffff) != 0) - return FALSE; - i1new = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) + on the insn. */ + insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); + off = insn2 & 0xffff; break; case 58: /* lwa, ld */ - if ((insn2 & 0xfffd) != 0) + if ((insn2 & 1) != 0) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; case 57: /* lxsd, lxssp */ - if ((insn2 & 0xfffc) != 0 || (insn2 & 3) < 2) + if ((insn2 & 3) < 2) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((40ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; case 61: /* stxsd, stxssp, lxv, stxv */ @@ -8258,40 +8383,39 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2) return FALSE; else if ((insn2 & 3) >= 2) { - if ((insn2 & 0xfffc) != 0) - return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((44ULL | (insn2 & 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; } else { - if ((insn2 & 0xfff0) != 0) - return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfff0; } break; case 56: /* lq */ - if ((insn2 & 0xffff) != 0) - return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | (insn2 & ((63ULL << 26) | (31ULL << 21)))); + off = insn2 & 0xffff; break; case 62: /* std, stq */ - if ((insn2 & 0xfffd) != 0) + if ((insn2 & 1) != 0) return FALSE; - i1new = ((1ULL << 58) | (1ULL << 52) + insn1 = ((1ULL << 58) | (1ULL << 52) | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26) | (insn2 & (31ULL << 21))); + off = insn2 & 0xfffc; break; } - *pinsn1 = i1new; + *pinsn1 = insn1; *pinsn2 = (uint64_t) NOP << 32; + *poff = (off ^ 0x8000) - 0x8000; return TRUE; } @@ -8554,65 +8678,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; bfd_vma val; - enum {no_check, check_lo, check_ha} insn_check; r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - default: - insn_check = no_check; - break; - - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT16_HA: - case R_PPC64_TOC16_HA: - insn_check = check_ha; - break; - - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_LO_DS: - insn_check = check_lo; - break; - } - - if (insn_check != no_check) - { - bfd_vma off = rel->r_offset & ~3; - unsigned char buf[4]; - unsigned int insn; - - if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) - { - free (used); - goto error_ret; - } - insn = bfd_get_32 (ibfd, buf); - if (insn_check == check_lo - ? !ok_lo_toc_insn (insn, r_type) - : ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) - { - char str[12]; - - ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; - sprintf (str, "%#08x", insn); - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: toc optimization is not supported for" - " %s instruction\n"), - ibfd, sec, rel->r_offset & ~3, str); - } - } - switch (r_type) { case R_PPC64_TOC16: @@ -8964,11 +9031,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if (!is_ppc64_elf (ibfd)) continue; - if (!ppc64_elf_tdata (ibfd)->has_gotrel) + if (!ppc64_elf_tdata (ibfd)->has_optrel) continue; sec = ppc64_elf_tdata (ibfd)->got; - got = sec->output_section->vma + sec->output_offset + 0x8000; + got = 0; + if (sec != NULL) + got = sec->output_section->vma + sec->output_offset + 0x8000; local_syms = NULL; symtab_hdr = &elf_symtab_hdr (ibfd); @@ -8976,7 +9045,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) for (sec = ibfd->sections; sec != NULL; sec = sec->next) { if (sec->reloc_count == 0 - || !ppc64_elf_section_data (sec)->has_gotrel + || !ppc64_elf_section_data (sec)->has_optrel || discarded_section (sec)) continue; @@ -9003,11 +9072,68 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) asection *sym_sec; struct elf_link_hash_entry *h; struct got_entry *ent; - bfd_vma sym_addend, val, pc; + bfd_vma val, pc; unsigned char buf[8]; unsigned int insn; + enum {no_check, check_lo, check_ha} insn_check; r_type = ELF64_R_TYPE (rel->r_info); + switch (r_type) + { + default: + insn_check = no_check; + break; + + case R_PPC64_PLT16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT16_HA: + case R_PPC64_TOC16_HA: + insn_check = check_ha; + break; + + case R_PPC64_PLT16_LO: + case R_PPC64_PLT16_LO_DS: + case R_PPC64_GOT_TLSLD16_LO: + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_LO: + case R_PPC64_TOC16_LO_DS: + insn_check = check_lo; + break; + } + + if (insn_check != no_check) + { + bfd_vma off = rel->r_offset & ~3; + + if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) + goto got_error_ret; + + insn = bfd_get_32 (ibfd, buf); + if (insn_check == check_lo + ? !ok_lo_toc_insn (insn, r_type) + : ((insn & ((0x3fu << 26) | 0x1f << 16)) + != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) + { + char str[12]; + + ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; + sprintf (str, "%#08x", insn); + info->callbacks->einfo + /* xgettext:c-format */ + (_("%H: got/toc optimization is not supported for" + " %s instruction\n"), + ibfd, sec, rel->r_offset & ~3, str); + continue; + } + } + switch (r_type) { /* Note that we don't delete GOT entries for @@ -9021,11 +9147,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) case R_PPC64_GOT16_HA: case R_PPC64_GOT16_LO_DS: - sym_addend = rel->r_addend; - break; - case R_PPC64_GOT_PCREL34: - sym_addend = 0; break; } @@ -9034,6 +9156,11 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) r_symndx, ibfd)) goto got_error_ret; + if (sym_sec == NULL + || sym_sec->output_section == NULL + || discarded_section (sym_sec)) + continue; + if (!SYMBOL_REFERENCES_LOCAL (info, h)) continue; @@ -9041,7 +9168,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) val = h->root.u.def.value; else val = sym->st_value; - val += sym_addend; + val += rel->r_addend; val += sym_sec->output_section->vma + sym_sec->output_offset; /* Fudge factor to allow for the fact that the preliminary layout @@ -9062,7 +9189,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) rel->r_offset & ~3, 4)) goto got_error_ret; insn = bfd_get_32 (ibfd, buf); - if (((insn & ((0x3f << 26) | 0x1f << 16)) + if (((insn & ((0x3fu << 26) | 0x1f << 16)) != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) continue; break; @@ -9075,7 +9202,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) rel->r_offset & ~3, 4)) goto got_error_ret; insn = bfd_get_32 (ibfd, buf); - if ((insn & (0x3f << 26 | 0x3)) != 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) != 58u << 26 /* ld */) continue; break; @@ -9092,7 +9219,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) if ((insn & (-1u << 18)) != ((1u << 26) | (1u << 20))) continue; insn = bfd_get_32 (ibfd, buf + 4); - if ((insn & (0x3f << 26)) != 57u << 26) + if ((insn & (0x3fu << 26)) != 57u << 26) continue; break; } @@ -9106,7 +9233,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) ent = local_got_ents[r_symndx]; } for (; ent != NULL; ent = ent->next) - if (ent->addend == sym_addend + if (ent->addend == rel->r_addend && ent->owner == ibfd && ent->tls_type == 0) break; @@ -9165,7 +9292,7 @@ allocate_got (struct elf_link_hash_entry *h, htab->got_reli_size += rentsize; } else if (((bfd_link_pic (info) - && !((gent->tls_type & TLS_TPREL) != 0 + && !(gent->tls_type != 0 && bfd_link_executable (info) && SYMBOL_REFERENCES_LOCAL (info, h))) || (htab->elf.dynamic_sections_created @@ -9240,7 +9367,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) eh = (struct ppc_link_hash_entry *) h; /* Run through the TLS GD got entries first if we're changing them to TPREL. */ - if ((eh->tls_mask & (TLS_TLS | TLS_TPRELGD)) == (TLS_TLS | TLS_TPRELGD)) + if ((eh->tls_mask & (TLS_TLS | TLS_GDIE)) == (TLS_TLS | TLS_GDIE)) for (gent = h->got.glist; gent != NULL; gent = gent->next) if (gent->got.refcount > 0 && (gent->tls_type & TLS_GD) != 0) @@ -9271,7 +9398,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (gent->got.refcount > 0) { if ((gent->tls_type & TLS_LD) != 0 - && !h->def_dynamic) + && SYMBOL_REFERENCES_LOCAL (info, h)) { ppc64_tlsld_got (gent->owner)->got.refcount += 1; *pgent = gent->next; @@ -9288,7 +9415,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) for (gent = h->got.glist; gent != NULL; gent = gent->next) if (!gent->is_indirect) { - /* Make sure this symbol is output as a dynamic symbol. */ + /* Ensure we catch all the cases where this symbol should + be made dynamic. */ if (!ensure_undef_dynamic (info, h)) return FALSE; @@ -9323,7 +9451,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) be defined in regular objects. For the normal shared case, discard space for relocs that have become local due to symbol visibility changes. */ - if (bfd_link_pic (info)) { /* Relocs that use pc_count are those that appear on a call @@ -9348,24 +9475,27 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (eh->dyn_relocs != NULL) { - /* Make sure this symbol is output as a dynamic symbol. */ + /* Ensure we catch all the cases where this symbol + should be made dynamic. */ if (!ensure_undef_dynamic (info, h)) return FALSE; } } - else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC) + + /* For a fixed position executable, discard space for + relocs against symbols which are not dynamic. */ + else if (h->type != STT_GNU_IFUNC) { - /* For the non-pic case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ if (h->dynamic_adjusted && !h->def_regular && !ELF_COMMON_DEF_P (h)) { - /* Make sure this symbol is output as a dynamic symbol. */ + /* Ensure we catch all the cases where this symbol + should be made dynamic. */ if (!ensure_undef_dynamic (info, h)) return FALSE; + /* But if that didn't work out, discard dynamic relocs. */ if (h->dynindx == -1) eh->dyn_relocs = NULL; } @@ -9697,7 +9827,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, htab->got_reli_size += rel_size; } else if (bfd_link_pic (info) - && !((ent->tls_type & TLS_TPREL) != 0 + && !(ent->tls_type != 0 && bfd_link_executable (info))) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; @@ -9774,7 +9904,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, ent->got.offset = s->size; ent->owner = ibfd; s->size += 16; - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += sizeof (Elf64_External_Rela); @@ -12069,7 +12199,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) htab->got_reli_size += rel_size; } else if (bfd_link_pic (info) - && !((ent->tls_type & TLS_TPREL) != 0 + && !(ent->tls_type != 0 && bfd_link_executable (info))) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; @@ -12095,7 +12225,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) asection *s = ppc64_elf_tdata (ibfd)->got; ent->got.offset = s->size; s->size += 16; - if (bfd_link_pic (info)) + if (bfd_link_dll (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += sizeof (Elf64_External_Rela); @@ -14033,6 +14163,66 @@ ppc64_elf_action_discarded (asection *sec) return _bfd_elf_default_action_discarded (sec); } +/* These are the dynamic relocations supported by glibc. */ + +static bfd_boolean +ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type) +{ + switch (r_type) + { + case R_PPC64_RELATIVE: + case R_PPC64_NONE: + case R_PPC64_ADDR64: + case R_PPC64_GLOB_DAT: + case R_PPC64_IRELATIVE: + case R_PPC64_JMP_IREL: + case R_PPC64_JMP_SLOT: + case R_PPC64_DTPMOD64: + case R_PPC64_DTPREL64: + case R_PPC64_TPREL64: + case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_DS: + case R_PPC64_TPREL16: + case R_PPC64_TPREL16_LO: + case R_PPC64_TPREL16_HI: + case R_PPC64_TPREL16_HIGH: + case R_PPC64_TPREL16_HA: + case R_PPC64_TPREL16_HIGHA: + case R_PPC64_TPREL16_HIGHER: + case R_PPC64_TPREL16_HIGHEST: + case R_PPC64_TPREL16_HIGHERA: + case R_PPC64_TPREL16_HIGHESTA: + case R_PPC64_ADDR16_LO_DS: + case R_PPC64_ADDR16_LO: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGH: + case R_PPC64_ADDR16_HA: + case R_PPC64_ADDR16_HIGHA: + case R_PPC64_REL30: + case R_PPC64_COPY: + case R_PPC64_UADDR64: + case R_PPC64_UADDR32: + case R_PPC64_ADDR32: + case R_PPC64_ADDR24: + case R_PPC64_ADDR16: + case R_PPC64_UADDR16: + case R_PPC64_ADDR16_DS: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHERA: + case R_PPC64_ADDR16_HIGHESTA: + case R_PPC64_ADDR14: + case R_PPC64_ADDR14_BRTAKEN: + case R_PPC64_ADDR14_BRNTAKEN: + case R_PPC64_REL32: + case R_PPC64_REL64: + return TRUE; + + default: + return FALSE; + } +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -14086,6 +14276,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_boolean is_opd; /* Assume 'at' branch hints. */ bfd_boolean is_isa_v2 = TRUE; + bfd_boolean warned_dynamic = FALSE; bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0); /* Initialize howto table if needed. */ @@ -14307,10 +14498,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (h == NULL || h->elf.root.type == bfd_link_hash_defined || h->elf.root.type == bfd_link_hash_defweak) - && (IS_PPC64_TLS_RELOC (r_type) - != (sym_type == STT_TLS - || (sym_type == STT_SECTION - && (sec->flags & SEC_THREAD_LOCAL) != 0)))) + && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS)) { if ((tls_mask & TLS_TLS) != 0 && (r_type == R_PPC64_TLS @@ -14350,7 +14538,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_LO_DS_OPT: insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); - if ((insn & (0x3f << 26)) != 58u << 26) + if ((insn & (0x3fu << 26)) != 58u << 26) abort (); insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset); @@ -14388,7 +14576,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, doing a GD->IE transition. */ if (retval == 2) { - tls_gd = TLS_TPRELGD; + tls_gd = TLS_GDIE; if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) goto tls_ldgd_opt; @@ -14442,35 +14630,78 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC64_GOT_TPREL34: + if ((tls_mask & TLS_TLS) != 0 + && (tls_mask & TLS_TPREL) == 0) + { + /* pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel */ + pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset); + pinsn <<= 32; + pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + pinsn += ((2ULL << 56) + (-1ULL << 52) + + (14ULL << 26) - (57ULL << 26) + (13ULL << 16)); + bfd_put_32 (input_bfd, pinsn >> 32, + contents + rel->r_offset); + bfd_put_32 (input_bfd, pinsn & 0xffffffff, + contents + rel->r_offset + 4); + r_type = R_PPC64_TPREL34; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + } + break; + case R_PPC64_TLS: if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_TPREL) == 0) { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); insn = _bfd_elf_ppc_at_tls_transform (insn, 13); if (insn == 0) - abort (); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - /* Was PPC64_TLS which sits on insn boundary, now - PPC64_TPREL16_LO which is at low-order half-word. */ - rel->r_offset += d_offset; - r_type = R_PPC64_TPREL16_LO; - if (toc_symndx != 0) + break; + if ((rel->r_offset & 3) == 0) { - rel->r_info = ELF64_R_INFO (toc_symndx, r_type); - rel->r_addend = toc_addend; - /* We changed the symbol. Start over in order to - get h, sym, sec etc. right. */ - goto again; + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + /* Was PPC64_TLS which sits on insn boundary, now + PPC64_TPREL16_LO which is at low-order half-word. */ + rel->r_offset += d_offset; + r_type = R_PPC64_TPREL16_LO; + if (toc_symndx != 0) + { + rel->r_info = ELF64_R_INFO (toc_symndx, r_type); + rel->r_addend = toc_addend; + /* We changed the symbol. Start over in order to + get h, sym, sec etc. right. */ + goto again; + } + else + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + } + else if ((rel->r_offset & 3) == 1) + { + /* For pcrel IE to LE we already have the full + offset and thus don't need an addi here. A nop + or mr will do. */ + if ((insn & (0x3fu << 26)) == 14 << 26) + { + /* Extract regs from addi rt,ra,si. */ + unsigned int rt = (insn >> 21) & 0x1f; + unsigned int ra = (insn >> 16) & 0x1f; + if (rt == ra) + insn = NOP; + else + { + /* Build or ra,rs,rb with rb==rs, ie. mr ra,rs. */ + insn = (rt << 16) | (ra << 21) | (ra << 11); + insn |= (31u << 26) | (444u << 1); + } + } + bfd_put_32 (input_bfd, insn, contents + rel->r_offset - 1); } - else - rel->r_info = ELF64_R_INFO (r_symndx, r_type); } break; case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - tls_gd = TLS_TPRELGD; + tls_gd = TLS_GDIE; if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) goto tls_gdld_hi; break; @@ -14495,7 +14726,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: - tls_gd = TLS_TPRELGD; + tls_gd = TLS_GDIE; if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) goto tls_ldgd_opt; break; @@ -14513,7 +14744,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, stays with its arg setup insns, ie. that the next reloc is the __tls_get_addr call associated with the current reloc. Edit both insns. */ - if (input_section->has_tls_get_addr_call + if (input_section->nomark_tls_get_addr && rel + 1 < relend && branch_reloc_hash_match (input_bfd, rel + 1, htab->tls_get_addr, @@ -14529,15 +14760,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* IE */ insn1 &= (0x1f << 21) | (0x1f << 16); - insn1 |= 58 << 26; /* ld */ + insn1 |= 58u << 26; /* ld */ insn2 = 0x7c636a14; /* add 3,3,13 */ if (offset != (bfd_vma) -1) rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - if ((tls_mask & TLS_EXPLICIT) == 0) - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - else + if (r_type == R_PPC64_TOC16 + || r_type == R_PPC64_TOC16_LO) r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; + else + r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 1)) & 1) + + R_PPC64_GOT_TPREL16_DS); rel->r_info = ELF64_R_INFO (r_symndx, r_type); } else @@ -14549,20 +14781,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (tls_gd == 0) { /* Was an LD reloc. */ - if (toc_symndx) - sec = local_sections[toc_symndx]; - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; + r_symndx = STN_UNDEF; rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); } else if (toc_symndx != 0) { @@ -14601,6 +14821,51 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC64_GOT_TLSGD34: + if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) + { + pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset); + pinsn <<= 32; + pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((tls_mask & TLS_GDIE) != 0) + { + /* IE, pla -> pld */ + pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26); + r_type = R_PPC64_GOT_TPREL34; + } + else + { + /* LE, pla pcrel -> paddi r13 */ + pinsn += (-1ULL << 52) + (13ULL << 16); + r_type = R_PPC64_TPREL34; + } + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + bfd_put_32 (input_bfd, pinsn >> 32, + contents + rel->r_offset); + bfd_put_32 (input_bfd, pinsn & 0xffffffff, + contents + rel->r_offset + 4); + } + break; + + case R_PPC64_GOT_TLSLD34: + if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) + { + pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset); + pinsn <<= 32; + pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + pinsn += (-1ULL << 52) + (13ULL << 16); + bfd_put_32 (input_bfd, pinsn >> 32, + contents + rel->r_offset); + bfd_put_32 (input_bfd, pinsn & 0xffffffff, + contents + rel->r_offset + 4); + rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; + r_symndx = STN_UNDEF; + r_type = R_PPC64_TPREL34; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + goto again; + } + break; + case R_PPC64_TLSGD: if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0 && rel + 1 < relend) @@ -14622,7 +14887,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL) bfd_put_32 (output_bfd, NOP, contents + offset + 4); - if ((tls_mask & TLS_TPRELGD) != 0) + if ((tls_mask & TLS_GDIE) != 0) { /* IE */ r_type = R_PPC64_NONE; @@ -14636,16 +14901,27 @@ ppc64_elf_relocate_section (bfd *output_bfd, r_symndx = toc_symndx; rel->r_addend = toc_addend; } - r_type = R_PPC64_TPREL16_LO; - rel->r_offset = offset + d_offset; - insn2 = 0x38630000; /* addi 3,3,0 */ + if (r_type1 == R_PPC64_REL24_NOTOC + || r_type1 == R_PPC64_PLTCALL_NOTOC) + { + r_type = R_PPC64_NONE; + insn2 = NOP; + } + else + { + rel->r_offset = offset + d_offset; + r_type = R_PPC64_TPREL16_LO; + insn2 = 0x38630000; /* addi 3,3,0 */ + } } rel->r_info = ELF64_R_INFO (r_symndx, r_type); /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (offset == rel[1].r_offset); rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); bfd_put_32 (input_bfd, insn2, contents + offset); - if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) + if ((tls_mask & TLS_GDIE) == 0 + && toc_symndx != 0 + && r_type != R_PPC64_NONE) goto again; } break; @@ -14671,30 +14947,27 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL) bfd_put_32 (output_bfd, NOP, contents + offset + 4); - if (toc_symndx) - sec = local_sections[toc_symndx]; - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); - - r_type = R_PPC64_TPREL16_LO; + if (r_type1 == R_PPC64_REL24_NOTOC + || r_type1 == R_PPC64_PLTCALL_NOTOC) + { + r_type = R_PPC64_NONE; + insn2 = NOP; + } + else + { + rel->r_offset = offset + d_offset; + r_symndx = STN_UNDEF; + r_type = R_PPC64_TPREL16_LO; + rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; + insn2 = 0x38630000; /* addi 3,3,0 */ + } rel->r_info = ELF64_R_INFO (r_symndx, r_type); - rel->r_offset = offset + d_offset; /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (offset == rel[1].r_offset); rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - insn2 = 0x38630000; /* addi 3,3,0 */ bfd_put_32 (input_bfd, insn2, contents + offset); - goto again; + if (r_type != R_PPC64_NONE) + goto again; } break; @@ -14706,7 +14979,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if ((tls_mask & TLS_GD) == 0) { rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE); - if ((tls_mask & TLS_TPRELGD) != 0) + if ((tls_mask & TLS_GDIE) != 0) r_type = R_PPC64_TPREL64; else { @@ -15162,7 +15435,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && SYMBOL_REFERENCES_LOCAL (info, &h->elf)) { insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */) { insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3)); @@ -15179,14 +15452,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, && SYMBOL_REFERENCES_LOCAL (info, &h->elf)) { insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26 | 0x3)) == 58u << 26 /* ld */) + if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */) { insn += (14u << 26) - (58u << 26); bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3)); r_type = R_PPC64_TOC16_LO; rel->r_info = ELF64_R_INFO (r_symndx, r_type); } - else if ((insn & (0x3f << 26)) == 15u << 26 /* addis */) + else if ((insn & (0x3fu << 26)) == 15u << 26 /* addis */) { r_type = R_PPC64_TOC16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -15243,18 +15516,29 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (off2 + 4 <= input_section->size) { uint64_t pinsn2; + bfd_signed_vma addend_off; pinsn2 = bfd_get_32 (input_bfd, contents + off2); pinsn2 <<= 32; if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) - break; - if (xlate_pcrel_opt (&pinsn, &pinsn2)) { + if (off2 + 8 > input_section->size) + break; + pinsn2 |= bfd_get_32 (input_bfd, + contents + off2 + 4); + } + if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off)) + { + addend += addend_off; + rel->r_addend = addend; bfd_put_32 (input_bfd, pinsn >> 32, contents + offset); bfd_put_32 (input_bfd, pinsn, contents + offset + 4); bfd_put_32 (input_bfd, pinsn2 >> 32, contents + off2); + if ((pinsn2 & (63ULL << 58)) == 1ULL << 58) + bfd_put_32 (input_bfd, pinsn2, + contents + off2 + 4); } } } @@ -15263,7 +15547,6 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; } - /* Set `addend'. */ tls_type = 0; save_unresolved_reloc = unresolved_reloc; switch (r_type) @@ -15296,6 +15579,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD34: tls_type = TLS_TLS | TLS_GD; goto dogot; @@ -15303,6 +15587,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD34: tls_type = TLS_TLS | TLS_LD; goto dogot; @@ -15310,6 +15595,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_TPREL34: tls_type = TLS_TLS | TLS_TPREL; goto dogot; @@ -15317,6 +15603,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_GOT_DTPREL16_LO_DS: case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL34: tls_type = TLS_TLS | TLS_DTPREL; goto dogot; @@ -15336,14 +15623,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma off; unsigned long indx = 0; struct got_entry *ent; - bfd_vma sym_addend = orig_rel.r_addend; - - if (r_type == R_PPC64_GOT_PCREL34) - sym_addend = 0; if (tls_type == (TLS_TLS | TLS_LD) - && (h == NULL - || !h->elf.def_dynamic)) + && SYMBOL_REFERENCES_LOCAL (info, &h->elf)) ent = ppc64_tlsld_got (input_bfd); else { @@ -15373,7 +15655,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } for (; ent != NULL; ent = ent->next) - if (ent->addend == sym_addend + if (ent->addend == orig_rel.r_addend && ent->owner == input_bfd && ent->tls_type == tls_type) break; @@ -15418,10 +15700,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, else if (indx != 0 || (bfd_link_pic (info) && (h == NULL - || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf) - || (tls_type == (TLS_TLS | TLS_LD) - && !h->elf.def_dynamic)) - && !(tls_type == (TLS_TLS | TLS_TPREL) + || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)) + && !(tls_type != 0 && bfd_link_executable (info) && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))) relgot = ppc64_elf_tdata (ent->owner)->relgot; @@ -15430,7 +15710,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, outrel.r_offset = (got->output_section->vma + got->output_offset + off); - outrel.r_addend = sym_addend; + outrel.r_addend = orig_rel.r_addend; if (tls_type & (TLS_LD | TLS_GD)) { outrel.r_addend = 0; @@ -15443,7 +15723,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); outrel.r_offset += 8; - outrel.r_addend = sym_addend; + outrel.r_addend = orig_rel.r_addend; outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64); } @@ -15489,7 +15769,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, emitting a reloc. */ else { - relocation += sym_addend; + relocation += orig_rel.r_addend; if (tls_type != 0) { if (htab->elf.tls_sec == NULL) @@ -15520,7 +15800,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, abort (); relocation = got->output_section->vma + got->output_offset + off; - if (r_type != R_PPC64_GOT_PCREL34) + addend = 0; + if (!(r_type == R_PPC64_GOT_PCREL34 + || r_type == R_PPC64_GOT_TLSGD34 + || r_type == R_PPC64_GOT_TLSLD34 + || r_type == R_PPC64_GOT_TPREL34 + || r_type == R_PPC64_GOT_DTPREL34)) addend = -(TOCstart + htab->sec_info[input_section->id].toc_off); } break; @@ -15553,15 +15838,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (plt_list) { struct plt_entry *ent; - bfd_vma sym_addend = orig_rel.r_addend; - - if (r_type == R_PPC64_PLT_PCREL34 - || r_type == R_PPC64_PLT_PCREL34_NOTOC) - sym_addend = 0; for (ent = *plt_list; ent != NULL; ent = ent->next) if (ent->plt.offset != (bfd_vma) -1 - && ent->addend == sym_addend) + && ent->addend == orig_rel.r_addend) { asection *plt; bfd_vma got; @@ -15590,9 +15870,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, + htab->sec_info[input_section->id].toc_off); relocation -= got; } - if (r_type != R_PPC64_PLT_PCREL34 - && r_type != R_PPC64_PLT_PCREL34_NOTOC) - addend = 0; + addend = 0; unresolved_reloc = FALSE; break; } @@ -15624,6 +15902,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOC16_LO_DS: case R_PPC64_TOC16_HA: addend -= TOCstart + htab->sec_info[input_section->id].toc_off; + if (h != NULL) + goto dodyn; break; /* Relocate against the beginning of the section. */ @@ -15673,6 +15953,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: + case R_PPC64_TPREL34: if (h != NULL && h->elf.root.type == bfd_link_hash_undefweak && h->elf.dynindx == -1) @@ -15708,6 +15989,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_HIGHERA: case R_PPC64_DTPREL16_HIGHEST: case R_PPC64_DTPREL16_HIGHESTA: + case R_PPC64_DTPREL34: if (htab->elf.tls_sec != NULL) addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; @@ -15891,21 +16173,38 @@ ppc64_elf_relocate_section (bfd *output_bfd, } else { - asection *osec; - - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; + asection *osec = sec->output_section; - if (indx == 0) + if ((osec->flags & SEC_THREAD_LOCAL) != 0) + { + /* TLS symbol values are relative to the + TLS segment. Dynamic relocations for + local TLS symbols therefore can't be + reduced to a relocation against their + section symbol because it holds the + address of the section, not a value + relative to the TLS segment. We could + change the .tdata dynamic section symbol + to be zero value but STN_UNDEF works + and is used elsewhere, eg. for TPREL64 + GOT relocs against local TLS symbols. */ + osec = htab->elf.tls_sec; + indx = 0; + } + else { - if ((osec->flags & SEC_READONLY) == 0 - && htab->elf.data_index_section != NULL) - osec = htab->elf.data_index_section; - else - osec = htab->elf.text_index_section; indx = elf_section_data (osec)->dynindx; + if (indx == 0) + { + if ((osec->flags & SEC_READONLY) == 0 + && htab->elf.data_index_section != NULL) + osec = htab->elf.data_index_section; + else + osec = htab->elf.text_index_section; + indx = elf_section_data (osec)->dynindx; + } + BFD_ASSERT (indx != 0); } - BFD_ASSERT (indx != 0); /* We are turning this relocation into one against a section symbol, so subtract out @@ -15940,6 +16239,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + if (!warned_dynamic + && !ppc64_glibc_dynamic_reloc (ELF64_R_TYPE (outrel.r_info))) + { + info->callbacks->einfo + /* xgettext:c-format */ + (_("%X%P: %pB: %s against %pT " + "is not supported by glibc as a dynamic relocation\n"), + input_bfd, + ppc64_elf_howto_table[ELF64_R_TYPE (outrel.r_info)]->name, + sym_name); + warned_dynamic = TRUE; + } + /* If this reloc is against an external symbol, it will be computed at runtime, so there's no need to do anything now. However, for the sake of prelink ensure @@ -16107,10 +16419,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, { bfd_byte *p = contents + (rel->r_offset & ~3); insn = bfd_get_32 (input_bfd, p); - if ((insn & (0x3f << 26)) == 12u << 26 /* addic */) + if ((insn & (0x3fu << 26)) == 12u << 26 /* addic */) { /* Transform addic to addi when we change reg. */ - insn &= ~((0x3f << 26) | (0x1f << 16)); + insn &= ~((0x3fu << 26) | (0x1f << 16)); insn |= (14u << 26) | (2 << 16); } else @@ -16127,7 +16439,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { bfd_byte *p = contents + (rel->r_offset & ~3); insn = bfd_get_32 (input_bfd, p); - if ((insn & ((0x3f << 26) | 0x1f << 16)) + if ((insn & ((0x3fu << 26) | 0x1f << 16)) != ((15u << 26) | (13 << 16)) /* addis rt,13,imm */) /* xgettext:c-format */ info->callbacks->minfo @@ -16236,8 +16548,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, forms of all the _DS relocs bloats all reloc switches in this file. It doesn't make much sense to use these relocs in data, so testing the insn should be safe. */ - if ((insn & (0x3f << 26)) == (56u << 26) - || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1)) + if ((insn & (0x3fu << 26)) == (56u << 26) + || ((insn & (0x3fu << 26)) == (61u << 26) && (insn & 3) == 1)) mask = 15; relocation += addend; addend = insn & (mask ^ 3); @@ -16286,15 +16598,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, enum complain_overflow complain = complain_overflow_signed; insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) + if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */) complain = complain_overflow_bitfield; else if (howto->rightshift == 0 - ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ - || (insn & (0x3f << 26)) == 24u << 26 /* ori */ - || (insn & (0x3f << 26)) == 26u << 26 /* xori */) - : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ - || (insn & (0x3f << 26)) == 25u << 26 /* oris */ - || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) + ? ((insn & (0x3fu << 26)) == 28u << 26 /* andi */ + || (insn & (0x3fu << 26)) == 24u << 26 /* ori */ + || (insn & (0x3fu << 26)) == 26u << 26 /* xori */) + : ((insn & (0x3fu << 26)) == 29u << 26 /* andis */ + || (insn & (0x3fu << 26)) == 25u << 26 /* oris */ + || (insn & (0x3fu << 26)) == 27u << 26 /* xoris */)) complain = complain_overflow_unsigned; if (howto->complain_on_overflow != complain) { @@ -16313,6 +16625,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_D34_HA30: case R_PPC64_PCREL34: case R_PPC64_GOT_PCREL34: + case R_PPC64_TPREL34: + case R_PPC64_DTPREL34: + case R_PPC64_GOT_TLSGD34: + case R_PPC64_GOT_TLSLD34: + case R_PPC64_GOT_TPREL34: + case R_PPC64_GOT_DTPREL34: case R_PPC64_PLT_PCREL34: case R_PPC64_PLT_PCREL34_NOTOC: case R_PPC64_D28: @@ -16532,18 +16850,18 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, break; } - if (h->needs_copy) + if (h->needs_copy + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section == htab->elf.sdynbss + || h->root.u.def.section == htab->elf.sdynrelro)) { /* This symbol needs a copy reloc. Set it up. */ Elf_Internal_Rela rela; asection *srel; bfd_byte *loc; - if (h->dynindx == -1 - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - || htab->elf.srelbss == NULL - || htab->elf.sreldynrelro == NULL) + if (h->dynindx == -1) abort (); rela.r_offset = (h->root.u.def.value