aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@sifive.com>2025-06-11 16:33:49 +0800
committerNelson Chu <nelson@rivosinc.com>2025-06-24 18:14:45 +0800
commit9b4b518eceaa1f59acfb88013406b4203f6a3016 (patch)
treeb4164fe767affa3a4e07b121246d21499f3bc02f
parent84eb7d284b3ae07ee894a1f21defc3c9669297b7 (diff)
downloadbinutils-9b4b518eceaa1f59acfb88013406b4203f6a3016.zip
binutils-9b4b518eceaa1f59acfb88013406b4203f6a3016.tar.gz
binutils-9b4b518eceaa1f59acfb88013406b4203f6a3016.tar.bz2
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
-rw-r--r--bfd/elfnn-riscv.c141
-rw-r--r--bfd/elfxx-riscv.h3
-rw-r--r--include/opcode/riscv.h1
-rw-r--r--ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp2
-rw-r--r--ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.d35
-rw-r--r--ld/testsuite/ld-riscv-elf/zicfilp-unlabeled-plt.s21
6 files changed, 202 insertions, 1 deletions
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 49e812e..790f0397 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 d8845af..db494d0 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 7fca806..2b146af 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 e03e44a..e103df6 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 0000000..2181fc4
--- /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 0000000..628fca8
--- /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: