From: Kito Cheng Date: Wed, 11 Jun 2025 08:33:49 +0000 (+0800) Subject: RISC-V: Support for unlabeled landing pad PLT generation X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9b4b518eceaa1f59acfb88013406b4203f6a3016;p=thirdparty%2Fbinutils-gdb.git RISC-V: Support for unlabeled landing pad PLT generation 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 --- diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 49e812ea99c..790f0397cf5 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -317,6 +317,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 @@ -334,6 +340,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 @@ -381,6 +412,64 @@ 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 @@ -415,6 +504,40 @@ 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; +} + /* Create an entry in an RISC-V ELF linker hash table. */ static struct bfd_hash_entry * @@ -541,6 +664,13 @@ setup_plt_values (struct bfd *output_bfd, 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, @@ -3717,6 +3847,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 (); } @@ -5823,6 +5956,13 @@ 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->output_bfd, riscv_elf_hash_table (info), + _bfd_riscv_elf_tdata (info->output_bfd)->plt_type); + return pbfd; } @@ -5873,6 +6013,7 @@ elfNN_riscv_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, #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 d8845afb666..db494d08a0c 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 7fca806b643..2b146afd868 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]+ : +.*:[ ]+[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]+ +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+t1,t3 + +[0-9a-f]+ : +.*:[ ]+[0-9a-f]+[ ]+lpad[ ]+0x0 +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+t3,0x1 +.*:[ ]+[0-9a-f]+[ ]+ld[ ]+t3,[0-9]+\(t3\) # [0-9a-f]+ +.*:[ ]+[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: