Skip to content

Commit 9b4b518

Browse files
kito-chengNelson Chu
authored andcommitted
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: riscv-non-isa/riscv-elf-psabi-doc#417
1 parent 84eb7d2 commit 9b4b518

File tree

6 files changed

+202
-1
lines changed

6 files changed

+202
-1
lines changed

bfd/elfnn-riscv.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
317317
#define PLT_ENTRY_INSNS 4
318318
#define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4)
319319
#define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4)
320+
321+
#define PLT_ZICFILP_UNLABELED_HEADER_INSNS 12
322+
#define PLT_ZICFILP_UNLABELED_ENTRY_INSNS 4
323+
#define PLT_ZICFILP_UNLABELED_HEADER_SIZE (PLT_ZICFILP_UNLABELED_HEADER_INSNS * 4)
324+
#define PLT_ZICFILP_UNLABELED_ENTRY_SIZE (PLT_ZICFILP_UNLABELED_ENTRY_INSNS * 4)
325+
320326
#define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
321327
#define TLS_GD_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
322328
#define TLS_IE_GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
@@ -334,6 +340,31 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
334340
# define MATCH_LREG MATCH_LD
335341
#endif
336342

343+
344+
/* Check whether the compact PLT is used in this object. Tools need this
345+
to dump the correct PLT header contents. */
346+
347+
static long
348+
elfNN_riscv_get_synthetic_symtab (bfd *abfd,
349+
long symcount,
350+
asymbol **syms,
351+
long dynsymcount,
352+
asymbol **dynsyms,
353+
asymbol **ret)
354+
{
355+
/* Check Zicfilp PLT. */
356+
elf_property *prop;
357+
prop = _bfd_elf_get_property (abfd, GNU_PROPERTY_RISCV_FEATURE_1_AND, 4);
358+
if (prop)
359+
{
360+
if (prop->u.number & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
361+
_bfd_riscv_elf_tdata (abfd)->plt_type |= PLT_ZICFILP_UNLABELED;
362+
}
363+
364+
return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
365+
dynsymcount, dynsyms, ret);
366+
}
367+
337368
/* Generate a PLT header. */
338369

339370
static bool
@@ -381,6 +412,64 @@ riscv_make_plt_header (bfd *output_bfd, struct riscv_elf_link_hash_table *htab)
381412
return true;
382413
}
383414

415+
static bool
416+
riscv_make_plt_zicfilp_unlabeled_header (bfd *output_bfd,
417+
struct riscv_elf_link_hash_table *htab)
418+
{
419+
/*
420+
lpad 0 # disable label checking
421+
auipc t2, %hi(.got.plt) # Rewrite this to using
422+
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 16
423+
l[w|d] t3, %lo(1b)(t2) # _dl_runtime_resolve
424+
addi t1, t1, -(hdr size + 12) # shifted .got.plt offset
425+
addi t0, t2, %pcrel_lo(1b) # &.got.plt
426+
srli t1, t1, log2(16/PTRSIZE) # .got.plt offset
427+
l[w|d] t0, PTRSIZE(t0) # link map
428+
jr t3
429+
nop
430+
nop
431+
nop */
432+
433+
/* RVE has no t3 register, so this won't work, and is not supported. */
434+
if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
435+
{
436+
_bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
437+
output_bfd);
438+
return false;
439+
}
440+
441+
asection *gotplt = htab->elf.sgotplt;
442+
bfd_vma gotplt_addr = sec_addr (gotplt);
443+
444+
asection *splt = htab->elf.splt;
445+
bfd_vma plt_header_addr = sec_addr (splt);
446+
447+
bfd_vma auipc_addr = plt_header_addr + 4;
448+
/* Add INSN_BYTES to skip the lpad instruction. */
449+
bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, auipc_addr);
450+
bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, auipc_addr);
451+
452+
uint32_t header[PLT_ZICFILP_UNLABELED_HEADER_INSNS];
453+
header[0] = RISCV_UTYPE (LPAD, X_ZERO, 0);
454+
header[1] = RISCV_UTYPE (AUIPC, X_T2, gotplt_offset_high);
455+
header[2] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T3);
456+
header[3] = RISCV_ITYPE (LREG, X_T3, X_T2, gotplt_offset_low);
457+
header[4] = RISCV_ITYPE (ADDI, X_T1, X_T1,
458+
(uint32_t) -(PLT_ZICFILP_UNLABELED_HEADER_SIZE + 16));
459+
header[5] = RISCV_ITYPE (ADDI, X_T0, X_T2, gotplt_offset_low);
460+
header[6] = RISCV_ITYPE (SRLI, X_T1, X_T1, 4 - RISCV_ELF_LOG_WORD_BYTES);
461+
header[7] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
462+
header[8] = RISCV_ITYPE (JALR, 0, X_T3, 0);
463+
header[9] = RISCV_NOP;
464+
header[10] = RISCV_NOP;
465+
header[11] = RISCV_NOP;
466+
467+
for (int i = 0; i < PLT_ZICFILP_UNLABELED_HEADER_INSNS; i++)
468+
bfd_putl32 (header[i], splt->contents + 4 * i);
469+
470+
return true;
471+
}
472+
384473
/* Generate a PLT entry. */
385474

386475
static bool
@@ -415,6 +504,40 @@ riscv_make_plt_entry (bfd *output_bfd, asection *gotsec, bfd_vma got_offset,
415504
return true;
416505
}
417506

507+
static bool
508+
riscv_make_plt_zicfilp_unlabeled_entry (bfd *output_bfd, asection *got,
509+
bfd_vma got_offset, asection *plt,
510+
bfd_vma plt_offset)
511+
{
512+
/* lpad 0
513+
1: auipc t3, %pcrel_hi([email protected])
514+
l[w|d] t3, %pcrel_lo(1b)(t3)
515+
jalr t1, t3 */
516+
517+
/* RVE has no t3 register, so this won't work, and is not supported. */
518+
if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
519+
{
520+
_bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
521+
output_bfd);
522+
return false;
523+
}
524+
525+
bfd_vma got_entry_addr = sec_addr(got) + got_offset;
526+
bfd_vma plt_entry_addr = sec_addr(plt) + plt_offset;
527+
bfd_vma auipc_addr = plt_entry_addr + 4;
528+
uint32_t entry[PLT_ZICFILP_UNLABELED_ENTRY_INSNS];
529+
entry[0] = RISCV_UTYPE (LPAD, X_ZERO, 0);
530+
entry[1] = RISCV_UTYPE (AUIPC, X_T3, RISCV_PCREL_HIGH_PART (got_entry_addr, auipc_addr));
531+
entry[2] = RISCV_ITYPE (LREG, X_T3, X_T3, RISCV_PCREL_LOW_PART (got_entry_addr, auipc_addr));
532+
entry[3] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
533+
534+
bfd_byte *loc = plt->contents + plt_offset;
535+
for (int i = 0; i < PLT_ZICFILP_UNLABELED_ENTRY_INSNS; i++)
536+
bfd_putl32 (entry[i], loc + 4 * i);
537+
538+
return true;
539+
}
540+
418541
/* Create an entry in an RISC-V ELF linker hash table. */
419542

420543
static struct bfd_hash_entry *
@@ -541,6 +664,13 @@ setup_plt_values (struct bfd *output_bfd,
541664
htab->make_plt_entry = riscv_make_plt_entry;
542665
break;
543666

667+
case PLT_ZICFILP_UNLABELED:
668+
htab->plt_header_size = PLT_ZICFILP_UNLABELED_HEADER_SIZE;
669+
htab->plt_entry_size = PLT_ZICFILP_UNLABELED_ENTRY_SIZE;
670+
htab->make_plt_header = riscv_make_plt_zicfilp_unlabeled_header;
671+
htab->make_plt_entry = riscv_make_plt_zicfilp_unlabeled_entry;
672+
break;
673+
544674
default:
545675
_bfd_error_handler (_("%pB: error: unsupported PLT type: %u"),
546676
output_bfd,
@@ -3717,6 +3847,9 @@ riscv_elf_plt_sym_val (bfd_vma i, const asection *plt,
37173847
case PLT_NORMAL:
37183848
return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);
37193849

3850+
case PLT_ZICFILP_UNLABELED:
3851+
return plt->vma + PLT_ZICFILP_UNLABELED_HEADER_SIZE + (i * PLT_ZICFILP_UNLABELED_ENTRY_SIZE);
3852+
37203853
default:
37213854
abort ();
37223855
}
@@ -5823,6 +5956,13 @@ elfNN_riscv_link_setup_gnu_properties (struct bfd_link_info *info)
58235956
bfd *pbfd = _bfd_riscv_elf_link_setup_gnu_properties (info, &and_prop);
58245957

58255958
_bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop = and_prop;
5959+
5960+
if (and_prop & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
5961+
_bfd_riscv_elf_tdata (info->output_bfd)->plt_type = PLT_ZICFILP_UNLABELED;
5962+
5963+
setup_plt_values (info->output_bfd, riscv_elf_hash_table (info),
5964+
_bfd_riscv_elf_tdata (info->output_bfd)->plt_type);
5965+
58265966
return pbfd;
58275967
}
58285968

@@ -5873,6 +6013,7 @@ elfNN_riscv_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd,
58736013
#define elf_info_to_howto riscv_info_to_howto_rela
58746014
#define bfd_elfNN_bfd_relax_section _bfd_riscv_relax_section
58756015
#define bfd_elfNN_mkobject elfNN_riscv_mkobject
6016+
#define bfd_elfNN_get_synthetic_symtab elfNN_riscv_get_synthetic_symtab
58766017
#define elf_backend_additional_program_headers \
58776018
riscv_elf_additional_program_headers
58786019
#define elf_backend_modify_segment_map riscv_elf_modify_segment_map

bfd/elfxx-riscv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929

3030
typedef enum
3131
{
32-
PLT_NORMAL = 0x0, /* Normal plts. */
32+
PLT_NORMAL = 0x0, /* Normal plts. */
33+
PLT_ZICFILP_UNLABELED = 0x1 /* Landing pad unlabeled plts. */
3334
} riscv_plt_type;
3435

3536
struct riscv_elf_params

include/opcode/riscv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ static inline unsigned int riscv_insn_length (insn_t insn)
421421

422422
/* ABI names for selected x-registers. */
423423

424+
#define X_ZERO 0
424425
#define X_RA 1
425426
#define X_SP 2
426427
#define X_GP 3

ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ if [istarget "riscv*-*-*"] {
233233
run_dump_test "property-combine-and-2"
234234
run_dump_test "property-combine-and-3"
235235

236+
run_dump_test "zicfilp-unlabeled-plt"
237+
236238
# IFUNC testcases.
237239
# Check IFUNC by single type relocs.
238240
run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#name: Unlabled landing pad PLT
2+
#source: zicfilp-unlabeled-plt.s
3+
#ld: -shared
4+
#objdump: -dr -j .plt
5+
#as: -march=rv64gc_zicfilp
6+
7+
[^:]*: *file format elf64-.*riscv
8+
9+
Disassembly of section \.plt:
10+
11+
[0-9a-f]+ <\.plt>:
12+
.*:[ ]+[0-9a-f]+[ ]+lpad[ ]+0x0
13+
.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+t2,0x[0-9a-f]+
14+
.*:[ ]+[0-9a-f]+[ ]+sub[ ]+t1,t1,t3
15+
.*:[ ]+[0-9a-f]+[ ]+ld[ ]+t3,[0-9]+\(t2\) # [0-9a-f]+ <\.got\.plt>
16+
.*:[ ]+[0-9a-f]+[ ]+addi[ ]+t1,t1,-64
17+
.*:[ ]+[0-9a-f]+[ ]+addi[ ]+t0,t2,[0-9]+
18+
.*:[ ]+[0-9a-f]+[ ]+srli[ ]+t1,t1,0x1
19+
.*:[ ]+[0-9a-f]+[ ]+ld[ ]+t0,8\(t0\)
20+
.*:[ ]+[0-9a-f]+[ ]+jr[ ]+t3
21+
.*:[ ]+[0-9a-f]+[ ]+nop
22+
.*:[ ]+[0-9a-f]+[ ]+nop
23+
.*:[ ]+[0-9a-f]+[ ]+nop
24+
25+
[0-9a-f]+ <foo@plt>:
26+
.*:[ ]+[0-9a-f]+[ ]+lpad[ ]+0x0
27+
.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+t3,0x[0-9a-f]+
28+
.*:[ ]+[0-9a-f]+[ ]+ld[ ]+t3,[0-9]+\(t3\) # [0-9a-f]+ <foo>
29+
.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+t1,t3
30+
31+
[0-9a-f]+ <bar@plt>:
32+
.*:[ ]+[0-9a-f]+[ ]+lpad[ ]+0x0
33+
.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+t3,0x1
34+
.*:[ ]+[0-9a-f]+[ ]+ld[ ]+t3,[0-9]+\(t3\) # [0-9a-f]+ <bar>
35+
.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+t1,t3
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.text
2+
.globl _start
3+
.type _start,@function
4+
_start:
5+
call foo
6+
call bar
7+
.section ".note.gnu.property", "a"
8+
.p2align 3
9+
.long 1f - 0f /* name length */
10+
.long 5f - 2f /* data length */
11+
.long 5 /* note type */
12+
0: .asciz "GNU" /* vendor name */
13+
1:
14+
.p2align 3
15+
2: .long 0xc0000000 /* pr_type. */
16+
.long 4f - 3f /* pr_datasz. */
17+
3:
18+
.long 0x1 /* CFI_LP. */
19+
4:
20+
.p2align 3
21+
5:

0 commit comments

Comments
 (0)