[PATCH 4/4] RISC-V: Support for unlabeled landing pad PLT generation

Nelson Chu nelson@rivosinc.com
Tue Jun 10 07:31:44 GMT 2025


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

> This patch adds support for generating unlabeled landing pad PLT entries
> for the RISC-V architecture. Unlabeled landing pad will place a LPAD
> instruction at the PLT entry and PLT header, also PLT header will have
> few changes due to the offset is different from the original one.
>
> Ref: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/417
> ---
>  bfd/elfnn-riscv.c                             | 168 ++++++++++++++++++
>  bfd/elfxx-riscv.h                             |   3 +-
>  include/opcode/riscv.h                        |   1 +
>  ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp    |   2 +
>  .../ld-riscv-elf/zicfilp-unlabeled-plt.d      |  35 ++++
>  .../ld-riscv-elf/zicfilp-unlabeled-plt.s      |  21 +++
>  6 files changed, 229 insertions(+), 1 deletion(-)
>  create mode 100644 ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.d
>  create mode 100644 ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.s
>
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 84f36960d49..c78817ea5d6 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -273,6 +273,8 @@ riscv_make_plt_header (bfd *, struct
> riscv_elf_link_hash_table *);
>  static bool
>  riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
>
> +static void
> +setup_plt_values (struct bfd_link_info *, unsigned);
>  void
>  riscv_elfNN_set_options (struct bfd_link_info *link_info,
>                          struct riscv_elf_params *params)
> @@ -320,6 +322,12 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
>  #define PLT_ENTRY_INSNS 4
>  #define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4)
>  #define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4)
> +
> +#define PLT_ZICFILP_UNLABELED_HEADER_INSNS 12
> +#define PLT_ZICFILP_UNLABELED_ENTRY_INSNS 4
> +#define PLT_ZICFILP_UNLABELED_HEADER_SIZE
> (PLT_ZICFILP_UNLABELED_HEADER_INSNS * 4)
> +#define PLT_ZICFILP_UNLABELED_ENTRY_SIZE
> (PLT_ZICFILP_UNLABELED_ENTRY_INSNS * 4)
> +
>  #define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
>  #define TLS_GD_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
>  #define TLS_IE_GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
> @@ -337,6 +345,31 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
>  # define MATCH_LREG MATCH_LD
>  #endif
>
> +
> +/* Check whether the compact PLT is used in this object.  Tools need this
> +   to dump the correct PLT header contents.  */
> +
> +static long
> +elfNN_riscv_get_synthetic_symtab (bfd *abfd,
> +                                 long symcount,
> +                                 asymbol **syms,
> +                                 long dynsymcount,
> +                                 asymbol **dynsyms,
> +                                 asymbol **ret)
> +{
> +  /* Check Zicfilp PLT.  */
> +  elf_property *prop;
> +  prop = _bfd_elf_get_property (abfd, GNU_PROPERTY_RISCV_FEATURE_1_AND,
> 4);
> +  if (prop)
> +    {
> +      if (prop->u.number & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
> +        _bfd_riscv_elf_tdata (abfd)->plt_type |= PLT_ZICFILP_UNLABELED;
> +    }
> +
> +  return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
> +                                       dynsymcount, dynsyms, ret);
> +}
> +
>  /* Generate a PLT header.  */
>
>  static bool
> @@ -384,6 +417,65 @@ riscv_make_plt_header (bfd *output_bfd, struct
> riscv_elf_link_hash_table *htab)
>    return true;
>  }
>
> +
> +static bool
> +riscv_make_plt_zicfilp_unlabeled_header (bfd *output_bfd,
> +                                        struct riscv_elf_link_hash_table
> *htab)
> +{
> +  /*
> +      lpad   0  # disable label checking
> +      auipc  t2, %hi(.got.plt)          # Rewrite this to using
> +      sub    t1, t1, t3                 # shifted .got.plt offset + hdr
> size + 16
> +      l[w|d] t3, %lo(1b)(t2)            # _dl_runtime_resolve
> +      addi   t1, t1, -(hdr size + 12)   # shifted .got.plt offset
> +      addi   t0, t2, %pcrel_lo(1b)      # &.got.plt
> +      srli   t1, t1, log2(16/PTRSIZE)   # .got.plt offset
> +      l[w|d] t0, PTRSIZE(t0)            # link map
> +      jr     t3
> +      nop
> +      nop
> +      nop  */
> +
> +  /* RVE has no t3 register, so this won't work, and is not supported.  */
> +  if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
> +    {
> +      _bfd_error_handler (_("%pB: warning: RVE PLT generation not
> supported"),
> +                         output_bfd);
> +      return false;
> +    }
> +
> +  asection *gotplt = htab->elf.sgotplt;
> +  bfd_vma gotplt_addr = sec_addr (gotplt);
> +
> +  asection *splt = htab->elf.splt;
> +  bfd_vma plt_header_addr = sec_addr (splt);
> +
> +  bfd_vma auipc_addr = plt_header_addr + 4;
> +  /* Add INSN_BYTES to skip the lpad instruction.  */
> +  bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr,
> auipc_addr);
> +  bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr,
> auipc_addr);
> +
> +  uint32_t header[PLT_ZICFILP_UNLABELED_HEADER_INSNS];
> +  header[0] = RISCV_UTYPE (LPAD, X_ZERO, 0);
> +  header[1] = RISCV_UTYPE (AUIPC, X_T2, gotplt_offset_high);
> +  header[2] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T3);
> +  header[3] = RISCV_ITYPE (LREG, X_T3, X_T2, gotplt_offset_low);
> +  header[4] = RISCV_ITYPE (ADDI, X_T1, X_T1,
> +                          (uint32_t) -(PLT_ZICFILP_UNLABELED_HEADER_SIZE
> + 16));
> +  header[5] = RISCV_ITYPE (ADDI, X_T0, X_T2, gotplt_offset_low);
> +  header[6] = RISCV_ITYPE (SRLI, X_T1, X_T1, 4 -
> RISCV_ELF_LOG_WORD_BYTES);
> +  header[7] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
> +  header[8] = RISCV_ITYPE (JALR, 0, X_T3, 0);
> +  header[9] = RISCV_NOP;
> +  header[10] = RISCV_NOP;
> +  header[11] = RISCV_NOP;
> +
> +  for (int i = 0; i < PLT_ZICFILP_UNLABELED_HEADER_INSNS; i++)
> +    bfd_putl32 (header[i], splt->contents + 4 * i);
> +
> +  return true;
> +}
> +
>  /* Generate a PLT entry.  */
>
>  static bool
> @@ -418,6 +510,72 @@ riscv_make_plt_entry (bfd *output_bfd, asection
> *gotsec, bfd_vma got_offset,
>    return true;
>  }
>
> +static bool
> +riscv_make_plt_zicfilp_unlabeled_entry (bfd *output_bfd, asection *got,
> +                                       bfd_vma got_offset, asection *plt,
> +                                       bfd_vma plt_offset)
> +{
> +  /*    lpad    0
> +    1:  auipc   t3, %pcrel_hi(function@.got.plt)
> +       l[w|d]  t3, %pcrel_lo(1b)(t3)
> +       jalr    t1, t3 */
> +
> +  /* RVE has no t3 register, so this won't work, and is not supported.  */
> +  if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
> +    {
> +      _bfd_error_handler (_("%pB: warning: RVE PLT generation not
> supported"),
> +                         output_bfd);
> +      return false;
> +    }
> +
> +  bfd_vma got_entry_addr = sec_addr(got) + got_offset;
> +  bfd_vma plt_entry_addr = sec_addr(plt) + plt_offset;
> +  bfd_vma auipc_addr = plt_entry_addr + 4;
> +  uint32_t entry[PLT_ZICFILP_UNLABELED_ENTRY_INSNS];
> +  entry[0] = RISCV_UTYPE (LPAD, X_ZERO, 0);
> +  entry[1] = RISCV_UTYPE (AUIPC, X_T3, RISCV_PCREL_HIGH_PART
> (got_entry_addr, auipc_addr));
> +  entry[2] = RISCV_ITYPE (LREG,  X_T3, X_T3, RISCV_PCREL_LOW_PART
> (got_entry_addr, auipc_addr));
> +  entry[3] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
> +
> +  bfd_byte *loc = plt->contents + plt_offset;
> +  for (int i = 0; i < PLT_ZICFILP_UNLABELED_ENTRY_INSNS; i++)
> +    bfd_putl32 (entry[i], loc + 4 * i);
> +
> +  return true;
> +}
> +
> +static void
> +setup_plt_values (struct bfd_link_info *link_info,
> +                 unsigned plt_type)
> +{
> +  struct bfd *output_bfd = link_info->output_bfd;
> +  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table
> (link_info);
> +
> +  switch (plt_type)
> +    {
> +    case PLT_NORMAL:
> +      htab->plt_header_size = PLT_HEADER_SIZE;
> +      htab->plt_entry_size = PLT_ENTRY_SIZE;
> +      htab->make_plt_header = riscv_make_plt_header;
> +      htab->make_plt_entry = riscv_make_plt_entry;
> +      break;
> +
> +    case PLT_ZICFILP_UNLABELED:
> +      htab->plt_header_size = PLT_ZICFILP_UNLABELED_HEADER_SIZE;
> +      htab->plt_entry_size = PLT_ZICFILP_UNLABELED_ENTRY_SIZE;
> +      htab->make_plt_header = riscv_make_plt_zicfilp_unlabeled_header;
> +      htab->make_plt_entry = riscv_make_plt_zicfilp_unlabeled_entry;
> +      break;
> +
> +    default:
> +      _bfd_error_handler (_("%pB: error: unsupported PLT type: %u"),
> +                         output_bfd,
> +                         plt_type);
> +      bfd_set_error (bfd_error_bad_value);
> +      break;
> +    }
> +}
> +

 /* Create an entry in an RISC-V ELF linker hash table.  */
>
>  static struct bfd_hash_entry *
> @@ -3698,6 +3856,9 @@ riscv_elf_plt_sym_val (bfd_vma i, const asection
> *plt,
>      case PLT_NORMAL:
>        return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);
>
> +    case PLT_ZICFILP_UNLABELED:
> +      return plt->vma + PLT_ZICFILP_UNLABELED_HEADER_SIZE + (i *
> PLT_ZICFILP_UNLABELED_ENTRY_SIZE);
> +
>      default:
>        abort ();
>      }
> @@ -5803,6 +5964,12 @@ elfNN_riscv_link_setup_gnu_properties (struct
> bfd_link_info *info)
>    bfd *pbfd = _bfd_riscv_elf_link_setup_gnu_properties (info, &and_prop);
>
>    _bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop = and_prop;
> +
> +  if (and_prop & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
> +  _bfd_riscv_elf_tdata (info->output_bfd)->plt_type =
> PLT_ZICFILP_UNLABELED;
> +
> +  setup_plt_values (info, _bfd_riscv_elf_tdata
> (info->output_bfd)->plt_type);
> +
>

The plt_type of tdata was initialized to zero (PLT_NORMAL), and the plt
values of htab were initialized in riscv_elf_link_hash_table_create.
Therefore, just curious once the plt type of output is changed to cfi style
(or whatever in the future), will it possible to change to others later?
Which means, the setup_plt_values seems redundant to do stuffs for
PLT_NORMAL?  Or maybe we can just call "setup_plt_values (info,
PLT_NORMAL)" in the riscv_elf_link_hash_table_create to initialize the ply
values.

Otherwise looks good, thanks.

Nelson

   return pbfd;
>  }
>
> @@ -5855,6 +6022,7 @@ elfNN_riscv_merge_gnu_properties (struct
> bfd_link_info *info,
>  #define elf_info_to_howto                      riscv_info_to_howto_rela
>  #define bfd_elfNN_bfd_relax_section            _bfd_riscv_relax_section
>  #define bfd_elfNN_mkobject                     elfNN_riscv_mkobject
> +#define bfd_elfNN_get_synthetic_symtab
>  elfNN_riscv_get_synthetic_symtab
>  #define elf_backend_additional_program_headers \
>    riscv_elf_additional_program_headers
>  #define elf_backend_modify_segment_map
>  riscv_elf_modify_segment_map
> diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
> index 3b60c65fe55..0e89d9b68f7 100644
> --- a/bfd/elfxx-riscv.h
> +++ b/bfd/elfxx-riscv.h
> @@ -29,7 +29,8 @@
>
>  typedef enum
>  {
> -    PLT_NORMAL    = 0x0,  /* Normal plts.  */
> +    PLT_NORMAL            = 0x0,  /* Normal plts.  */
> +    PLT_ZICFILP_UNLABELED = 0x1   /* Landing pad unlabeled plts.  */
>  } riscv_plt_type;
>
>  struct riscv_elf_params
> diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> index c5dd546aac5..48f32fd19ed 100644
> --- a/include/opcode/riscv.h
> +++ b/include/opcode/riscv.h
> @@ -421,6 +421,7 @@ static inline unsigned int riscv_insn_length (insn_t
> insn)
>
>  /* ABI names for selected x-registers.  */
>
> +#define X_ZERO 0
>  #define X_RA 1
>  #define X_SP 2
>  #define X_GP 3
> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> index e03e44ae4a2..e103df66e11 100644
> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> @@ -233,6 +233,8 @@ if [istarget "riscv*-*-*"] {
>      run_dump_test "property-combine-and-2"
>      run_dump_test "property-combine-and-3"
>
> +    run_dump_test "zicfilp-unlabeled-plt"
> +
>      # IFUNC testcases.
>      # Check IFUNC by single type relocs.
>      run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
> diff --git a/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.d
> b/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.d
> new file mode 100644
> index 00000000000..2181fc49786
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.d
> @@ -0,0 +1,35 @@
> +#name: Unlabled landing pad PLT
> +#source: zicfilp-unlabeled-plt.s
> +#ld: -shared
> +#objdump: -dr -j .plt
> +#as: -march=rv64gc_zicfilp
> +
> +[^:]*: *file format elf64-.*riscv
> +
> +Disassembly of section \.plt:
> +
> +[0-9a-f]+ <\.plt>:
> +.*:[   ]+[0-9a-f]+[    ]+lpad[         ]+0x0
> +.*:[   ]+[0-9a-f]+[    ]+auipc[        ]+t2,0x[0-9a-f]+
> +.*:[   ]+[0-9a-f]+[    ]+sub[  ]+t1,t1,t3
> +.*:[   ]+[0-9a-f]+[    ]+ld[   ]+t3,[0-9]+\(t2\) # [0-9a-f]+ <\.got\.plt>
> +.*:[   ]+[0-9a-f]+[    ]+addi[         ]+t1,t1,-64
> +.*:[   ]+[0-9a-f]+[    ]+addi[         ]+t0,t2,[0-9]+
> +.*:[   ]+[0-9a-f]+[    ]+srli[         ]+t1,t1,0x1
> +.*:[   ]+[0-9a-f]+[    ]+ld[   ]+t0,8\(t0\)
> +.*:[   ]+[0-9a-f]+[    ]+jr[   ]+t3
> +.*:[   ]+[0-9a-f]+[    ]+nop
> +.*:[   ]+[0-9a-f]+[    ]+nop
> +.*:[   ]+[0-9a-f]+[    ]+nop
> +
> +[0-9a-f]+ <foo@plt>:
> +.*:[   ]+[0-9a-f]+[    ]+lpad[         ]+0x0
> +.*:[   ]+[0-9a-f]+[    ]+auipc[        ]+t3,0x[0-9a-f]+
> +.*:[   ]+[0-9a-f]+[    ]+ld[   ]+t3,[0-9]+\(t3\) # [0-9a-f]+ <foo>
> +.*:[   ]+[0-9a-f]+[    ]+jalr[         ]+t1,t3
> +
> +[0-9a-f]+ <bar@plt>:
> +.*:[   ]+[0-9a-f]+[    ]+lpad[         ]+0x0
> +.*:[   ]+[0-9a-f]+[    ]+auipc[        ]+t3,0x1
> +.*:[   ]+[0-9a-f]+[    ]+ld[   ]+t3,[0-9]+\(t3\) # [0-9a-f]+ <bar>
> +.*:[   ]+[0-9a-f]+[    ]+jalr[         ]+t1,t3
> diff --git a/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.s
> b/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.s
> new file mode 100644
> index 00000000000..628fca85aa0
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.s
> @@ -0,0 +1,21 @@
> +       .text
> +       .globl _start
> +       .type _start,@function
> +_start:
> +       call foo
> +       call bar
> +       .section ".note.gnu.property", "a"
> +       .p2align 3
> +       .long 1f - 0f           /* name length */
> +       .long 5f - 2f           /* data length */
> +       .long 5                 /* note type */
> +0:     .asciz "GNU"            /* vendor name */
> +1:
> +       .p2align 3
> +2:     .long 0xc0000000        /* pr_type.  */
> +       .long 4f - 3f           /* pr_datasz.  */
> +3:
> +       .long 0x1               /* CFI_LP.  */
> +4:
> +       .p2align 3
> +5:
> --
> 2.34.1
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20250610/626ac8e9/attachment-0001.htm>


More information about the Binutils mailing list