@@ -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
339370static 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
386475static 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
420543static 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
0 commit comments