[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