PowerPC64 DT_RELR
H.J. Lu
hjl.tools@gmail.com
Tue Jan 18 13:32:37 GMT 2022
On Mon, Jan 17, 2022 at 5:08 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Jan 17, 2022 at 4:54 PM Alan Modra via Binutils
> <binutils@sourceware.org> wrote:
> >
> > PowerPC64 takes a more traditional approach to DT_RELR than x86. Count
> > relative relocs in check_relocs, allocate space for them and output in
> > the usual places but not doing so when enable_dt_relr. DT_RELR is
> > sized in the existing ppc stub relaxation machinery, run via the
> > linker's ldemul_after_allocation hook. DT_RELR is output in the same
> > function that writes ppc stubs, run via ldemul_finish.
> >
> > This support should be considered experimental.
> >
> > bfd/
> > * elf64-ppc.c (struct ppc_local_dyn_relocs): Renamed from
> > ppc_dyn_relocs. Add rel_count field. Update uses.
> > (struct ppc_dyn_relocs): New. Replace all uses of elf_dyn_relocs.
> > (struct ppc_link_hash_table): Add relr_alloc, relr_count and
> > relr_addr.
> > (ppc64_elf_copy_indirect_symbol): Merge rel_count.
> > (ppc64_elf_check_relocs): Init rel_count for global and local syms.
> > (dec_dynrel_count): Change r_info param to reloc pointer. Update
> > all callers. Handle decrementing rel_count.
> > (allocate_got): Don't allocate space for relative relocs when
> > enable_dt_relr.
> > (allocate_dynrelocs): Likewise.
> > (ppc64_elf_size_dynamic_sections): Likewise. Handle srelrdyn.
> > (ppc_build_one_stub): Don't emit relative relocs on .branch_lt.
> > (compare_relr_address, append_relr_off): New functions.
> > (got_and_plt_relr_for_local_syms, got_and_plt_relr): Likewise.
> > (ppc64_elf_size_stubs): Size .relr.syn.
> > (ppc64_elf_build_stubs): Emit .relr.dyn.
> > (build_global_entry_stubs_and_plt): Don't output relative relocs
> > when enable_dt_relr.
> > (write_plt_relocs_for_local_syms): Likewise.
> > (ppc64_elf_relocate_section): Likewise.
> > binutils/
> > * testsuite/lib/binutils-common.exp (supports_dt_relr): Add
> > powerpc64.
> > ld/
> > * emulparams/elf64ppc.sh: Source dt-relr.sh.
> > * testsuite/ld-elf/dt-relr-2b.d: Adjust for powerpc.
> > * testsuite/ld-elf/dt-relr-2c.d: Likewise.
> > * testsuite/ld-elf/dt-relr-2d.d: Likewise.
> > * testsuite/ld-elf/dt-relr-2e.d: Likewise.
> >
> > diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
> > index ea9e60217bc..0f945797b49 100644
> > --- a/bfd/elf64-ppc.c
> > +++ b/bfd/elf64-ppc.c
> > @@ -3094,7 +3094,7 @@ struct ppc_branch_hash_entry
> > unsigned int iter;
> > };
> >
> > -/* Used to track dynamic relocations for local symbols. */
> > +/* Used to track dynamic relocations. */
> > struct ppc_dyn_relocs
> > {
> > struct ppc_dyn_relocs *next;
> > @@ -3103,7 +3103,27 @@ struct ppc_dyn_relocs
> > asection *sec;
> >
> > /* Total number of relocs copied for the input section. */
> > - unsigned int count : 31;
> > + unsigned int count;
> > +
> > + /* Number of pc-relative relocs copied for the input section. */
> > + unsigned int pc_count;
> > +
> > + /* Number of relocs that might become R_PPC64_RELATIVE. */
> > + unsigned int rel_count;
> > +};
> > +
> > +struct ppc_local_dyn_relocs
> > +{
> > + struct ppc_local_dyn_relocs *next;
> > +
> > + /* The input section of the reloc. */
> > + asection *sec;
> > +
> > + /* Total number of relocs copied for the input section. */
> > + unsigned int count;
> > +
> > + /* Number of relocs that might become R_PPC64_RELATIVE. */
> > + unsigned int rel_count : 31;
> >
> > /* Whether this entry is for STT_GNU_IFUNC symbols. */
> > unsigned int ifunc : 1;
> > @@ -3250,6 +3270,11 @@ struct ppc_link_hash_table
> > /* The size of reliplt used by got entry relocs. */
> > bfd_size_type got_reli_size;
> >
> > + /* DT_RELR array of r_offset. */
> > + size_t relr_alloc;
> > + size_t relr_count;
> > + bfd_vma *relr_addr;
> > +
> > /* Statistics. */
> > unsigned long stub_count[ppc_stub_save_res];
> >
> > @@ -4068,27 +4093,32 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
> > {
> > if (dir->dyn_relocs != NULL)
> > {
> > - struct elf_dyn_relocs **pp;
> > - struct elf_dyn_relocs *p;
> > + struct ppc_dyn_relocs **pp;
> > + struct ppc_dyn_relocs *p;
> >
> > /* Add reloc counts against the indirect sym to the direct sym
> > list. Merge any entries against the same section. */
> > - for (pp = &ind->dyn_relocs; (p = *pp) != NULL; )
> > + for (pp = (struct ppc_dyn_relocs **) &ind->dyn_relocs;
> > + (p = *pp) != NULL;
> > + )
> > {
> > - struct elf_dyn_relocs *q;
> > + struct ppc_dyn_relocs *q;
> >
> > - for (q = dir->dyn_relocs; q != NULL; q = q->next)
> > + for (q = (struct ppc_dyn_relocs *) dir->dyn_relocs;
> > + q != NULL;
> > + q = q->next)
> > if (q->sec == p->sec)
> > {
> > - q->pc_count += p->pc_count;
> > q->count += p->count;
> > + q->pc_count += p->pc_count;
> > + q->rel_count += p->rel_count;
> > *pp = p->next;
> > break;
> > }
> > if (q == NULL)
> > pp = &p->next;
> > }
> > - *pp = dir->dyn_relocs;
> > + *pp = (struct ppc_dyn_relocs *) dir->dyn_relocs;
> > }
> >
> > dir->dyn_relocs = ind->dyn_relocs;
> > @@ -5337,10 +5367,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> > relocations we need for this symbol. */
> > if (h != NULL)
> > {
> > - struct elf_dyn_relocs *p;
> > - struct elf_dyn_relocs **head;
> > + struct ppc_dyn_relocs *p;
> > + struct ppc_dyn_relocs **head;
> >
> > - head = &h->dyn_relocs;
> > + head = (struct ppc_dyn_relocs **) &h->dyn_relocs;
> > p = *head;
> > if (p == NULL || p->sec != sec)
> > {
> > @@ -5352,18 +5382,25 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> > p->sec = sec;
> > p->count = 0;
> > p->pc_count = 0;
> > + p->rel_count = 0;
> > }
> > p->count += 1;
> > if (!must_be_dyn_reloc (info, r_type))
> > p->pc_count += 1;
> > + if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
> > + && rel->r_offset % 2 == 0
> > + && sec->alignment_power != 0
> > + && ((!NO_OPD_RELOCS && is_opd)
> > + || (!ifunc && SYMBOL_REFERENCES_LOCAL (info, h))))
> > + p->rel_count += 1;
> > }
> > else
> > {
> > /* Track dynamic relocs needed for local syms too.
> > We really need local syms available to do this
> > easily. Oh well. */
> > - struct ppc_dyn_relocs *p;
> > - struct ppc_dyn_relocs **head;
> > + struct ppc_local_dyn_relocs *p;
> > + struct ppc_local_dyn_relocs **head;
> > bool is_ifunc;
> > asection *s;
> > void *vpp;
> > @@ -5379,7 +5416,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> > s = sec;
> >
> > vpp = &elf_section_data (s)->local_dynrel;
> > - head = (struct ppc_dyn_relocs **) vpp;
> > + head = (struct ppc_local_dyn_relocs **) vpp;
> > is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
> > p = *head;
> > if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
> > @@ -5392,10 +5429,16 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> > p->next = *head;
> > *head = p;
> > p->sec = sec;
> > - p->ifunc = is_ifunc;
> > p->count = 0;
> > + p->rel_count = 0;
> > + p->ifunc = is_ifunc;
> > }
> > p->count += 1;
> > + if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
> > + && rel->r_offset % 2 == 0
> > + && sec->alignment_power != 0
> > + && ((!NO_OPD_RELOCS && is_opd) || !is_ifunc))
> > + p->rel_count += 1;
> > }
> > }
> > break;
> > @@ -6576,9 +6619,9 @@ alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
> > static bool
> > pc_dynrelocs (struct ppc_link_hash_entry *eh)
> > {
> > - struct elf_dyn_relocs *p;
> > + struct ppc_dyn_relocs *p;
> >
> > - for (p = eh->elf.dyn_relocs; p != NULL; p = p->next)
> > + for (p = (struct ppc_dyn_relocs *) eh->elf.dyn_relocs; p != NULL; p = p->next)
> > if (p->pc_count != 0)
> > return true;
> > return false;
> > @@ -7113,7 +7156,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
> > have already been determined. */
> >
> > static bool
> > -dec_dynrel_count (bfd_vma r_info,
> > +dec_dynrel_count (const Elf_Internal_Rela *rel,
> > asection *sec,
> > struct bfd_link_info *info,
> > Elf_Internal_Sym **local_syms,
> > @@ -7125,7 +7168,7 @@ dec_dynrel_count (bfd_vma r_info,
> >
> > /* Can this reloc be dynamic? This switch, and later tests here
> > should be kept in sync with the code in check_relocs. */
> > - r_type = ELF64_R_TYPE (r_info);
> > + r_type = ELF64_R_TYPE (rel->r_info);
> > switch (r_type)
> > {
> > default:
> > @@ -7199,7 +7242,7 @@ dec_dynrel_count (bfd_vma r_info,
> > unsigned long r_symndx;
> > bfd *ibfd = sec->owner;
> >
> > - r_symndx = ELF64_R_SYM (r_info);
> > + r_symndx = ELF64_R_SYM (rel->r_info);
> > if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
> > return false;
> > }
> > @@ -7222,9 +7265,9 @@ dec_dynrel_count (bfd_vma r_info,
> >
> > if (h != NULL)
> > {
> > - struct elf_dyn_relocs *p;
> > - struct elf_dyn_relocs **pp;
> > - pp = &h->dyn_relocs;
> > + struct ppc_dyn_relocs *p;
> > + struct ppc_dyn_relocs **pp;
> > + pp = (struct ppc_dyn_relocs **) &h->dyn_relocs;
> >
> > /* elf_gc_sweep may have already removed all dyn relocs associated
> > with local syms for a given section. Also, symbol flags are
> > @@ -7239,6 +7282,14 @@ dec_dynrel_count (bfd_vma r_info,
> > {
> > if (!must_be_dyn_reloc (info, r_type))
> > p->pc_count -= 1;
> > + if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
> > + && rel->r_offset % 2 == 0
> > + && sec->alignment_power != 0
> > + && ((!NO_OPD_RELOCS
> > + && ppc64_elf_section_data (sec)->sec_type == sec_opd)
> > + || (h->type != STT_GNU_IFUNC
> > + && SYMBOL_REFERENCES_LOCAL (info, h))))
> > + p->rel_count -= 1;
> > p->count -= 1;
> > if (p->count == 0)
> > *pp = p->next;
> > @@ -7249,8 +7300,8 @@ dec_dynrel_count (bfd_vma r_info,
> > }
> > else
> > {
> > - struct ppc_dyn_relocs *p;
> > - struct ppc_dyn_relocs **pp;
> > + struct ppc_local_dyn_relocs *p;
> > + struct ppc_local_dyn_relocs **pp;
> > void *vpp;
> > bool is_ifunc;
> >
> > @@ -7260,7 +7311,7 @@ dec_dynrel_count (bfd_vma r_info,
> > sym_sec = sec;
> >
> > vpp = &elf_section_data (sym_sec)->local_dynrel;
> > - pp = (struct ppc_dyn_relocs **) vpp;
> > + pp = (struct ppc_local_dyn_relocs **) vpp;
> >
> > if (*pp == NULL && info->gc_sections)
> > return true;
> > @@ -7270,6 +7321,13 @@ dec_dynrel_count (bfd_vma r_info,
> > {
> > if (p->sec == sec && p->ifunc == is_ifunc)
> > {
> > + if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
> > + && rel->r_offset % 2 == 0
> > + && sec->alignment_power != 0
> > + && ((!NO_OPD_RELOCS
> > + && ppc64_elf_section_data (sec)->sec_type == sec_opd)
> > + || !is_ifunc))
> > + p->rel_count -= 1;
> > p->count -= 1;
> > if (p->count == 0)
> > *pp = p->next;
> > @@ -7567,7 +7625,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
> > else
> > while (1)
> > {
> > - if (!dec_dynrel_count (rel->r_info, sec, info,
> > + if (!dec_dynrel_count (rel, sec, info,
> > NULL, h, sym))
> > goto error_ret;
> >
> > @@ -8587,13 +8645,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
> > {
> > /* If we got rid of a DTPMOD/DTPREL reloc pair then
> > we'll lose one or two dyn relocs. */
> > - if (!dec_dynrel_count (rel->r_info, sec, info,
> > + if (!dec_dynrel_count (rel, sec, info,
> > NULL, h, sym))
> > return false;
> >
> > if (tls_set == (TLS_EXPLICIT | TLS_GD))
> > {
> > - if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
> > + if (!dec_dynrel_count (rel + 1, sec, info,
> > NULL, h, sym))
> > return false;
> > }
> > @@ -9419,7 +9477,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
> > wrel->r_addend = rel->r_addend;
> > ++wrel;
> > }
> > - else if (!dec_dynrel_count (rel->r_info, toc, info,
> > + else if (!dec_dynrel_count (rel, toc, info,
> > &local_syms, NULL, NULL))
> > goto error_ret;
> >
> > @@ -9720,9 +9778,10 @@ allocate_got (struct elf_link_hash_entry *h,
> > htab->got_reli_size += rentsize;
> > }
> > else if (((bfd_link_pic (info)
> > - && !(gent->tls_type != 0
> > - && bfd_link_executable (info)
> > - && SYMBOL_REFERENCES_LOCAL (info, h)))
> > + && (gent->tls_type == 0
> > + ? !info->enable_dt_relr
> > + : !(bfd_link_executable (info)
> > + && SYMBOL_REFERENCES_LOCAL (info, h))))
> > || (htab->elf.dynamic_sections_created
> > && h->dynindx != -1
> > && !SYMBOL_REFERENCES_LOCAL (info, h)))
> > @@ -9884,7 +9943,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> >
> > if (h->dyn_relocs != NULL)
> > {
> > - struct elf_dyn_relocs *p, **pp;
> > + struct ppc_dyn_relocs *p, **pp;
> >
> > /* In the shared -Bsymbolic case, discard space allocated for
> > dynamic pc-relative relocs against symbols which turn out to
> > @@ -9902,7 +9961,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> > avoid writing weird assembly. */
> > if (SYMBOL_CALLS_LOCAL (info, h))
> > {
> > - for (pp = &h->dyn_relocs; (p = *pp) != NULL; )
> > + for (pp = (struct ppc_dyn_relocs **) &h->dyn_relocs;
> > + (p = *pp) != NULL;
> > + )
> > {
> > p->count -= p->pc_count;
> > p->pc_count = 0;
> > @@ -9948,12 +10009,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> > }
> >
> > /* Finally, allocate space. */
> > - for (p = h->dyn_relocs; p != NULL; p = p->next)
> > + for (p = (struct ppc_dyn_relocs *) h->dyn_relocs; p != NULL; p = p->next)
> > {
> > + unsigned int count;
> > asection *sreloc = elf_section_data (p->sec)->sreloc;
> > if (eh->elf.type == STT_GNU_IFUNC)
> > sreloc = htab->elf.irelplt;
> > - sreloc->size += p->count * sizeof (Elf64_External_Rela);
> > + count = p->count;
> > + if (info->enable_dt_relr)
> > + count -= p->rel_count;
> > + sreloc->size += count * sizeof (Elf64_External_Rela);
> > }
> > }
> >
> > @@ -9994,7 +10059,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> > s = htab->pltlocal;
> > pent->plt.offset = s->size;
> > s->size += LOCAL_PLT_ENTRY_SIZE (htab);
> > - s = bfd_link_pic (info) ? htab->relpltlocal : NULL;
> > + s = NULL;
> > + if (bfd_link_pic (info)
> > + && !(info->enable_dt_relr && !htab->opd_abi))
> > + s = htab->relpltlocal;
> > }
> > }
> > else
> > @@ -10180,7 +10248,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
> >
> > for (s = ibfd->sections; s != NULL; s = s->next)
> > {
> > - struct ppc_dyn_relocs *p;
> > + struct ppc_local_dyn_relocs *p;
> >
> > for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
> > {
> > @@ -10194,10 +10262,16 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
> > }
> > else if (p->count != 0)
> > {
> > - asection *srel = elf_section_data (p->sec)->sreloc;
> > + unsigned int count;
> > + asection *srel;
> > +
> > + count = p->count;
> > + if (info->enable_dt_relr)
> > + count -= p->rel_count;
> > + srel = elf_section_data (p->sec)->sreloc;
> > if (p->ifunc)
> > srel = htab->elf.irelplt;
> > - srel->size += p->count * sizeof (Elf64_External_Rela);
> > + srel->size += count * sizeof (Elf64_External_Rela);
> > if ((p->sec->output_section->flags & SEC_READONLY) != 0)
> > info->flags |= DF_TEXTREL;
> > }
> > @@ -10342,7 +10416,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
> > if ((s->flags & SEC_LINKER_CREATED) == 0)
> > continue;
> >
> > - if (s == htab->brlt || s == htab->relbrlt)
> > + if (s == htab->brlt || s == htab->relbrlt || s == htab->elf.srelrdyn)
> > /* These haven't been allocated yet; don't strip. */
> > continue;
> > else if (s == htab->elf.sgot
> > @@ -11693,7 +11767,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
> > {
> > br_entry->iter = 0;
> >
> > - if (htab->relbrlt != NULL)
> > + if (htab->relbrlt != NULL && !info->enable_dt_relr)
> > {
> > /* Create a reloc for the branch lookup table entry. */
> > Elf_Internal_Rela rela;
> > @@ -12198,7 +12272,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
> > br_entry->offset = htab->brlt->size;
> > htab->brlt->size += 8;
> >
> > - if (htab->relbrlt != NULL)
> > + if (htab->relbrlt != NULL && !info->enable_dt_relr)
> > htab->relbrlt->size += sizeof (Elf64_External_Rela);
> > else if (info->emitrelocations)
> > {
> > @@ -13293,6 +13367,174 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec)
> > }
> > }
> >
> > +static int
> > +compare_relr_address (const void *arg1, const void *arg2)
> > +{
> > + bfd_vma a = *(bfd_vma *) arg1;
> > + bfd_vma b = *(bfd_vma *) arg2;
> > + return a < b ? -1 : a > b ? 1 : 0;
> > +}
> > +
> > +static bool
> > +append_relr_off (struct ppc_link_hash_table *htab, bfd_vma off)
> > +{
> > + if (htab->relr_count >= htab->relr_alloc)
> > + {
> > + if (htab->relr_alloc == 0)
> > + htab->relr_alloc = 4096;
> > + else
> > + htab->relr_alloc *= 2;
> > + htab->relr_addr
> > + = bfd_realloc (htab->relr_addr,
> > + htab->relr_alloc * sizeof (htab->relr_addr[0]));
> > + if (htab->relr_addr == NULL)
> > + return false;
> > + }
> > + htab->relr_addr[htab->relr_count++] = off;
> > + return true;
> > +}
> > +
> > +static bool
> > +got_and_plt_relr_for_local_syms (struct bfd_link_info *info)
> > +{
> > + struct ppc_link_hash_table *htab = ppc_hash_table (info);
> > + bfd *ibfd;
> > +
> > + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
> > + {
> > + struct got_entry **lgot_ents, **lgot, **end_lgot_ents;
> > + struct plt_entry **local_plt, **lplt, **end_local_plt;
> > + Elf_Internal_Shdr *symtab_hdr;
> > + bfd_size_type locsymcount;
> > + Elf_Internal_Sym *local_syms = NULL;
> > + struct plt_entry *pent;
> > + struct got_entry *gent;
> > +
> > + if (!is_ppc64_elf (ibfd))
> > + continue;
> > +
> > + lgot_ents = elf_local_got_ents (ibfd);
> > + if (!lgot_ents)
> > + continue;
> > +
> > + symtab_hdr = &elf_symtab_hdr (ibfd);
> > + locsymcount = symtab_hdr->sh_info;
> > + end_lgot_ents = lgot_ents + locsymcount;
> > + local_plt = (struct plt_entry **) end_lgot_ents;
> > + end_local_plt = local_plt + locsymcount;
> > + for (lgot = lgot_ents; lgot < end_lgot_ents; ++lgot)
> > + for (gent = *lgot; gent != NULL; gent = gent->next)
> > + if (!gent->is_indirect
> > + && gent->tls_type == 0
> > + && gent->got.offset != (bfd_vma) -1)
> > + {
> > + asection *got = ppc64_elf_tdata (gent->owner)->got;
> > + bfd_vma r_offset = (got->output_section->vma
> > + + got->output_offset
> > + + gent->got.offset);
> > + if (!append_relr_off (htab, r_offset))
> > + {
> > + htab->stub_error = true;
> > + return false;
> > + }
> > + }
> > +
> > + if (!htab->opd_abi)
> > + for (lplt = local_plt; lplt < end_local_plt; ++lplt)
> > + for (pent = *lplt; pent != NULL; pent = pent->next)
> > + if (pent->plt.offset != (bfd_vma) -1)
> > + {
> > + Elf_Internal_Sym *sym;
> > +
> > + if (!get_sym_h (NULL, &sym, NULL, NULL, &local_syms,
> > + lplt - local_plt, ibfd))
> > + {
> > + err_exit:
> > + if (symtab_hdr->contents != (unsigned char *) local_syms)
> > + free (local_syms);
> > + return false;
> > + }
> > +
> > + if (ELF_ST_TYPE (sym->st_info) != STT_GNU_IFUNC)
> > + {
> > + bfd_vma r_offset = (pent->plt.offset
> > + + htab->pltlocal->output_offset
> > + + htab->pltlocal->output_section->vma);
> > + if (!append_relr_off (htab, r_offset))
> > + goto err_exit;
> > + }
> > + }
> > +
> > + if (local_syms != NULL
> > + && symtab_hdr->contents != (unsigned char *) local_syms)
> > + {
> > + if (!info->keep_memory)
> > + free (local_syms);
> > + else
> > + symtab_hdr->contents = (unsigned char *) local_syms;
> > + }
> > + }
> > + return true;
> > +}
> > +
> > +static bool
> > +got_and_plt_relr (struct elf_link_hash_entry *h, void *inf)
> > +{
> > + struct bfd_link_info *info;
> > + struct ppc_link_hash_table *htab;
> > + struct plt_entry *pent;
> > + struct got_entry *gent;
> > +
> > + if (h->root.type == bfd_link_hash_indirect)
> > + return true;
> > +
> > + info = (struct bfd_link_info *) inf;
> > + htab = ppc_hash_table (info);
> > + if (htab == NULL)
> > + return false;
> > +
> > + if (h->type != STT_GNU_IFUNC
> > + && h->def_regular
> > + && (h->root.type == bfd_link_hash_defined
> > + || h->root.type == bfd_link_hash_defweak))
> > + {
> > + if (!htab->elf.dynamic_sections_created
> > + || h->dynindx == -1
> > + || SYMBOL_REFERENCES_LOCAL (info, h))
> > + for (gent = h->got.glist; gent != NULL; gent = gent->next)
> > + if (!gent->is_indirect
> > + && gent->tls_type == 0
> > + && gent->got.offset != (bfd_vma) -1)
> > + {
> > + asection *got = ppc64_elf_tdata (gent->owner)->got;
> > + bfd_vma r_offset = (got->output_section->vma
> > + + got->output_offset
> > + + gent->got.offset);
> > + if (!append_relr_off (htab, r_offset))
> > + {
> > + htab->stub_error = true;
> > + return false;
> > + }
> > + }
> > +
> > + if (!htab->opd_abi
> > + && use_local_plt (info, h))
> > + for (pent = h->plt.plist; pent != NULL; pent = pent->next)
> > + if (pent->plt.offset != (bfd_vma) -1)
> > + {
> > + bfd_vma r_offset = (htab->pltlocal->output_section->vma
> > + + htab->pltlocal->output_offset
> > + + pent->plt.offset);
> > + if (!append_relr_off (htab, r_offset))
> > + {
> > + htab->stub_error = true;
> > + return false;
> > + }
> > + }
> > + }
> > + return true;
> > +}
> > +
> > /* Determine and set the size of the stub section for a final link.
> >
> > The basic idea here is to examine all the relocations looking for
> > @@ -13413,6 +13655,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > struct map_stub *group;
> >
> > htab->stub_iteration += 1;
> > + htab->relr_count = 0;
> >
> > for (input_bfd = info->input_bfds, bfd_indx = 0;
> > input_bfd != NULL;
> > @@ -13436,16 +13679,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > section = section->next)
> > {
> > Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
> > + bool is_opd;
> >
> > /* If there aren't any relocs, then there's nothing more
> > to do. */
> > if ((section->flags & SEC_RELOC) == 0
> > || (section->flags & SEC_ALLOC) == 0
> > || (section->flags & SEC_LOAD) == 0
> > - || (section->flags & SEC_CODE) == 0
> > || section->reloc_count == 0)
> > continue;
> >
> > + if (!info->enable_dt_relr
> > + && (section->flags & SEC_CODE) == 0)
> > + continue;
> > +
> > /* If this section is a link-once section that will be
> > discarded, then don't create any stubs. */
> > if (section->output_section == NULL
> > @@ -13459,6 +13706,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > if (internal_relocs == NULL)
> > goto error_ret_free_local;
> >
> > + is_opd = ppc64_elf_section_data (section)->sec_type == sec_opd;
> > +
> > /* Now examine each relocation. */
> > irela = internal_relocs;
> > irelaend = irela + section->reloc_count;
> > @@ -13492,21 +13741,76 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > }
> >
> > /* Only look for stubs on branch instructions. */
> > - if (r_type != R_PPC64_REL24
> > - && r_type != R_PPC64_REL24_NOTOC
> > - && r_type != R_PPC64_REL24_P9NOTOC
> > - && r_type != R_PPC64_REL14
> > - && r_type != R_PPC64_REL14_BRTAKEN
> > - && r_type != R_PPC64_REL14_BRNTAKEN)
> > - continue;
> > + switch (r_type)
> > + {
> > + default:
> > + continue;
> > +
> > + case R_PPC64_REL24:
> > + case R_PPC64_REL24_NOTOC:
> > + case R_PPC64_REL24_P9NOTOC:
> > + case R_PPC64_REL14:
> > + case R_PPC64_REL14_BRTAKEN:
> > + case R_PPC64_REL14_BRNTAKEN:
> > + if ((section->flags & SEC_CODE) != 0)
> > + break;
> > + continue;
> > +
> > + case R_PPC64_ADDR64:
> > + case R_PPC64_TOC:
> > + if (info->enable_dt_relr
> > + && irela->r_offset % 2 == 0
> > + && section->alignment_power != 0)
> > + break;
> > + continue;
> > + }
> >
> > /* Now determine the call target, its name, value,
> > section. */
> > if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
> > r_indx, input_bfd))
> > goto error_ret_free_internal;
> > - hash = ppc_elf_hash_entry (h);
> >
> > + if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
> > + {
> > + /* Only locally defined symbols can possibly use
> > + relative relocations. */
> > + bfd_vma r_offset;
> > + if ((sym_sec == NULL
> > + || sym_sec->output_section == NULL)
> > + /* No symbol is OK too. */
> > + && !(sym != NULL && sym->st_shndx == 0)
> > + /* Hack for __ehdr_start, which is undefined
> > + at this point. */
> > + && !(h != NULL && h->root.linker_def))
> > + continue;
> > + if (NO_OPD_RELOCS && is_opd)
> > + continue;
> > + if (!is_opd
> > + && r_type == R_PPC64_ADDR64)
> > + {
> > + if (h != NULL
> > + ? h->type == STT_GNU_IFUNC
> > + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
> > + continue;
> > + if (h != NULL
> > + && !SYMBOL_REFERENCES_LOCAL (info, h))
> > + continue;
> > + }
> > + r_offset = _bfd_elf_section_offset (info->output_bfd,
> > + info,
> > + section,
> > + irela->r_offset);
> > + if (r_offset >= (bfd_vma) -2)
> > + continue;
> > + r_offset += (section->output_section->vma
> > + + section->output_offset);
> > + if (!append_relr_off (htab, r_offset))
> > + goto error_ret_free_internal;
> > + continue;
> > + }
> > +
> > + hash = ppc_elf_hash_entry (h);
> > ok_dest = false;
> > fdh = NULL;
> > sym_value = 0;
> > @@ -13804,6 +14108,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > if (htab->relbrlt != NULL)
> > htab->relbrlt->size = 0;
> >
> > + if (htab->elf.srelrdyn != NULL)
> > + {
> > + if (htab->stub_iteration <= STUB_SHRINK_ITER
> > + || htab->elf.srelrdyn->rawsize < htab->elf.srelrdyn->size)
> > + htab->elf.srelrdyn->rawsize = htab->elf.srelrdyn->size;
> > + htab->elf.srelrdyn->size = 0;
> > + }
> > +
> > bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
> >
> > for (group = htab->group; group != NULL; group = group->next)
> > @@ -13845,6 +14157,53 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > = (group->stub_sec->size + (1 << align) - 1) & -(1 << align);
> > }
> >
> > + if (htab->elf.srelrdyn != NULL)
> > + {
> > + bfd_vma r_offset;
> > +
> > + for (r_offset = 0; r_offset < htab->brlt->size; r_offset += 8)
> > + if (!append_relr_off (htab, (r_offset
> > + + htab->brlt->output_section->vma
> > + + htab->brlt->output_offset)))
> > + return false;
> > +
> > + if (!got_and_plt_relr_for_local_syms (info))
> > + return false;
> > + elf_link_hash_traverse (&htab->elf, got_and_plt_relr, info);
> > + if (htab->stub_error)
> > + return false;
> > +
> > + if (htab->relr_count > 1)
> > + qsort (htab->relr_addr, htab->relr_count, sizeof (*htab->relr_addr),
> > + compare_relr_address);
> > +
> > + size_t i = 0;
> > + while (i < htab->relr_count)
> > + {
> > + bfd_vma base = htab->relr_addr[i];
> > + htab->elf.srelrdyn->size += 8;
> > + i++;
> > + /* Handle possible duplicate address. This can happen
> > + as sections increase in size when adding stubs. */
> > + while (i < htab->relr_count
> > + && htab->relr_addr[i] == base)
> > + i++;
> > + base += 8;
> > + while (1)
> > + {
> > + size_t start_i = i;
> > + while (i < htab->relr_count
> > + && htab->relr_addr[i] - base < 63 * 8
> > + && (htab->relr_addr[i] - base) % 8 == 0)
> > + i++;
> > + if (i == start_i)
> > + break;
> > + htab->elf.srelrdyn->size += 8;
> > + base += 63 * 8;
> > + }
> > + }
> > + }
> > +
> > for (group = htab->group; group != NULL; group = group->next)
> > if (group->stub_sec != NULL
> > && group->stub_sec->rawsize != group->stub_sec->size
> > @@ -13856,6 +14215,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > && (htab->brlt->rawsize == htab->brlt->size
> > || (htab->stub_iteration > STUB_SHRINK_ITER
> > && htab->brlt->rawsize > htab->brlt->size))
> > + && (htab->elf.srelrdyn == NULL
> > + || htab->elf.srelrdyn->rawsize == htab->elf.srelrdyn->size
> > + || (htab->stub_iteration > STUB_SHRINK_ITER
> > + && htab->elf.srelrdyn->rawsize > htab->elf.srelrdyn->size))
> > && (htab->glink_eh_frame == NULL
> > || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)
> > && (htab->tga_group == NULL
> > @@ -13959,6 +14322,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
> > maybe_strip_output (info, htab->relbrlt);
> > if (htab->glink_eh_frame != NULL)
> > maybe_strip_output (info, htab->glink_eh_frame);
> > + if (htab->elf.srelrdyn != NULL)
> > + maybe_strip_output (info, htab->elf.srelrdyn);
> >
> > return true;
> > }
> > @@ -14120,7 +14485,9 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
> > else
> > {
> > plt = htab->pltlocal;
> > - if (bfd_link_pic (info))
> > + relplt = NULL;
> > + if (bfd_link_pic (info)
> > + && !(info->enable_dt_relr && !htab->opd_abi))
> > {
> > relplt = htab->relpltlocal;
> > if (htab->opd_abi)
> > @@ -14128,8 +14495,6 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
> > else
> > rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
> > }
> > - else
> > - relplt = NULL;
> > }
> > rela.r_addend = defined_sym_val (h) + ent->addend;
> >
> > @@ -14311,7 +14676,10 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
> > else
> > {
> > plt = htab->pltlocal;
> > - relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
> > + relplt = NULL;
> > + if (bfd_link_pic (info)
> > + && !(info->enable_dt_relr && !htab->opd_abi))
> > + relplt = htab->relpltlocal;
> > }
> >
> > if (relplt == NULL)
> > @@ -14749,6 +15117,55 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
> > }
> > }
> >
> > + if (htab->elf.srelrdyn != NULL && htab->elf.srelrdyn->size != 0)
> > + {
> > + htab->elf.srelrdyn->contents
> > + = bfd_alloc (htab->elf.dynobj, htab->elf.srelrdyn->size);
> > + if (htab->elf.srelrdyn->contents == NULL)
> > + return false;
> > +
> > + size_t i = 0;
> > + bfd_byte *loc = htab->elf.srelrdyn->contents;
> > + while (i < htab->relr_count)
> > + {
> > + bfd_vma base = htab->relr_addr[i];
> > + BFD_ASSERT (base % 2 == 0);
> > + bfd_put_64 (htab->elf.dynobj, base, loc);
> > + loc += 8;
> > + i++;
> > + while (i < htab->relr_count
> > + && htab->relr_addr[i] == base)
> > + {
> > + htab->stub_error = true;
> > + i++;
> > + }
> > + base += 8;
> > + while (1)
> > + {
> > + bfd_vma bits = 0;
> > + while (i < htab->relr_count
> > + && htab->relr_addr[i] - base < 63 * 8
> > + && (htab->relr_addr[i] - base) % 8 == 0)
> > + {
> > + bits |= (bfd_vma) 1 << ((htab->relr_addr[i] - base) / 8);
> > + i++;
> > + }
> > + if (bits == 0)
> > + break;
> > + bfd_put_64 (htab->elf.dynobj, (bits << 1) | 1, loc);
> > + loc += 8;
> > + base += 63 * 8;
> > + }
> > + }
> > + /* Pad any excess with 1's, a do-nothing encoding. */
> > + while ((size_t) (loc - htab->elf.srelrdyn->contents)
> > + < htab->elf.srelrdyn->size)
> > + {
> > + bfd_put_64 (htab->elf.dynobj, 1, loc);
> > + loc += 8;
> > + }
> > + }
> > +
> > for (group = htab->group; group != NULL; group = group->next)
> > if ((stub_sec = group->stub_sec) != NULL)
> > {
> > @@ -14760,14 +15177,14 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
> > }
> >
> > if (group != NULL)
> > + htab->stub_error = true;
> > +
> > + if (htab->stub_error)
> > {
> > - htab->stub_error = true;
> > _bfd_error_handler (_("stubs don't match calculated size"));
> > + return false;
> > }
> >
> > - if (htab->stub_error)
> > - return false;
> > -
> > if (stats != NULL)
> > {
> > char *groupmsg;
> > @@ -16462,10 +16879,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
> > outrel.r_addend -= htab->elf.tls_sec->vma;
> > }
> > }
> > - loc = relgot->contents;
> > - loc += (relgot->reloc_count++
> > - * sizeof (Elf64_External_Rela));
> > - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
> > + if (!(info->enable_dt_relr
> > + && ELF64_R_TYPE (outrel.r_info) == R_PPC64_RELATIVE))
> > + {
> > + loc = relgot->contents;
> > + loc += (relgot->reloc_count++
> > + * sizeof (Elf64_External_Rela));
> > + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
> > + }
> > }
> >
> > /* Init the .got section contents here if we're not
> > @@ -16924,24 +17345,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
> > }
> > }
> >
> > - sreloc = elf_section_data (input_section)->sreloc;
> > - if (h != NULL
> > - ? h->elf.type == STT_GNU_IFUNC
> > - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
> > + if (!(info->enable_dt_relr
> > + && ELF64_R_TYPE (outrel.r_info) == R_PPC64_RELATIVE
> > + && rel->r_offset % 2 == 0
> > + && input_section->alignment_power != 0
> > + && ELF64_R_TYPE (orig_rel.r_info) != R_PPC64_UADDR64))
> > {
> > - sreloc = htab->elf.irelplt;
> > - if (indx == 0 || is_static_defined (&h->elf))
> > - htab->elf.ifunc_resolvers = true;
> > + sreloc = elf_section_data (input_section)->sreloc;
> > + if (h != NULL
> > + ? h->elf.type == STT_GNU_IFUNC
> > + : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
> > + {
> > + sreloc = htab->elf.irelplt;
> > + if (indx == 0 || is_static_defined (&h->elf))
> > + htab->elf.ifunc_resolvers = true;
> > + }
> > + if (sreloc == NULL)
> > + abort ();
> > +
> > + if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
> > + >= sreloc->size)
> > + abort ();
> > + loc = sreloc->contents;
> > + loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
> > + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
> > }
> > - if (sreloc == NULL)
> > - abort ();
> > -
> > - if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
> > - >= sreloc->size)
> > - abort ();
> > - loc = sreloc->contents;
> > - 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)))
> > diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
> > index 93603b0be68..2a2aaf4a17d 100644
> > --- a/binutils/testsuite/lib/binutils-common.exp
> > +++ b/binutils/testsuite/lib/binutils-common.exp
s> > @@ -429,7 +429,9 @@ proc supports_persistent_section {} {
> >
> > # Whether a target support DT_RELR sections.
> > proc supports_dt_relr {} {
> > - if { ([istarget x86_64-*-*] || [istarget i?86-*-*])
> > + if { ([istarget x86_64-*-*]
> > + || [istarget i?86-*-*]
> > + || [istarget powerpc64*-*-*])
> > && ([istarget *-*-linux*]
> > || [istarget *-*-gnu*]) } {
> > return 1
> > diff --git a/ld/emulparams/elf64ppc.sh b/ld/emulparams/elf64ppc.sh
> > index 15221b82220..a18393b7202 100644
> > --- a/ld/emulparams/elf64ppc.sh
> > +++ b/ld/emulparams/elf64ppc.sh
> > @@ -1,5 +1,6 @@
> > source_sh ${srcdir}/emulparams/elf32ppccommon.sh
> > source_sh ${srcdir}/emulparams/plt_unwind.sh
> > +source_sh ${srcdir}/emulparams/dt-relr.sh
> > EXTRA_EM_FILE=ppc64elf
> > ELFSIZE=64
> > OUTPUT_FORMAT="elf64-powerpc"
> > diff --git a/ld/testsuite/ld-elf/dt-relr-2b.d b/ld/testsuite/ld-elf/dt-relr-2b.d
> > index cea2931e37d..b1391566a13 100644
> > --- a/ld/testsuite/ld-elf/dt-relr-2b.d
> > +++ b/ld/testsuite/ld-elf/dt-relr-2b.d
> > @@ -10,7 +10,7 @@
> > #...
> > Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
> > #...
> > -[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
> > +[0-9a-f]+ +[0-9a-f]+ +R_.*_(RELATIVE|UADDR.*) .*
> > #...
> > Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> > 4 offsets
> > diff --git a/ld/testsuite/ld-elf/dt-relr-2c.d b/ld/testsuite/ld-elf/dt-relr-2c.d
> > index 73087a67533..c285e8707d7 100644
> > --- a/ld/testsuite/ld-elf/dt-relr-2c.d
> > +++ b/ld/testsuite/ld-elf/dt-relr-2c.d
> > @@ -10,7 +10,7 @@
> > #...
> > Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> > #...
> > -[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
> > +[0-9a-f]+ +[0-9a-f]+ +R_.*_(RELATIVE|UADDR.*) .*
> > #...
> > Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> > 3 offsets
> > diff --git a/ld/testsuite/ld-elf/dt-relr-2d.d b/ld/testsuite/ld-elf/dt-relr-2d.d
> > index 4987b0865a3..7fd3046a1cf 100644
> > --- a/ld/testsuite/ld-elf/dt-relr-2d.d
> > +++ b/ld/testsuite/ld-elf/dt-relr-2d.d
> > @@ -10,7 +10,7 @@
> > #...
> > Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
> > #...
> > -[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
> > +[0-9a-f]+ +[0-9a-f]+ +R_.*_(RELATIVE|UADDR.*) .*
> > #...
> > Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> > 4 offsets
> > diff --git a/ld/testsuite/ld-elf/dt-relr-2e.d b/ld/testsuite/ld-elf/dt-relr-2e.d
> > index 24ce6cc0070..cdff8465a57 100644
> > --- a/ld/testsuite/ld-elf/dt-relr-2e.d
> > +++ b/ld/testsuite/ld-elf/dt-relr-2e.d
> > @@ -10,7 +10,7 @@
> > #...
> > Relocation section '\.rel(a|)\.data' at offset 0x[0-9a-f]+ contains 1 entry:
> > #...
> > -[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
> > +[0-9a-f]+ +[0-9a-f]+ +R_.*_(RELATIVE|UADDR.*) .*
> > #...
> > Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
> > 4 offsets
> >
> > --
> > Alan Modra
> > Australia Development Lab, IBM
>
> You can test your linker wiith the glibc build using users/hjl/relr/master
> branch:
>
> https://gitlab.com/x86-glibc/glibc/-/commits/users/hjl/relr/master
>
> by enabling -Wl,-z,pack-relative-relocs by default.
>
I tried binutils master branch on glibc master branch:
$ readelf -r libc.so.6
Relocation section '.rela.dyn' at offset 0x21d38 contains 562 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000000 000000000000 R_PPC64_NONE 0
000000000000 000000000000 R_PPC64_NONE 0
There are 238 R_PPC64_NONEs in libc.so.6 alone. There is none
for i686, x32 and x86-64.
--
H.J.
More information about the Binutils
mailing list