Skip to content

Commit a566eaf

Browse files
kito-chenglgaver2
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 1e60adc commit a566eaf

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
@@ -320,6 +320,12 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
320320
#define PLT_ENTRY_INSNS 4
321321
#define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4)
322322
#define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4)
323+
324+
#define PLT_ZICFILP_UNLABELED_HEADER_INSNS 12
325+
#define PLT_ZICFILP_UNLABELED_ENTRY_INSNS 4
326+
#define PLT_ZICFILP_UNLABELED_HEADER_SIZE (PLT_ZICFILP_UNLABELED_HEADER_INSNS * 4)
327+
#define PLT_ZICFILP_UNLABELED_ENTRY_SIZE (PLT_ZICFILP_UNLABELED_ENTRY_INSNS * 4)
328+
323329
#define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
324330
#define TLS_GD_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
325331
#define TLS_IE_GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
@@ -339,6 +345,31 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
339345
# define MATCH_LREG MATCH_LQ
340346
#endif
341347

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

344375
static bool
@@ -386,6 +417,64 @@ riscv_make_plt_header (bfd *output_bfd, struct riscv_elf_link_hash_table *htab)
386417
return true;
387418
}
388419

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

391480
static bool
@@ -420,6 +509,40 @@ riscv_make_plt_entry (bfd *output_bfd, asection *gotsec, bfd_vma got_offset,
420509
return true;
421510
}
422511

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

425548
static struct bfd_hash_entry *
@@ -546,6 +669,13 @@ setup_plt_values (struct bfd *output_bfd,
546669
htab->make_plt_entry = riscv_make_plt_entry;
547670
break;
548671

672+
case PLT_ZICFILP_UNLABELED:
673+
htab->plt_header_size = PLT_ZICFILP_UNLABELED_HEADER_SIZE;
674+
htab->plt_entry_size = PLT_ZICFILP_UNLABELED_ENTRY_SIZE;
675+
htab->make_plt_header = riscv_make_plt_zicfilp_unlabeled_header;
676+
htab->make_plt_entry = riscv_make_plt_zicfilp_unlabeled_entry;
677+
break;
678+
549679
default:
550680
_bfd_error_handler (_("%pB: error: unsupported PLT type: %u"),
551681
output_bfd,
@@ -3745,6 +3875,9 @@ riscv_elf_plt_sym_val (bfd_vma i, const asection *plt,
37453875
case PLT_NORMAL:
37463876
return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);
37473877

3878+
case PLT_ZICFILP_UNLABELED:
3879+
return plt->vma + PLT_ZICFILP_UNLABELED_HEADER_SIZE + (i * PLT_ZICFILP_UNLABELED_ENTRY_SIZE);
3880+
37483881
default:
37493882
abort ();
37503883
}
@@ -5855,6 +5988,13 @@ elfNN_riscv_link_setup_gnu_properties (struct bfd_link_info *info)
58555988
bfd *pbfd = _bfd_riscv_elf_link_setup_gnu_properties (info, &and_prop);
58565989

58575990
_bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop = and_prop;
5991+
5992+
if (and_prop & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
5993+
_bfd_riscv_elf_tdata (info->output_bfd)->plt_type = PLT_ZICFILP_UNLABELED;
5994+
5995+
setup_plt_values (info->output_bfd, riscv_elf_hash_table (info),
5996+
_bfd_riscv_elf_tdata (info->output_bfd)->plt_type);
5997+
58585998
return pbfd;
58595999
}
58606000

@@ -5905,6 +6045,7 @@ elfNN_riscv_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd,
59056045
#define elf_info_to_howto riscv_info_to_howto_rela
59066046
#define bfd_elfNN_bfd_relax_section _bfd_riscv_relax_section
59076047
#define bfd_elfNN_mkobject elfNN_riscv_mkobject
6048+
#define bfd_elfNN_get_synthetic_symtab elfNN_riscv_get_synthetic_symtab
59086049
#define elf_backend_additional_program_headers \
59096050
riscv_elf_additional_program_headers
59106051
#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
@@ -462,6 +462,7 @@ static inline unsigned int riscv_insn_length (insn_t insn)
462462

463463
/* ABI names for selected x-registers. */
464464

465+
#define X_ZERO 0
465466
#define X_RA 1
466467
#define X_SP 2
467468
#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)