diff options
author | David Carlton <carlton@bactrian.org> | 2003-03-06 00:56:43 +0000 |
---|---|---|
committer | David Carlton <carlton@bactrian.org> | 2003-03-06 00:56:43 +0000 |
commit | 7e08d3087ba5fdeb658bcd13d333082efce78257 (patch) | |
tree | 4301ea268ab39b53f7243453399615ac9cc0fdb4 /bfd/elf64-ppc.c | |
parent | 0c40460023b3ee8a5b9b37f5bedd604f482f4963 (diff) | |
download | gdb-7e08d3087ba5fdeb658bcd13d333082efce78257.tar.gz |
2003-03-05 David Carlton <carlton@math.stanford.edu>
* Merge with mainline. Tag is carlton_dictionary-20030305-merge.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 1048 |
1 files changed, 567 insertions, 481 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index b86bb858caf..23d95d512e4 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3,21 +3,21 @@ Written by Linus Nordberg, Swox AB <info@swox.com>, based on elf32-ppc.c by Ian Lance Taylor. -This file is part of BFD, the Binary File Descriptor library. + This file is part of BFD, the Binary File Descriptor library. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file is based on the 64-bit PowerPC ELF ABI. It is also based on the file elf32-ppc.c. */ @@ -2503,14 +2503,18 @@ struct got_entry { struct got_entry *next; + /* The symbol addend that we'll be placing in the GOT. */ bfd_vma addend; + /* Reference count until size_dynamic_sections, GOT offset thereafter. */ union { bfd_signed_vma refcount; bfd_vma offset; } got; + /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD, + TLS_TPREL or TLS_DTPREL for tls entries. */ char tls_type; }; @@ -2529,13 +2533,20 @@ struct plt_entry }; /* Of those relocs that might be copied as dynamic relocs, this macro - selects those that must be copied when linking a shared library. */ + selects those that must be copied when linking a shared library, + even when the symbol is local. */ #define MUST_BE_DYN_RELOC(RTYPE) \ ((RTYPE) != R_PPC64_REL32 \ && (RTYPE) != R_PPC64_REL64 \ && (RTYPE) != R_PPC64_REL30) +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + /* Section name for stubs is the associated section name plus this string. */ #define STUB_SUFFIX ".stub" @@ -2633,14 +2644,21 @@ struct ppc_link_hash_entry unsigned int is_entry:1; /* Contexts in which symbol is used in the GOT (or TOC). - Linker optimization will result in various transformations. */ -#define TLS_TLS 1 /* Any TLS reloc. */ -#define TLS_GD_LD 2 /* GD or LD reloc requiring 2 got slots. */ -#define TLS_LD 4 /* LD reloc. */ -#define TLS_TPREL 8 /* TPREL reloc, => IE. */ -#define TLS_DTPREL 16 /* DTPREL reloc, => LD. */ -#define TLS_EXPLICIT 32 /* Marks TOC section relocs. */ - char tls_type; + TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the + corresponding relocs are encountered during check_relocs. + tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to + indicate the corresponding GOT entry type is not needed. + 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. */ +#define TLS_GD 1 /* GD reloc. */ +#define TLS_LD 2 /* LD reloc. */ +#define TLS_TPREL 4 /* TPREL reloc, => IE. */ +#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ +#define TLS_TLS 16 /* Any TLS reloc. */ +#define TLS_EXPLICIT 32 /* Marks TOC section TLS relocs. */ +#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */ + char tls_mask; }; /* ppc64 ELF linker hash table. */ @@ -2767,7 +2785,7 @@ static void ppc64_elf_hide_symbol static bfd_boolean get_sym_h PARAMS ((struct elf_link_hash_entry **, Elf_Internal_Sym **, asection **, char **, Elf_Internal_Sym **, unsigned long, bfd *)); -static bfd_boolean get_tls_type +static int get_tls_mask PARAMS ((char **, Elf_Internal_Sym **, const Elf_Internal_Rela *, bfd *)); static bfd_boolean allocate_dynrelocs PARAMS ((struct elf_link_hash_entry *, PTR)); @@ -2909,7 +2927,7 @@ link_hash_newfunc (entry, table, string) eh->is_func = 0; eh->is_func_descriptor = 0; eh->is_entry = 0; - eh->tls_type = 0; + eh->tls_mask = 0; } return entry; @@ -2957,13 +2975,20 @@ ppc64_elf_link_hash_table_create (abfd) htab->sbrlt = NULL; htab->srelbrlt = NULL; htab->tls_sec = NULL; + htab->tls_get_addr = NULL; htab->tlsld_got.refcount = 0; htab->stub_error = 0; htab->has_14bit_branch = 0; htab->have_undefweak = 0; htab->stub_iteration = 0; htab->sym_sec.abfd = NULL; + /* Initializing two fields of the union is just cosmetic. We really + only care about glist, but when compiled on a 32-bit host the + bfd_vma fields are larger. Setting the bfd_vma to zero makes + debugger inspection of these fields look nicer. */ + htab->elf.init_refcount.refcount = 0; htab->elf.init_refcount.glist = NULL; + htab->elf.init_offset.offset = 0; htab->elf.init_offset.glist = NULL; return &htab->elf.root; @@ -3289,6 +3314,7 @@ ppc64_elf_copy_indirect_symbol (bed, dir, ind) edir->is_func |= eind->is_func; edir->is_func_descriptor |= eind->is_func_descriptor; edir->is_entry |= eind->is_entry; + edir->tls_mask |= eind->tls_mask; /* Copy down any references that we may have already seen to the symbol which just became indirect. */ @@ -3404,13 +3430,13 @@ update_local_sym_info (abfd, symtab_hdr, r_symndx, r_addend, tls_type) int tls_type; { struct got_entry **local_got_ents = elf_local_got_ents (abfd); - char *local_got_tls_types; + char *local_got_tls_masks; if (local_got_ents == NULL) { bfd_size_type size = symtab_hdr->sh_info; - size *= sizeof (*local_got_ents) + sizeof (char); + size *= sizeof (*local_got_ents) + sizeof (*local_got_tls_masks); local_got_ents = (struct got_entry **) bfd_zalloc (abfd, size); if (local_got_ents == NULL) return FALSE; @@ -3439,8 +3465,8 @@ update_local_sym_info (abfd, symtab_hdr, r_symndx, r_addend, tls_type) ent->got.refcount += 1; } - local_got_tls_types = (char *) (local_got_ents + symtab_hdr->sh_info); - local_got_tls_types[r_symndx] |= tls_type; + local_got_tls_masks = (char *) (local_got_ents + symtab_hdr->sh_info); + local_got_tls_masks[r_symndx] |= tls_type; return TRUE; } @@ -3556,14 +3582,14 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: htab->tlsld_got.refcount += 1; - tls_type = TLS_TLS | TLS_GD_LD | TLS_LD; + tls_type = TLS_TLS | TLS_LD; goto dogottls; case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD_LD; + tls_type = TLS_TLS | TLS_GD; goto dogottls; case R_PPC64_GOT_TPREL16_DS: @@ -3618,7 +3644,7 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) eh->elf.got.glist = ent; } ent->got.refcount += 1; - eh->tls_type |= tls_type; + eh->tls_mask |= tls_type; } else /* This is a global offset table entry for a local symbol. */ @@ -3709,7 +3735,10 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) return FALSE; if (h == htab->tls_get_addr) sec->has_tls_reloc = 1; - else if (strcmp (h->root.root.string, ".__tls_get_addr") == 0) + else if ((strncmp (h->root.root.string, ".__tls_get_addr", 15) + == 0) + && (h->root.root.string[15] == 0 + || h->root.root.string[15] == '@')) { htab->tls_get_addr = h; sec->has_tls_reloc = 1; @@ -3727,9 +3756,9 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) if (rel + 1 < rel_end && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) && rel[1].r_offset == rel->r_offset + 8) - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD; + tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD; else - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD | TLS_LD; + tls_type = TLS_EXPLICIT | TLS_TLS | TLS_LD; goto dotlstoc; case R_PPC64_DTPREL64: @@ -3747,7 +3776,7 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) { struct ppc_link_hash_entry *eh; eh = (struct ppc_link_hash_entry *) h; - eh->tls_type |= tls_type; + eh->tls_mask |= tls_type; } else if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, @@ -3756,7 +3785,8 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) if (ppc64_elf_section_data (sec)->t_symndx == NULL) { - bfd_size_type amt = sec->_raw_size * sizeof (unsigned) / 8; + /* One extra to simplify get_tls_mask. */ + bfd_size_type amt = sec->_raw_size * sizeof (unsigned) / 8 + 1; ppc64_elf_section_data (sec)->t_symndx = (unsigned *) bfd_zalloc (abfd, amt); if (ppc64_elf_section_data (sec)->t_symndx == NULL) @@ -3764,6 +3794,13 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) } BFD_ASSERT (rel->r_offset % 8 == 0); ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8] = r_symndx; + + /* Mark the second slot of a GD or LD entry. + -1 to indicate GD and -2 to indicate LD. */ + if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) + ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8 + 1] = -1; + else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD)) + ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8 + 1] = -2; goto dodyn; case R_PPC64_TPREL16: @@ -3844,6 +3881,10 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) if (NO_OPD_RELOCS && opd_sym_map != NULL) break; + /* Don't propagate relocs that the dynamic linker won't relocate. */ + if ((sec->flags & SEC_ALLOC) == 0) + break; + /* If we are creating a shared library, and this is a reloc against a global symbol, or a non PC relative reloc against a local symbol, then we need to copy the reloc @@ -3856,7 +3897,7 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) later (it is never cleared). In case of a weak definition, DEF_REGULAR may be cleared later by a strong definition in a shared library. We account for that possibility below by - storing information in the relocs_copied field of the hash + storing information in the dyn_relocs field of the hash table entry. A similar situation occurs when creating shared libraries and symbol visibility changes render the symbol local. @@ -3867,15 +3908,14 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs) symbol. */ dodyn: if ((info->shared - && (sec->flags & SEC_ALLOC) != 0 && (MUST_BE_DYN_RELOC (r_type) || (h != NULL && (! info->symbolic || h->root.type == bfd_link_hash_defweak || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) - || (!info->shared - && (sec->flags & SEC_ALLOC) != 0 + || (ELIMINATE_COPY_RELOCS + && !info->shared && h != NULL && (h->root.type == bfd_link_hash_defweak || (h->elf_link_hash_flags @@ -4078,11 +4118,29 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs) { unsigned long r_symndx; enum elf_ppc64_reloc_type r_type; - struct elf_link_hash_entry *h; + struct elf_link_hash_entry *h = NULL; char tls_type = 0; r_symndx = ELF64_R_SYM (rel->r_info); r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + struct ppc_link_hash_entry *eh; + struct ppc_dyn_relocs **pp; + struct ppc_dyn_relocs *p; + + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + eh = (struct ppc_link_hash_entry *) h; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + /* Everything must go for SEC. */ + *pp = p->next; + break; + } + } + switch (r_type) { case R_PPC64_GOT_TLSLD16: @@ -4090,14 +4148,14 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs) case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: htab->tlsld_got.refcount -= 1; - tls_type = TLS_TLS | TLS_GD_LD | TLS_LD; + tls_type = TLS_TLS | TLS_LD; goto dogot; case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD_LD; + tls_type = TLS_TLS | TLS_GD; goto dogot; case R_PPC64_GOT_TPREL16_DS: @@ -4124,11 +4182,8 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs) { struct got_entry *ent; - if (r_symndx >= symtab_hdr->sh_info) - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - ent = h->got.glist; - } + if (h != NULL) + ent = h->got.glist; else ent = local_got_ents[r_symndx]; @@ -4152,11 +4207,10 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs) case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: - if (r_symndx >= symtab_hdr->sh_info) + if (h != NULL) { struct plt_entry *ent; - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; for (ent = h->plt.plist; ent != NULL; ent = ent->next) if (ent->addend == rel->r_addend) break; @@ -4167,73 +4221,6 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs) } break; - case R_PPC64_REL30: - case R_PPC64_REL32: - case R_PPC64_REL64: - if (r_symndx >= symtab_hdr->sh_info) - { - struct ppc_link_hash_entry *eh; - struct ppc_dyn_relocs **pp; - struct ppc_dyn_relocs *p; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - eh = (struct ppc_link_hash_entry *) h; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) - if (p->sec == sec) - { - p->pc_count -= 1; - p->count -= 1; - if (p->count == 0) - *pp = p->next; - break; - } - } - break; - - case R_PPC64_DTPMOD64: - case R_PPC64_DTPREL64: - case R_PPC64_TPREL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR16: - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HI: - case R_PPC64_ADDR16_HIGHER: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHEST: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_ADDR16_LO: - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_ADDR24: - case R_PPC64_ADDR32: - case R_PPC64_ADDR64: - case R_PPC64_UADDR16: - case R_PPC64_UADDR32: - case R_PPC64_UADDR64: - case R_PPC64_TOC: - if (r_symndx >= symtab_hdr->sh_info) - { - struct ppc_link_hash_entry *eh; - struct ppc_dyn_relocs **pp; - struct ppc_dyn_relocs *p; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - eh = (struct ppc_link_hash_entry *) h; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) - if (p->sec == sec) - { - p->count -= 1; - if (p->count == 0) - *pp = p->next; - break; - } - } - break; - default: break; } @@ -4492,8 +4479,6 @@ ppc64_elf_adjust_dynamic_symbol (info, h) struct elf_link_hash_entry *h; { struct ppc_link_hash_table *htab; - struct ppc_link_hash_entry * eh; - struct ppc_dyn_relocs *p; asection *s; unsigned int power_of_two; @@ -4551,20 +4536,26 @@ ppc64_elf_adjust_dynamic_symbol (info, h) if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0) return TRUE; - eh = (struct ppc_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) + if (ELIMINATE_COPY_RELOCS) { - s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - break; - } + struct ppc_link_hash_entry * eh; + struct ppc_dyn_relocs *p; - /* 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. */ - if (p == NULL) - { - h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; - return TRUE; + eh = (struct ppc_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & SEC_READONLY) != 0) + break; + } + + /* 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. */ + if (p == NULL) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + return TRUE; + } } /* We must allocate the symbol in our .dynbss section, which will @@ -4672,11 +4663,11 @@ ppc64_elf_hide_symbol (info, h, force_local) } static bfd_boolean -get_sym_h (hp, symp, symsecp, tlstypep, locsymsp, r_symndx, ibfd) +get_sym_h (hp, symp, symsecp, tls_maskp, locsymsp, r_symndx, ibfd) struct elf_link_hash_entry **hp; Elf_Internal_Sym **symp; asection **symsecp; - char **tlstypep; + char **tls_maskp; Elf_Internal_Sym **locsymsp; unsigned long r_symndx; bfd *ibfd; @@ -4708,12 +4699,12 @@ get_sym_h (hp, symp, symsecp, tlstypep, locsymsp, r_symndx, ibfd) *symsecp = symsec; } - if (tlstypep != NULL) + if (tls_maskp != NULL) { struct ppc_link_hash_entry *eh; eh = (struct ppc_link_hash_entry *) h; - *tlstypep = &eh->tls_type; + *tls_maskp = &eh->tls_mask; } } else @@ -4750,45 +4741,50 @@ get_sym_h (hp, symp, symsecp, tlstypep, locsymsp, r_symndx, ibfd) *symsecp = symsec; } - if (tlstypep != NULL) + if (tls_maskp != NULL) { struct got_entry **lgot_ents; - char *tlstype; + char *tls_mask; - tlstype = NULL; + tls_mask = NULL; lgot_ents = elf_local_got_ents (ibfd); if (lgot_ents != NULL) { - char *lgot_types = (char *) (lgot_ents + symtab_hdr->sh_info); - tlstype = &lgot_types[r_symndx]; + char *lgot_masks = (char *) (lgot_ents + symtab_hdr->sh_info); + tls_mask = &lgot_masks[r_symndx]; } - *tlstypep = tlstype; + *tls_maskp = tls_mask; } } return TRUE; } -static bfd_boolean -get_tls_type (tls_type, locsymsp, rel, ibfd) - char **tls_type; +/* Returns TLS_MASKP for the given REL symbol. Function return is 0 on + error, 2 on a toc GD type suitable for optimization, 3 on a toc LD + type suitable for optimization, and 1 otherwise. */ + +static int +get_tls_mask (tls_maskp, locsymsp, rel, ibfd) + char **tls_maskp; Elf_Internal_Sym **locsymsp; const Elf_Internal_Rela *rel; bfd *ibfd; { unsigned long r_symndx; + unsigned int next_r; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; bfd_vma off; r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sec, tls_type, locsymsp, r_symndx, ibfd)) - return FALSE; + if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) + return 0; - if ((*tls_type != NULL && **tls_type != 0) + if ((*tls_maskp != NULL && **tls_maskp != 0) || sec == NULL || ppc64_elf_section_data (sec)->t_symndx == NULL) - return TRUE; + return 1; /* Look inside a TOC section too. */ if (h != NULL) @@ -4801,7 +4797,21 @@ get_tls_type (tls_type, locsymsp, rel, ibfd) off += rel->r_addend; BFD_ASSERT (off % 8 == 0); r_symndx = ppc64_elf_section_data (sec)->t_symndx[off / 8]; - return get_sym_h (&h, &sym, NULL, tls_type, locsymsp, r_symndx, ibfd); + next_r = ppc64_elf_section_data (sec)->t_symndx[off / 8 + 1]; + if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) + return 0; + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + if (next_r == (unsigned) -1) + return 2; + if (next_r == (unsigned) -2 + && (h == NULL + || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))) + return 3; + } + return 1; } bfd_boolean @@ -5110,39 +5120,58 @@ ppc64_elf_edit_opd (obfd, info) return TRUE; } -/* Run through all the TLS relocs looking for optimization - opportunities. The linker has been hacked (see ppc64elf.em) to do - a preliminary section layout so that we know the TLS segment - offsets. We can't optimize earlier because some optimizations need - to know the tp offset, and we need to optimize before allocating - dynamic relocations. */ +/* Set htab->tls_sec. */ bfd_boolean -ppc64_elf_tls_optimize (obfd, info) +ppc64_elf_tls_setup (obfd, info) bfd *obfd; struct bfd_link_info *info; { asection *tls; - bfd *ibfd; - asection *sec; struct ppc_link_hash_table *htab; - if (info->relocateable) - return TRUE; - for (tls = obfd->sections; tls != NULL; tls = tls->next) if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) == (SEC_THREAD_LOCAL | SEC_LOAD)) break; - if (tls == NULL) - return TRUE; htab = ppc_hash_table (info); htab->tls_sec = tls; - if (info->shared) + if (htab->tls_get_addr != NULL) + { + struct elf_link_hash_entry *h = htab->tls_get_addr; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + htab->tls_get_addr = h; + } + + return tls != NULL; +} + +/* Run through all the TLS relocs looking for optimization + opportunities. The linker has been hacked (see ppc64elf.em) to do + a preliminary section layout so that we know the TLS segment + offsets. We can't optimize earlier because some optimizations need + to know the tp offset, and we need to optimize before allocating + dynamic relocations. */ + +bfd_boolean +ppc64_elf_tls_optimize (obfd, info) + bfd *obfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + bfd *ibfd; + asection *sec; + struct ppc_link_hash_table *htab; + + if (info->relocateable || info->shared) return TRUE; + htab = ppc_hash_table (info); for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) { Elf_Internal_Sym *locsyms = NULL; @@ -5169,13 +5198,13 @@ ppc64_elf_tls_optimize (obfd, info) struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sym_sec; - char *tls_type; - char tls_set, tls_clear, got_tls_type = 0; + char *tls_mask; + char tls_set, tls_clear, tls_type = 0; bfd_vma value; - bfd_boolean ok_tprel; + bfd_boolean ok_tprel, is_local; r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, &tls_type, &locsyms, + if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, r_symndx, ibfd)) { err_free_rel: @@ -5197,9 +5226,13 @@ ppc64_elf_tls_optimize (obfd, info) } else value = sym->st_value; + ok_tprel = FALSE; - if (sym_sec != NULL && sym_sec->output_section != NULL) + is_local = FALSE; + if (h == NULL + || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)) { + is_local = TRUE; value += sym_sec->output_offset; value += sym_sec->output_section->vma; value -= htab->tls_sec->vma; @@ -5215,16 +5248,17 @@ ppc64_elf_tls_optimize (obfd, info) case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: + /* These relocs should never be against a symbol + defined in a shared lib. Leave them alone if + that turns out to be the case. */ htab->tlsld_got.refcount -= 1; - if (ok_tprel) - /* LD -> LE */ - tls_set = 0; - else - /* We still need a GOT entry as the offset is - too big. ie. LD -> IE. */ - tls_set = TLS_TLS | TLS_TPREL; - tls_clear = TLS_GD_LD; - got_tls_type = TLS_TLS | TLS_GD_LD | TLS_LD; + if (!is_local) + continue; + + /* LD -> LE */ + tls_set = 0; + tls_clear = TLS_LD; + tls_type = TLS_TLS | TLS_LD; expecting_tls_get_addr = 1; break; @@ -5232,21 +5266,14 @@ ppc64_elf_tls_optimize (obfd, info) case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - if (ok_tprel - && (h == NULL - || ((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) != 0 - && ((h->elf_link_hash_flags - & ELF_LINK_FORCED_LOCAL) != 0 - || !info->shared - || info->symbolic)))) + if (ok_tprel) /* GD -> LE */ tls_set = 0; else /* GD -> IE */ - tls_set = TLS_TLS | TLS_TPREL; - tls_clear = TLS_GD_LD; - got_tls_type = TLS_TLS | TLS_GD_LD; + tls_set = TLS_TLS | TLS_TPRELGD; + tls_clear = TLS_GD; + tls_type = TLS_TLS | TLS_GD; expecting_tls_get_addr = 1; break; @@ -5260,7 +5287,7 @@ ppc64_elf_tls_optimize (obfd, info) /* IE -> LE */ tls_set = 0; tls_clear = TLS_TPREL; - got_tls_type = TLS_TLS | TLS_TPREL; + tls_type = TLS_TLS | TLS_TPREL; break; } else @@ -5282,12 +5309,14 @@ ppc64_elf_tls_optimize (obfd, info) { /* Check for toc tls entries. */ char *toc_tls; + int retval; - if (!get_tls_type (&toc_tls, &locsyms, - rel - 1, ibfd)) + retval = get_tls_mask (&toc_tls, &locsyms, + rel - 1, ibfd); + if (retval == 0) goto err_free_rel; if (toc_tls != NULL) - expecting_tls_get_addr = *toc_tls != 0; + expecting_tls_get_addr = retval > 1; } if (expecting_tls_get_addr) @@ -5319,32 +5348,27 @@ ppc64_elf_tls_optimize (obfd, info) case R_PPC64_DTPMOD64: expecting_tls_get_addr = 0; - if ((*tls_type & TLS_LD) == 0) + if (rel + 1 < relend + && (rel[1].r_info + == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) + && rel[1].r_offset == rel->r_offset + 8) { - if ((h == NULL - || ((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) != 0 - && ((h->elf_link_hash_flags - & ELF_LINK_FORCED_LOCAL) != 0 - || !info->shared - || info->symbolic))) - && ok_tprel) + if (ok_tprel) /* GD -> LE */ - tls_set = TLS_EXPLICIT; + tls_set = TLS_EXPLICIT | TLS_GD; else /* GD -> IE */ - tls_set = TLS_EXPLICIT | TLS_TPREL; - tls_clear = TLS_GD_LD; + tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; + tls_clear = TLS_GD; } else { - if (ok_tprel) - /* LD -> LE */ - tls_set = TLS_EXPLICIT; - else - /* LD -> IE */ - tls_set = TLS_EXPLICIT | TLS_TPREL; - tls_clear = TLS_GD_LD; + if (!is_local) + continue; + + /* LD -> LE */ + tls_set = TLS_EXPLICIT; + tls_clear = TLS_LD; } break; @@ -5365,7 +5389,7 @@ ppc64_elf_tls_optimize (obfd, info) for (; ent != NULL; ent = ent->next) if (ent->addend == rel->r_addend - && ent->tls_type == got_tls_type) + && ent->tls_type == tls_type) break; if (ent == NULL) abort (); @@ -5376,8 +5400,6 @@ ppc64_elf_tls_optimize (obfd, info) if (ent->got.refcount > 0) ent->got.refcount -= 1; } - else - ent->tls_type = tls_set; } else if (h != NULL) { @@ -5395,22 +5417,17 @@ ppc64_elf_tls_optimize (obfd, info) /* If we got rid of a DTPMOD/DTPREL reloc pair then we'll lose one or two dyn relocs. */ - if (tls_clear == TLS_GD_LD - && rel + 1 < relend - && (rel[1].r_info - == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) - && rel[1].r_offset == rel->r_offset + 8) - p->count -= 1; - if (tls_set == TLS_EXPLICIT) + if (tls_set == (TLS_EXPLICIT | TLS_GD)) p->count -= 1; + p->count -= 1; if (p->count == 0) *pp = p->next; break; } } - *tls_type |= tls_set; - *tls_type &= ~tls_clear; + *tls_mask |= tls_set; + *tls_mask &= ~tls_clear; } if (elf_section_data (sec)->relocs != relstart) @@ -5434,9 +5451,9 @@ ppc64_elf_tls_optimize (obfd, info) will be called from elflink.h. If elflink.h doesn't call our finish_dynamic_symbol routine, we'll need to do something about initializing any .plt and .got entries in ppc64_elf_relocate_section. */ -#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ ((DYN) \ - && ((INFO)->shared \ + && ((SHARED) \ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ && ((H)->dynindx != -1 \ || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) @@ -5467,7 +5484,7 @@ allocate_dynrelocs (h, inf) if (htab->elf.dynamic_sections_created && h->dynindx != -1 - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h)) + && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) { struct plt_entry *pent; bfd_boolean doneone = FALSE; @@ -5515,11 +5532,39 @@ allocate_dynrelocs (h, inf) h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; } + 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_TPRELGD) != 0) + for (gent = h->got.glist; gent != NULL; gent = gent->next) + if (gent->got.refcount > 0 + && (gent->tls_type & TLS_GD) != 0) + { + /* This was a GD entry that has been converted to TPREL. If + there happens to be a TPREL entry we can use that one. */ + struct got_entry *ent; + for (ent = h->got.glist; ent != NULL; ent = ent->next) + if (ent->got.refcount > 0 + && (ent->tls_type & TLS_TPREL) != 0 + && ent->addend == gent->addend) + { + gent->got.refcount = 0; + break; + } + + /* If not, then we'll be using our own TPREL entry. */ + if (gent->got.refcount != 0) + gent->tls_type = TLS_TLS | TLS_TPREL; + } + for (gent = h->got.glist; gent != NULL; gent = gent->next) if (gent->got.refcount > 0) { + bfd_boolean dyn; + /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ + Undefined weak syms won't yet be marked as dynamic, + nor will all TLS symbols. */ if (h->dynindx == -1 && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) { @@ -5527,27 +5572,28 @@ allocate_dynrelocs (h, inf) return FALSE; } - if ((gent->tls_type & TLS_LD) != 0) - gent->got.offset = htab->tlsld_got.offset; - else + if ((gent->tls_type & TLS_LD) != 0 + && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)) { - bfd_boolean dyn; - - s = htab->sgot; - gent->got.offset = s->_raw_size; - s->_raw_size += (gent->tls_type & TLS_GD_LD) != 0 ? 16 : 8; - dyn = htab->elf.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)) - htab->srelgot->_raw_size - += ((gent->tls_type & TLS_GD_LD) != 0 - ? 2 * sizeof (Elf64_External_Rela) - : sizeof (Elf64_External_Rela)); + gent->got.offset = htab->tlsld_got.offset; + continue; } + + s = htab->sgot; + gent->got.offset = s->_raw_size; + s->_raw_size + += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8; + dyn = htab->elf.dynamic_sections_created; + if (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) + htab->srelgot->_raw_size + += (gent->tls_type & eh->tls_mask & TLS_GD + ? 2 * sizeof (Elf64_External_Rela) + : sizeof (Elf64_External_Rela)); } else gent->got.offset = (bfd_vma) -1; - eh = (struct ppc_link_hash_entry *) h; if (eh->dyn_relocs == NULL) return TRUE; @@ -5576,18 +5622,15 @@ allocate_dynrelocs (h, inf) } } } - else + else if (ELIMINATE_COPY_RELOCS) { /* For the non-shared case, discard space for relocs against symbols which turn out to need copy relocs or are not dynamic. */ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 - && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) - || (htab->elf.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) { /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -5697,6 +5740,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info) { struct got_entry **lgot_ents; struct got_entry **end_lgot_ents; + char *lgot_masks; bfd_size_type locsymcount; Elf_Internal_Shdr *symtab_hdr; asection *srel; @@ -5738,16 +5782,17 @@ ppc64_elf_size_dynamic_sections (output_bfd, info) symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; locsymcount = symtab_hdr->sh_info; end_lgot_ents = lgot_ents + locsymcount; + lgot_masks = (char *) end_lgot_ents; s = htab->sgot; srel = htab->srelgot; - for (; lgot_ents < end_lgot_ents; ++lgot_ents) + for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks) { struct got_entry *ent; for (ent = *lgot_ents; ent != NULL; ent = ent->next) if (ent->got.refcount > 0) { - if ((ent->tls_type & TLS_LD) != 0) + if ((ent->tls_type & *lgot_masks & TLS_LD) != 0) { if (htab->tlsld_got.offset == (bfd_vma) -1) { @@ -5761,7 +5806,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info) else { ent->got.offset = s->_raw_size; - if ((ent->tls_type & TLS_GD_LD) != 0) + if ((ent->tls_type & *lgot_masks & TLS_GD) != 0) { s->_raw_size += 16; if (info->shared) @@ -6190,13 +6235,14 @@ ppc_size_one_stub (gen_entry, in_arg) if (stub_entry->stub_type == ppc_stub_plt_call) { struct plt_entry *ent; + off = (bfd_vma) -1; for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next) if (ent->addend == stub_entry->addend) { off = ent->plt.offset & ~(bfd_vma) 1; break; } - if (ent == NULL) + if (off >= (bfd_vma) -2) abort (); off += (htab->splt->output_offset + htab->splt->output_section->vma @@ -6376,12 +6422,15 @@ group_sections (htab, stub_group_size, stubs_always_before_branch) asection *curr; asection *prev; bfd_size_type total; + bfd_boolean big_sec; curr = tail; if (tail->_cooked_size) total = tail->_cooked_size; else total = tail->_raw_size; + big_sec = total >= stub_group_size; + while ((prev = PREV_SEC (curr)) != NULL && ((total += curr->output_offset - prev->output_offset) < stub_group_size)) @@ -6396,7 +6445,7 @@ group_sections (htab, stub_group_size, stubs_always_before_branch) section size. That's a little tricky, and this way will only break if stubs added make the total size more than 2^25, ie. for the default stub_group_size, if stubs total - more than 2834432 bytes, or over 100000 plt call stubs. */ + more than 2097152 bytes, or nearly 75000 plt call stubs. */ do { prev = PREV_SEC (tail); @@ -6406,8 +6455,11 @@ group_sections (htab, stub_group_size, stubs_always_before_branch) while (tail != curr && (tail = prev) != NULL); /* But wait, there's more! Input sections up to stub_group_size - bytes before the stub section can be handled by it too. */ - if (!stubs_always_before_branch) + bytes before the stub section can be handled by it too. + Don't do this if we have a really large section after the + stubs, as adding more stubs increases the chance that + branches may not reach into the stub section. */ + if (!stubs_always_before_branch && !big_sec) { total = 0; while (prev != NULL @@ -6459,9 +6511,18 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size, if (stub_group_size == 1) { /* Default values. */ - stub_group_size = 30720000; - if (htab->has_14bit_branch) - stub_group_size = 30000; + if (stubs_always_before_branch) + { + stub_group_size = 0x1e00000; + if (htab->has_14bit_branch) + stub_group_size = 0x7800; + } + else + { + stub_group_size = 0x1c00000; + if (htab->has_14bit_branch) + stub_group_size = 0x7000; + } } group_sections (htab, stub_group_size, stubs_always_before_branch); @@ -6603,13 +6664,12 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size, && irela != internal_relocs) { /* Get tls info. */ - char *tls_type; + char *tls_mask; - if (!get_tls_type (&tls_type, &local_syms, + if (!get_tls_mask (&tls_mask, &local_syms, irela - 1, input_bfd)) goto error_ret_free_internal; - if (tls_type != NULL - && (*tls_type & (TLS_TLS | TLS_GD_LD)) == TLS_TLS) + if (*tls_mask != 0) continue; } @@ -6902,7 +6962,6 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; bfd_byte *loc; - unsigned int tls_get_addr_type; struct got_entry **local_got_ents; bfd_vma TOCstart; bfd_boolean ret = TRUE; @@ -6918,27 +6977,12 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, ppc_howto_init (); htab = ppc_hash_table (info); - if (info->shared && (htab->tlsld_got.offset & 1) == 0) - { - outrel.r_offset = (htab->sgot->output_section->vma - + htab->sgot->output_offset - + htab->tlsld_got.offset); - outrel.r_info = ELF64_R_INFO (0, R_PPC64_DTPMOD64); - outrel.r_addend = 0; - - loc = htab->srelgot->contents; - loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - htab->tlsld_got.offset |= 1; - } - local_got_ents = elf_local_got_ents (input_bfd); TOCstart = elf_gp (output_bfd); symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); is_opd = ppc64_elf_section_data (input_section)->opd.adjust != NULL; - tls_get_addr_type = 0; rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) @@ -6952,7 +6996,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, struct elf_link_hash_entry *fdh; const char *sym_name; unsigned long r_symndx; - char tls_type; + char tls_mask, tls_gd, tls_type; bfd_vma relocation; bfd_boolean unresolved_reloc; bfd_boolean warned; @@ -6963,7 +7007,6 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info); r_symndx = ELF64_R_SYM (rel->r_info); - r = bfd_reloc_other; sym = (Elf_Internal_Sym *) 0; sec = (asection *) 0; h = (struct elf_link_hash_entry *) 0; @@ -7019,7 +7062,6 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, else if (h->root.type == bfd_link_hash_undefweak) ; else if (info->shared - && (!info->symbolic || info->allow_shlib_undefined) && !info->no_undefined && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ; @@ -7035,17 +7077,21 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, } } - /* TLS optimizations. */ - tls_type = 0; - if (IS_TLS_RELOC (r_type)) + /* TLS optimizations. Replace instruction sequences and relocs + based on information we collected in tls_optimize. We edit + RELOCS so that --emit-relocs will output something sensible + for the final instruction stream. */ + tls_mask = 0; + tls_gd = 0; + if (IS_PPC64_TLS_RELOC (r_type)) { if (h != NULL) - tls_type = ((struct ppc_link_hash_entry *) h)->tls_type; + tls_mask = ((struct ppc_link_hash_entry *) h)->tls_mask; else if (local_got_ents != NULL) { - char *lgot_types; - lgot_types = (char *) (local_got_ents + symtab_hdr->sh_info); - tls_type = lgot_types[r_symndx]; + char *lgot_masks; + lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info); + tls_mask = lgot_masks[r_symndx]; } } @@ -7064,39 +7110,52 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, switch (r_type) { default: - tls_get_addr_type = 0; break; case R_PPC64_TOC16: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_LO_DS: - tls_get_addr_type = 0; { /* Check for toc tls entries. */ char *toc_tls; + int retval; - if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd)) + retval = get_tls_mask (&toc_tls, &local_syms, rel, input_bfd); + if (retval == 0) return FALSE; if (toc_tls) { - tls_type = *toc_tls; + tls_mask = *toc_tls; if (r_type == R_PPC64_TOC16_DS || r_type == R_PPC64_TOC16_LO_DS) goto toctprel; else - tls_get_addr_type = tls_type; + { + /* If we found a GD reloc pair, then we might be + doing a GD->IE transition. */ + if (retval == 2) + { + tls_gd = TLS_TPRELGD; + if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) + goto tls_get_addr_check; + } + else if (retval == 3) + { + if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) + goto tls_get_addr_check; + } + } } } break; case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_TPREL16_LO_DS: - tls_get_addr_type = 0; toctprel: - if (tls_type != 0 - && (tls_type & TLS_TPREL) == 0) + if (tls_mask != 0 + && (tls_mask & TLS_TPREL) == 0) { bfd_vma insn; insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2); @@ -7109,20 +7168,19 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, break; case R_PPC64_TLS: - tls_get_addr_type = 0; - if (tls_type == 0) + if (tls_mask == 0) { /* Check for toc tls entries. */ char *toc_tls; - if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd)) + if (!get_tls_mask (&toc_tls, &local_syms, rel, input_bfd)) return FALSE; if (toc_tls) - tls_type = *toc_tls; + tls_mask = *toc_tls; } - if (tls_type != 0 - && (tls_type & TLS_TPREL) == 0) + if (tls_mask != 0 + && (tls_mask & TLS_TPREL) == 0) { bfd_vma insn, rtra; insn = bfd_get_32 (output_bfd, contents + rel->r_offset); @@ -7164,130 +7222,162 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, } break; - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: + tls_gd = TLS_TPRELGD; + if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) + goto tls_gdld_hi; + break; + case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - tls_get_addr_type = 0; - if (tls_type != 0 && (tls_type & TLS_GD_LD) == 0) + if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) { - if (r_type == R_PPC64_GOT_TLSGD16_HI - || r_type == R_PPC64_GOT_TLSGD16_HA - || r_type == R_PPC64_GOT_TLSLD16_HI - || r_type == R_PPC64_GOT_TLSLD16_HA) + tls_gdld_hi: + if ((tls_mask & tls_gd) != 0) + r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) + + R_PPC64_GOT_TPREL16_DS); + else { - if ((tls_type & TLS_LD) != 0) - { - bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); - r_type = R_PPC64_NONE; - rel->r_offset -= 2; - } - else - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - break; + bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); + rel->r_offset -= 2; + r_type = R_PPC64_NONE; } - - /* This reloc and its instruction will be replaced so there's - not much point in doing anything more here. We know the - next reloc will be a REL24 to __tls_get_addr, and will - be handled below. */ - tls_get_addr_type = tls_type; - continue; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); } break; - case R_PPC64_REL14: - case R_PPC64_REL14_BRTAKEN: - case R_PPC64_REL14_BRNTAKEN: - case R_PPC64_REL24: - if (h != NULL - && h == htab->tls_get_addr - && tls_get_addr_type != 0 - && (tls_get_addr_type & TLS_GD_LD) == 0) - { - /* Replace the call. */ - bfd_vma insn1, insn2, insn3; - bfd_vma offset = rel->r_offset; + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_LO: + tls_gd = TLS_TPRELGD; + if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) + goto tls_get_addr_check; + break; - insn1 = bfd_get_32 (output_bfd, contents + rel[-1].r_offset - 2); - insn3 = bfd_get_32 (output_bfd, contents + offset + 4); - if (tls_get_addr_type & TLS_TPREL) - { - /* IE */ - insn1 &= (1 << 26) - (1 << 2); - insn1 |= 58 << 26; /* ld */ - insn2 = 0x7c636a14; /* add 3,3,13 */ - /* Fix the relocs for --emit-relocs. */ - r_type = ELF64_R_TYPE (rel[-1].r_info); - if (tls_get_addr_type & TLS_EXPLICIT) - r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; - else - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - rel[-1].r_info - = ELF64_R_INFO (ELF64_R_SYM (rel[-1].r_info), r_type); - rel->r_info = 0; - } - else + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_LO: + if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) + { + tls_get_addr_check: + if (rel + 1 < relend) { - /* LE */ - insn1 = 0x3c6d0000; /* addis 3,13,0 */ - insn2 = 0x38630000; /* addi 3,3,0 */ - if (tls_get_addr_type & TLS_LD) + enum elf_ppc64_reloc_type r_type2; + unsigned long r_symndx2; + struct elf_link_hash_entry *h2; + bfd_vma insn1, insn2, insn3; + bfd_vma offset; + + /* The next instruction should be a call to + __tls_get_addr. Peek at the reloc to be sure. */ + r_type2 + = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel[1].r_info); + r_symndx2 = ELF64_R_SYM (rel[1].r_info); + if (r_symndx2 < symtab_hdr->sh_info + || (r_type2 != R_PPC64_REL14 + && r_type2 != R_PPC64_REL14_BRTAKEN + && r_type2 != R_PPC64_REL14_BRNTAKEN + && r_type2 != R_PPC64_REL24)) + break; + + h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; + while (h2->root.type == bfd_link_hash_indirect + || h2->root.type == bfd_link_hash_warning) + h2 = (struct elf_link_hash_entry *) h2->root.u.i.link; + if (h2 == NULL || h2 != htab->tls_get_addr) + break; + + /* OK, it checks out. Replace the call. */ + offset = rel[1].r_offset; + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - 2); + insn3 = bfd_get_32 (output_bfd, + contents + offset + 4); + if ((tls_mask & tls_gd) != 0) { - r_symndx = 0; - rel[-1].r_addend = htab->tls_sec->vma + DTP_OFFSET; - rel->r_addend = htab->tls_sec->vma + DTP_OFFSET; + /* IE */ + insn1 &= (1 << 26) - (1 << 2); + insn1 |= 58 << 26; /* ld */ + insn2 = 0x7c636a14; /* add 3,3,13 */ + rel[1].r_info = ELF64_R_INFO (r_symndx2, 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 + r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); } else - r_symndx = ELF64_R_SYM (rel[-1].r_info); - rel[-1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_HA); - rel->r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_LO); - rel->r_offset += 2; - } - if (insn3 == NOP - || insn3 == CROR_151515 || insn3 == CROR_313131) - { - insn3 = insn2; - insn2 = NOP; - rel->r_offset += 4; + { + /* LE */ + insn1 = 0x3c6d0000; /* addis 3,13,0 */ + insn2 = 0x38630000; /* addi 3,3,0 */ + if (tls_gd == 0) + { + /* Was an LD reloc. */ + r_symndx = 0; + rel->r_addend = htab->tls_sec->vma + DTP_OFFSET; + rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET; + } + r_type = R_PPC64_TPREL16_HA; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + rel[1].r_info = ELF64_R_INFO (r_symndx, + R_PPC64_TPREL16_LO); + rel[1].r_offset += 2; + } + if (insn3 == NOP + || insn3 == CROR_151515 || insn3 == CROR_313131) + { + insn3 = insn2; + insn2 = NOP; + rel[1].r_offset += 4; + } + bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2); + bfd_put_32 (output_bfd, insn2, contents + offset); + bfd_put_32 (output_bfd, insn3, contents + offset + 4); + if (tls_gd == 0) + { + /* We changed the symbol on an LD reloc. Start over + in order to get h, sym, sec etc. right. */ + rel--; + continue; + } } - bfd_put_32 (output_bfd, insn1, contents + rel[-1].r_offset - 2); - bfd_put_32 (output_bfd, insn2, contents + offset); - bfd_put_32 (output_bfd, insn3, contents + offset + 4); - /* Do the relocs again. */ - rel -= 2; - tls_get_addr_type = 0; - continue; } - tls_get_addr_type = 0; break; case R_PPC64_DTPMOD64: - if ((tls_type & TLS_GD_LD) == 0) + if (rel + 1 < relend + && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) + && rel[1].r_offset == rel->r_offset + 8) { - if ((tls_type & TLS_TPREL) != 0) - r_type = R_PPC64_TPREL64; - else + if ((tls_mask & TLS_GD) == 0) + { + rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE); + if ((tls_mask & TLS_TPRELGD) != 0) + r_type = R_PPC64_TPREL64; + else + { + bfd_put_64 (output_bfd, (bfd_vma) 1, + contents + rel->r_offset); + r_type = R_PPC64_NONE; + } + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + } + } + else + { + if ((tls_mask & TLS_LD) == 0) { bfd_put_64 (output_bfd, (bfd_vma) 1, contents + rel->r_offset); r_type = R_PPC64_NONE; + rel->r_info = ELF64_R_INFO (r_symndx, r_type); } - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - if ((tls_type & TLS_LD) == 0) - rel[1].r_info = 0; } break; case R_PPC64_TPREL64: - if ((tls_type & TLS_TPREL) == 0) + if ((tls_mask & TLS_TPREL) == 0) { r_type = R_PPC64_NONE; rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -7437,14 +7527,14 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD_LD; + tls_type = TLS_TLS | TLS_GD; goto dogot; case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HA: - tls_type = TLS_TLS | TLS_GD_LD | TLS_LD; + tls_type = TLS_TLS | TLS_LD; goto dogot; case R_PPC64_GOT_TPREL16_DS: @@ -7471,57 +7561,64 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, { /* Relocation is to the entry for this symbol in the global offset table. */ - struct got_entry *ent; + bfd_vma *offp; bfd_vma off; - unsigned long indx; + unsigned long indx = 0; if (htab->sgot == NULL) abort (); - if (h != NULL) - ent = h->got.glist; + if (tls_type == (TLS_TLS | TLS_LD) + && (h == NULL + || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC))) + offp = &htab->tlsld_got.offset; else { - if (local_got_ents == NULL) - abort (); - ent = local_got_ents[r_symndx]; - } + struct got_entry *ent; - for (; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->tls_type == tls_type) - break; - if (ent == NULL) - abort (); - - off = ent->got.offset; - indx = 0; - if (h != NULL) - { - bfd_boolean dyn = htab->elf.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h) - || (info->shared - && (info->symbolic - || h->dynindx == -1 - || (h->elf_link_hash_flags - & ELF_LINK_FORCED_LOCAL)) - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR))) - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. */ - ; + if (h != NULL) + { + bfd_boolean dyn = htab->elf.dynamic_sections_created; + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && (info->symbolic + || h->dynindx == -1 + || (h->elf_link_hash_flags + & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR))) + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. */ + ; + else + { + indx = h->dynindx; + unresolved_reloc = FALSE; + } + ent = h->got.glist; + } else { - indx = h->dynindx; - unresolved_reloc = FALSE; + if (local_got_ents == NULL) + abort (); + ent = local_got_ents[r_symndx]; } + + for (; ent != NULL; ent = ent->next) + if (ent->addend == rel->r_addend + && ent->tls_type == tls_type) + break; + if (ent == NULL) + abort (); + offp = &ent->got.offset; } /* The offset must always be a multiple of 8. We use the least significant bit to record whether we have already processed this entry. */ + off = *offp; if ((off & 1) != 0) off &= ~1; else @@ -7529,32 +7626,37 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* Generate relocs for the dynamic linker, except in the case of TLSLD where we'll use one entry per module. */ - if ((info->shared || indx != 0) - && ent->tls_type != (TLS_TLS | TLS_GD_LD | TLS_LD)) + *offp = off | 1; + if (info->shared || indx != 0) { outrel.r_offset = (htab->sgot->output_section->vma + htab->sgot->output_offset + off); - if (ent->tls_type == (TLS_TLS | TLS_GD_LD)) + if (tls_type & (TLS_LD | TLS_GD)) { outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64); outrel.r_addend = 0; - loc = htab->srelgot->contents; - loc += (htab->srelgot->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64); - outrel.r_offset += 8; + if (tls_type == (TLS_TLS | TLS_GD)) + { + loc = htab->srelgot->contents; + loc += (htab->srelgot->reloc_count++ + * sizeof (Elf64_External_Rela)); + bfd_elf64_swap_reloca_out (output_bfd, + &outrel, loc); + outrel.r_info + = ELF64_R_INFO (indx, R_PPC64_DTPREL64); + outrel.r_offset += 8; + } } - else if (ent->tls_type == (TLS_TLS | TLS_DTPREL)) + else if (tls_type == (TLS_TLS | TLS_DTPREL)) outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64); - else if (ent->tls_type == (TLS_TLS | TLS_TPREL)) + else if (tls_type == (TLS_TLS | TLS_TPREL)) outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64); else if (indx == 0) outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE); else outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT); - outrel.r_addend = ent->addend; + outrel.r_addend = rel->r_addend; if (indx == 0) outrel.r_addend += relocation; loc = htab->srelgot->contents; @@ -7565,29 +7667,27 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* Init the .got section contents if we're not emitting a reloc. */ - if (!(info->shared || indx != 0)) + else { - - relocation += ent->addend; - if ((tls_type & TLS_TLS) != 0) + relocation += rel->r_addend; + if (tls_type != 0) { relocation -= htab->tls_sec->vma + DTP_OFFSET; if ((tls_type & TLS_TPREL) != 0) relocation += DTP_OFFSET - TP_OFFSET; } - if ((tls_type & TLS_GD_LD) != 0) + if ((tls_type & TLS_GD) != 0) { - if ((tls_type & TLS_LD) != 0) - relocation = - DTP_OFFSET; bfd_put_64 (output_bfd, relocation, htab->sgot->contents + off + 8); relocation = 1; } + else if (tls_type == (TLS_TLS | TLS_LD)) + relocation = 1; bfd_put_64 (output_bfd, relocation, htab->sgot->contents + off); } - ent->got.offset |= 1; } if (off >= (bfd_vma) -2) @@ -7748,16 +7848,13 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, && (! info->symbolic || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) - || (!info->shared + || (ELIMINATE_COPY_RELOCS + && !info->shared && h != NULL && h->dynindx != -1 && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 - && (((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0) - || h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined))) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) { Elf_Internal_Rela outrel; bfd_boolean skip, relocate; @@ -7871,7 +7968,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, case R_PPC64_RELATIVE: /* We shouldn't ever see these dynamic relocs in relocatable files. */ - /* Fall thru */ + /* Fall through. */ case R_PPC64_PLTGOT16: case R_PPC64_PLTGOT16_DS: @@ -8016,11 +8113,14 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, if (r != bfd_reloc_ok) { - const char *name; - - if (h != NULL) + if (sym_name == NULL) + sym_name = "(null)"; + if (r == bfd_reloc_overflow) { - if (h->root.type == bfd_link_hash_undefweak + if (warned) + continue; + if (h != NULL + && h->root.type == bfd_link_hash_undefweak && ppc64_elf_howto_table[(int) r_type]->pc_relative) { /* Assume this is a call protected by other code that @@ -8032,21 +8132,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, continue; } - name = h->root.root.string; - } - else - { - name = bfd_elf_local_sym_name (input_bfd, sym); - if (name == NULL) - continue; - } - - if (r == bfd_reloc_overflow) - { - if (warned) - continue; if (!((*info->callbacks->reloc_overflow) - (info, name, ppc64_elf_howto_table[(int) r_type]->name, + (info, sym_name, ppc64_elf_howto_table[(int) r_type]->name, rel->r_addend, input_bfd, input_section, rel->r_offset))) return FALSE; } @@ -8056,7 +8143,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section, (_("%s(%s+0x%lx): reloc against `%s': error %d"), bfd_archive_filename (input_bfd), bfd_get_section_name (input_bfd, input_section), - (long) rel->r_offset, name, (int) r); + (long) rel->r_offset, sym_name, (int) r); ret = FALSE; } } @@ -8100,7 +8187,6 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym) /* Create a JMP_SLOT reloc to inform the dynamic linker to fill in the PLT entry. */ - rela.r_offset = (htab->splt->output_section->vma + htab->splt->output_offset + ent->plt.offset); |