From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pf1-x431.google.com (mail-pf1-x431.google.com [IPv6:2607:f8b0:4864:20::431]) by sourceware.org (Postfix) with ESMTPS id 943833858D3C for ; Tue, 18 Jan 2022 01:08:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 943833858D3C Received: by mail-pf1-x431.google.com with SMTP id m21so11634900pfd.3 for ; Mon, 17 Jan 2022 17:08:50 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3rvd3Rl5MqaLO7EaxbKvsEwT8nHTbBtM7nXPWTg0/+Q=; b=NfxvJMLvuCAoH8N8nDOtjQIrl5ht32u9D9mRSiiqw4AJJZ29uv5pAf48QLy9hspqjN 6MvFzw7BFSQg3q40JRxO2IbxzUkHbWWmkO3CJBFQPqiGA138C1ivUMnP31U+RPY+NQRf 2LO0D/pCyy8dFOHGrXT3AYSXCKuWMCgfqHNbdUM2oWjwmdWjCihpu91c75w0Uti/g6f9 llmk5huiIlKUjD7nNUPJ3xpdQBbt1HB2HbeLo5S23dpWJmRH8bKevsLzBiKZ/4Bts25Q MuEQGshG2JhDTaP7NyAFvygPB+BksE2YIXsfGQnFt1w7Yn49Ui0RovJIlA037KH2XwyK QktQ== X-Gm-Message-State: AOAM532VCA0K5Fl5DODB56MF6oViyimRwTWYflIByzGEO5YQIGq/5J6S HzWpGkURSsHcRhJ0wjZPAHqykUN74Q6fKJH32gwv17V7OPY= X-Google-Smtp-Source: ABdhPJyBLfec7nqKM8MLVUh/qu97SY3vT5A2/15ZKdRKLxseqpO8hudsNN6urt15vB8zS/ZUbo1++hu3g9oES56PVAE= X-Received: by 2002:a63:b24e:: with SMTP id t14mr21289201pgo.381.1642468129108; Mon, 17 Jan 2022 17:08:49 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: "H.J. Lu" Date: Mon, 17 Jan 2022 17:08:12 -0800 Message-ID: Subject: Re: PowerPC64 DT_RELR To: Alan Modra Cc: Binutils Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-3026.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 18 Jan 2022 01:08:55 -0000 On Mon, Jan 17, 2022 at 4:54 PM Alan Modra via Binutils 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 > @@ -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. -- H.J.