[PATCH 1/4] RISC-V: Refactor PLT generation

Nelson Chu nelson@rivosinc.com
Tue Jun 10 05:51:57 GMT 2025


On Thu, May 15, 2025 at 7:04 PM Kito Cheng <kito.cheng@sifive.com> wrote:

> The goal of this refactor is to improve the possiblity of having
> different PLT generation code for different RISC-V ABIs. The changes
> include:
> - Extract PLT generation logic into individual functions.
> - Keep the PLT generation data in riscv_elf_link_hash_table.
>
> In the following patches, we will use this framework to implement
> different PLT.
> ---
>  bfd/elfnn-riscv.c | 105 ++++++++++++++++++++++++++++++----------------
>  bfd/elfxx-riscv.h |   5 +++
>  2 files changed, 75 insertions(+), 35 deletions(-)
>
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 1c494f5f986..eef4d40299a 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -176,6 +176,9 @@ struct _bfd_riscv_elf_obj_tdata
>
>    /* tls_type for each local got entry.  */
>    char *local_got_tls_type;
> +
> +  /* PLT type.  */
> +  riscv_plt_type plt_type;
>  };
>
>  #define _bfd_riscv_elf_tdata(abfd) \
> @@ -232,6 +235,15 @@ struct riscv_elf_link_hash_table
>
>    /* Relocations for variant CC symbols may be present.  */
>    int variant_cc;
> +
> +  /* The number of bytes in the PLT header and enties.  */
> +  bfd_size_type plt_header_size;
> +  bfd_size_type plt_entry_size;
> +
> +  /* Functions to make PLT header and entries.  */
> +  bool (*make_plt_header) (bfd *output_bfd, struct
> riscv_elf_link_hash_table *htab);
> +  bool (*make_plt_entry) (bfd *output_bfd, asection *got, bfd_vma
> got_offset,
> +                         asection *plt, bfd_vma plt_offset);
>  };
>
>  /* Instruction access functions. */
> @@ -252,6 +264,13 @@ struct riscv_elf_link_hash_table
>      && elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA)       \
>     ? (struct riscv_elf_link_hash_table *) (p)->hash : NULL)
>
> +/* Forward declaration PLT related functions.  */
> +static bool
> +riscv_make_plt_header (bfd *, struct riscv_elf_link_hash_table *);
> +
> +static bool
> +riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
> +
>  void
>  riscv_elfNN_set_options (struct bfd_link_info *link_info,
>                          struct riscv_elf_params *params)
> @@ -317,9 +336,14 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
>  /* Generate a PLT header.  */
>
>  static bool
> -riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
> -                      uint32_t *entry)
> +riscv_make_plt_header (bfd *output_bfd, struct riscv_elf_link_hash_table
> *htab)
>  {
> +  asection *splt = htab->elf.splt;
> +  bfd_vma addr = sec_addr(splt);
> +
> +  asection *sgotplt = htab->elf.sgotplt;
> +  bfd_vma gotplt_addr = sec_addr (sgotplt);
> +
>    bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, addr);
>    bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, addr);
>
> @@ -340,6 +364,7 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma
> gotplt_addr, bfd_vma addr,
>       l[w|d] t0, PTRSIZE(t0)         # link map
>       jr            t3  */
>
> +  uint32_t entry[PLT_HEADER_INSNS];
>    entry[0] = RISCV_UTYPE (AUIPC, X_T2, gotplt_offset_high);
>    entry[1] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T3);
>    entry[2] = RISCV_ITYPE (LREG, X_T3, X_T2, gotplt_offset_low);
> @@ -349,15 +374,20 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma
> gotplt_addr, bfd_vma addr,
>    entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
>    entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0);
>
> +  for (int i = 0; i < PLT_HEADER_INSNS; i++)
> +    bfd_putl32 (entry[i], splt->contents + 4*i);
> +
>    return true;
>  }
>
>  /* Generate a PLT entry.  */
>
>  static bool
> -riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
> -                     uint32_t *entry)
> +riscv_make_plt_entry (bfd *output_bfd, asection *gotsec, bfd_vma
> got_offset,
> +                     asection *pltsec, bfd_vma plt_offset)
>  {
> +  bfd_vma got = sec_addr(gotsec) + got_offset;

+  bfd_vma addr = sec_addr(pltsec) + plt_offset;
>

Coding style, need space after sec_addr?


>    /* RVE has no t3 register, so this won't work, and is not supported.  */
>    if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
>      {
> @@ -371,11 +401,16 @@ riscv_make_plt_entry (bfd *output_bfd, bfd_vma got,
> bfd_vma addr,
>       jalr   t1, t3
>       nop  */
>
> +  uint32_t entry[PLT_ENTRY_INSNS];
>    entry[0] = RISCV_UTYPE (AUIPC, X_T3, RISCV_PCREL_HIGH_PART (got, addr));
>    entry[1] = RISCV_ITYPE (LREG,  X_T3, X_T3, RISCV_PCREL_LOW_PART (got,
> addr));
>    entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
>    entry[3] = RISCV_NOP;
>
> +  bfd_byte *loc = pltsec->contents + plt_offset;
> +  for (int i = 0; i < PLT_ENTRY_INSNS; i++)
> +    bfd_putl32 (entry[i], loc + i * 4);
> +
>    return true;
>  }
>
> @@ -511,6 +546,11 @@ riscv_elf_link_hash_table_create (bfd *abfd)
>    ret->max_alignment = (bfd_vma) -1;
>    ret->max_alignment_for_gp = (bfd_vma) -1;
>
> +  ret->plt_header_size = PLT_HEADER_SIZE;
> +  ret->plt_entry_size = PLT_ENTRY_SIZE;
> +  ret->make_plt_header = riscv_make_plt_header;
> +  ret->make_plt_entry = riscv_make_plt_entry;
> +
>    /* Create hash table for local ifunc.  */
>    ret->loc_hash_table = htab_try_create (1024,
>                                          riscv_elf_local_htab_hash,
> @@ -1259,12 +1299,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h,
> void *inf)
>           asection *s = htab->elf.splt;
>
>           if (s->size == 0)
> -           s->size = PLT_HEADER_SIZE;
> +           s->size = htab->plt_header_size;
>
>           h->plt.offset = s->size;
>
>           /* Make room for this entry.  */
> -         s->size += PLT_ENTRY_SIZE;
> +         s->size += htab->plt_entry_size;
>
>           /* We also need to make an entry in the .got.plt section.  */
>           htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
> @@ -1456,6 +1496,7 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry
> *h,
>                           void *inf)
>  {
>    struct bfd_link_info *info;
> +  struct riscv_elf_link_hash_table *htab;
>
>    if (h->root.type == bfd_link_hash_indirect)
>      return true;
> @@ -1464,6 +1505,7 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry
> *h,
>      h = (struct elf_link_hash_entry *) h->root.u.i.link;
>
>    info = (struct bfd_link_info *) inf;
> +  htab = riscv_elf_hash_table (info);
>
>    /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
>       here if it is defined and referenced in a non-shared object.  */
> @@ -1471,8 +1513,8 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry
> *h,
>        && h->def_regular)
>      return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
>                                                &h->dyn_relocs,
> -                                              PLT_ENTRY_SIZE,
> -                                              PLT_HEADER_SIZE,
> +                                              htab->plt_entry_size,
> +                                              htab->plt_header_size,
>                                                GOT_ENTRY_SIZE,
>                                                true);
>    return true;
> @@ -2472,14 +2514,14 @@ riscv_elf_relocate_section (bfd *output_bfd,
>
>                     if (htab->elf.splt != NULL)
>                       {
> -                       plt_idx = (h->plt.offset - PLT_HEADER_SIZE)
> -                                 / PLT_ENTRY_SIZE;
> +                       plt_idx = (h->plt.offset - htab->plt_header_size)
> +                                 / htab->plt_entry_size;
>                         off = GOTPLT_HEADER_SIZE + (plt_idx *
> GOT_ENTRY_SIZE);
>                         base_got = htab->elf.sgotplt;
>                       }
>                     else
>                       {
> -                       plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
> +                       plt_idx = h->plt.offset / htab->plt_entry_size;
>                         off = plt_idx * GOT_ENTRY_SIZE;
>                         base_got = htab->elf.igotplt;
>                       }
> @@ -3247,8 +3289,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
>      {
>        /* We've decided to create a PLT entry for this symbol.  */
>        bfd_byte *loc;
> -      bfd_vma i, header_address, plt_idx, got_offset, got_address;
> -      uint32_t plt_entry[PLT_ENTRY_INSNS];
> +      bfd_vma plt_idx, got_offset, got_address;
>        Elf_Internal_Rela rela;
>        asection *plt, *gotplt, *relplt;
>
> @@ -3278,36 +3319,29 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
>           || relplt == NULL)
>         abort ();
>
> -      /* Calculate the address of the PLT header.  */
> -      header_address = sec_addr (plt);
> -
>        /* Calculate the index of the entry and the offset of .got.plt
> entry.
>          For static executables, we don't reserve anything.  */
>        if (plt == htab->elf.splt)
>         {
> -         plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
> +         plt_idx = (h->plt.offset - htab->plt_header_size)
> +                    / htab->plt_entry_size;
>           got_offset = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
>         }
>        else
>         {
> -         plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
> +         plt_idx = h->plt.offset / htab->plt_entry_size;
>           got_offset = plt_idx * GOT_ENTRY_SIZE;
>         }
>
>        /* Calculate the address of the .got.plt entry.  */
>        got_address = sec_addr (gotplt) + got_offset;
>
> -      /* Find out where the .plt entry should go.  */
> -      loc = plt->contents + h->plt.offset;
>
>        /* Fill in the PLT entry itself.  */
> -      if (! riscv_make_plt_entry (output_bfd, got_address,
> -                                 header_address + h->plt.offset,
> -                                 plt_entry))
> +      if (! htab->make_plt_entry (output_bfd, gotplt, got_offset,
> +                                 plt, h->plt.offset))
>         return false;
>
> -      for (i = 0; i < PLT_ENTRY_INSNS; i++)
> -       bfd_putl32 (plt_entry[i], loc + 4*i);
>
>        /* Fill in the initial value of the .got.plt entry.  */
>        loc = gotplt->contents + (got_address - sec_addr (gotplt));
>

Can we also move these initial steps into make_plt_entry?
/* Fill in the initial value of the .got.plt entry.  */
loc = gotplt->contents + (got_address - sec_addr (gotplt));
bfd_put_NN (output_bfd, sec_addr (plt), loc);

"rela.r_offset = sec_addr (gotplt) + got_offset", so that we don't need
got_address above.


> @@ -3595,19 +3629,12 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
>        /* Fill in the head and tail entries in the procedure linkage
> table.  */
>        if (splt->size > 0)
>         {
> -         int i;
> -         uint32_t plt_header[PLT_HEADER_INSNS];
> -         ret = riscv_make_plt_header (output_bfd,
> -                                      sec_addr (htab->elf.sgotplt),
> -                                      sec_addr (splt), plt_header);
> +         ret = htab->make_plt_header (output_bfd, htab);
>           if (!ret)
>             return ret;
>
> -         for (i = 0; i < PLT_HEADER_INSNS; i++)
> -           bfd_putl32 (plt_header[i], splt->contents + 4*i);
> -
>           elf_section_data (splt->output_section)->this_hdr.sh_entsize
> -           = PLT_ENTRY_SIZE;
> +           = htab->plt_entry_size;
>         }
>      }
>
> @@ -3661,7 +3688,15 @@ static bfd_vma
>  riscv_elf_plt_sym_val (bfd_vma i, const asection *plt,
>                        const arelent *rel ATTRIBUTE_UNUSED)
>  {
> -  return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE;
> +  unsigned plt_type = _bfd_riscv_elf_tdata (plt->owner)->plt_type;
> +  switch (plt_type)
> +    {
> +    case PLT_NORMAL:
> +      return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);

+
> +    default:
> +      abort ();
> +    }
>  }
>
>  /* Used to decide how to sort relocs in an optimal manner for the
> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
> index 1ce682a97ac..6223281acb5 100644
> --- a/bfd/elfxx-riscv.h
> +++ b/bfd/elfxx-riscv.h
> @@ -27,6 +27,11 @@
>
>  #define RISCV_UNKNOWN_VERSION -1
>
> +typedef enum
> +{
> +    PLT_NORMAL    = 0x0,  /* Normal plts.  */
> +} riscv_plt_type;
> +
>  struct riscv_elf_params
>  {
>    /* Whether to relax code sequences to GP-relative addressing.  */
> --
> 2.34.1
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20250610/28de9834/attachment-0001.htm>


More information about the Binutils mailing list