Skip to content

Commit 51a39a5

Browse files
kito-chengNelson Chu
authored andcommitted
RISC-V: Refactor PLT generation
The goal of this refactor is to improve the possiblity of having different PLT generation code for different RISC-V ABIs. The changes include: - Extract PLT generation logic into individual functions. - Keep the PLT generation data in riscv_elf_link_hash_table. In the following patches, we will use this framework to implement different PLT.
1 parent c287307 commit 51a39a5

File tree

2 files changed

+96
-35
lines changed

2 files changed

+96
-35
lines changed

bfd/elfnn-riscv.c

Lines changed: 91 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ struct _bfd_riscv_elf_obj_tdata
176176

177177
/* tls_type for each local got entry. */
178178
char *local_got_tls_type;
179+
180+
/* PLT type. */
181+
riscv_plt_type plt_type;
179182
};
180183

181184
#define _bfd_riscv_elf_tdata(abfd) \
@@ -232,6 +235,15 @@ struct riscv_elf_link_hash_table
232235

233236
/* Relocations for variant CC symbols may be present. */
234237
int variant_cc;
238+
239+
/* The number of bytes in the PLT header and enties. */
240+
bfd_size_type plt_header_size;
241+
bfd_size_type plt_entry_size;
242+
243+
/* Functions to make PLT header and entries. */
244+
bool (*make_plt_header) (bfd *output_bfd, struct riscv_elf_link_hash_table *htab);
245+
bool (*make_plt_entry) (bfd *output_bfd, asection *got, bfd_vma got_offset,
246+
asection *plt, bfd_vma plt_offset);
235247
};
236248

237249
/* Instruction access functions. */
@@ -252,6 +264,12 @@ struct riscv_elf_link_hash_table
252264
&& elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA) \
253265
? (struct riscv_elf_link_hash_table *) (p)->hash : NULL)
254266

267+
/* Forward declaration PLT related functions. */
268+
static bool
269+
riscv_make_plt_header (bfd *, struct riscv_elf_link_hash_table *);
270+
static bool
271+
riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
272+
255273
void
256274
riscv_elfNN_set_options (struct bfd_link_info *link_info,
257275
struct riscv_elf_params *params)
@@ -317,9 +335,14 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
317335
/* Generate a PLT header. */
318336

319337
static bool
320-
riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
321-
uint32_t *entry)
338+
riscv_make_plt_header (bfd *output_bfd, struct riscv_elf_link_hash_table *htab)
322339
{
340+
asection *splt = htab->elf.splt;
341+
bfd_vma addr = sec_addr (splt);
342+
343+
asection *sgotplt = htab->elf.sgotplt;
344+
bfd_vma gotplt_addr = sec_addr (sgotplt);
345+
323346
bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, addr);
324347
bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, addr);
325348

@@ -340,6 +363,7 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
340363
l[w|d] t0, PTRSIZE(t0) # link map
341364
jr t3 */
342365

366+
uint32_t entry[PLT_HEADER_INSNS];
343367
entry[0] = RISCV_UTYPE (AUIPC, X_T2, gotplt_offset_high);
344368
entry[1] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T3);
345369
entry[2] = RISCV_ITYPE (LREG, X_T3, X_T2, gotplt_offset_low);
@@ -349,15 +373,20 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
349373
entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
350374
entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0);
351375

376+
for (int i = 0; i < PLT_HEADER_INSNS; i++)
377+
bfd_putl32 (entry[i], splt->contents + 4 * i);
378+
352379
return true;
353380
}
354381

355382
/* Generate a PLT entry. */
356383

357384
static bool
358-
riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
359-
uint32_t *entry)
385+
riscv_make_plt_entry (bfd *output_bfd, asection *gotsec, bfd_vma got_offset,
386+
asection *pltsec, bfd_vma plt_offset)
360387
{
388+
bfd_vma got = sec_addr (gotsec) + got_offset;
389+
bfd_vma addr = sec_addr (pltsec) + plt_offset;
361390
/* RVE has no t3 register, so this won't work, and is not supported. */
362391
if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
363392
{
@@ -371,11 +400,16 @@ riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
371400
jalr t1, t3
372401
nop */
373402

403+
uint32_t entry[PLT_ENTRY_INSNS];
374404
entry[0] = RISCV_UTYPE (AUIPC, X_T3, RISCV_PCREL_HIGH_PART (got, addr));
375405
entry[1] = RISCV_ITYPE (LREG, X_T3, X_T3, RISCV_PCREL_LOW_PART (got, addr));
376406
entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
377407
entry[3] = RISCV_NOP;
378408

409+
bfd_byte *loc = pltsec->contents + plt_offset;
410+
for (int i = 0; i < PLT_ENTRY_INSNS; i++)
411+
bfd_putl32 (entry[i], loc + 4 * i);
412+
379413
return true;
380414
}
381415

@@ -489,6 +523,31 @@ riscv_elf_link_hash_table_free (bfd *obfd)
489523
_bfd_elf_link_hash_table_free (obfd);
490524
}
491525

526+
/* Set up the PLT generation stubs in the hash table. */
527+
528+
static void
529+
setup_plt_values (struct bfd *output_bfd,
530+
struct riscv_elf_link_hash_table *htab,
531+
unsigned plt_type)
532+
{
533+
switch (plt_type)
534+
{
535+
case PLT_NORMAL:
536+
htab->plt_header_size = PLT_HEADER_SIZE;
537+
htab->plt_entry_size = PLT_ENTRY_SIZE;
538+
htab->make_plt_header = riscv_make_plt_header;
539+
htab->make_plt_entry = riscv_make_plt_entry;
540+
break;
541+
542+
default:
543+
_bfd_error_handler (_("%pB: error: unsupported PLT type: %u"),
544+
output_bfd,
545+
plt_type);
546+
bfd_set_error (bfd_error_bad_value);
547+
break;
548+
}
549+
}
550+
492551
/* Create a RISC-V ELF linker hash table. */
493552

494553
static struct bfd_link_hash_table *
@@ -511,6 +570,8 @@ riscv_elf_link_hash_table_create (bfd *abfd)
511570
ret->max_alignment = (bfd_vma) -1;
512571
ret->max_alignment_for_gp = (bfd_vma) -1;
513572

573+
setup_plt_values (abfd, ret, PLT_NORMAL);
574+
514575
/* Create hash table for local ifunc. */
515576
ret->loc_hash_table = htab_try_create (1024,
516577
riscv_elf_local_htab_hash,
@@ -1259,12 +1320,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
12591320
asection *s = htab->elf.splt;
12601321

12611322
if (s->size == 0)
1262-
s->size = PLT_HEADER_SIZE;
1323+
s->size = htab->plt_header_size;
12631324

12641325
h->plt.offset = s->size;
12651326

12661327
/* Make room for this entry. */
1267-
s->size += PLT_ENTRY_SIZE;
1328+
s->size += htab->plt_entry_size;
12681329

12691330
/* We also need to make an entry in the .got.plt section. */
12701331
htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
@@ -1456,6 +1517,7 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
14561517
void *inf)
14571518
{
14581519
struct bfd_link_info *info;
1520+
struct riscv_elf_link_hash_table *htab;
14591521

14601522
if (h->root.type == bfd_link_hash_indirect)
14611523
return true;
@@ -1464,15 +1526,16 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
14641526
h = (struct elf_link_hash_entry *) h->root.u.i.link;
14651527

14661528
info = (struct bfd_link_info *) inf;
1529+
htab = riscv_elf_hash_table (info);
14671530

14681531
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
14691532
here if it is defined and referenced in a non-shared object. */
14701533
if (h->type == STT_GNU_IFUNC
14711534
&& h->def_regular)
14721535
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
14731536
&h->dyn_relocs,
1474-
PLT_ENTRY_SIZE,
1475-
PLT_HEADER_SIZE,
1537+
htab->plt_entry_size,
1538+
htab->plt_header_size,
14761539
GOT_ENTRY_SIZE,
14771540
true);
14781541
return true;
@@ -2472,14 +2535,14 @@ riscv_elf_relocate_section (bfd *output_bfd,
24722535

24732536
if (htab->elf.splt != NULL)
24742537
{
2475-
plt_idx = (h->plt.offset - PLT_HEADER_SIZE)
2476-
/ PLT_ENTRY_SIZE;
2538+
plt_idx = (h->plt.offset - htab->plt_header_size)
2539+
/ htab->plt_entry_size;
24772540
off = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
24782541
base_got = htab->elf.sgotplt;
24792542
}
24802543
else
24812544
{
2482-
plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
2545+
plt_idx = h->plt.offset / htab->plt_entry_size;
24832546
off = plt_idx * GOT_ENTRY_SIZE;
24842547
base_got = htab->elf.igotplt;
24852548
}
@@ -3247,8 +3310,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
32473310
{
32483311
/* We've decided to create a PLT entry for this symbol. */
32493312
bfd_byte *loc;
3250-
bfd_vma i, header_address, plt_idx, got_offset, got_address;
3251-
uint32_t plt_entry[PLT_ENTRY_INSNS];
3313+
bfd_vma plt_idx, got_offset, got_address;
32523314
Elf_Internal_Rela rela;
32533315
asection *plt, *gotplt, *relplt;
32543316

@@ -3278,36 +3340,29 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
32783340
|| relplt == NULL)
32793341
abort ();
32803342

3281-
/* Calculate the address of the PLT header. */
3282-
header_address = sec_addr (plt);
3283-
32843343
/* Calculate the index of the entry and the offset of .got.plt entry.
32853344
For static executables, we don't reserve anything. */
32863345
if (plt == htab->elf.splt)
32873346
{
3288-
plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
3347+
plt_idx = (h->plt.offset - htab->plt_header_size)
3348+
/ htab->plt_entry_size;
32893349
got_offset = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
32903350
}
32913351
else
32923352
{
3293-
plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
3353+
plt_idx = h->plt.offset / htab->plt_entry_size;
32943354
got_offset = plt_idx * GOT_ENTRY_SIZE;
32953355
}
32963356

32973357
/* Calculate the address of the .got.plt entry. */
32983358
got_address = sec_addr (gotplt) + got_offset;
32993359

3300-
/* Find out where the .plt entry should go. */
3301-
loc = plt->contents + h->plt.offset;
33023360

33033361
/* Fill in the PLT entry itself. */
3304-
if (! riscv_make_plt_entry (output_bfd, got_address,
3305-
header_address + h->plt.offset,
3306-
plt_entry))
3362+
if (! htab->make_plt_entry (output_bfd, gotplt, got_offset,
3363+
plt, h->plt.offset))
33073364
return false;
33083365

3309-
for (i = 0; i < PLT_ENTRY_INSNS; i++)
3310-
bfd_putl32 (plt_entry[i], loc + 4*i);
33113366

33123367
/* Fill in the initial value of the .got.plt entry. */
33133368
loc = gotplt->contents + (got_address - sec_addr (gotplt));
@@ -3595,19 +3650,12 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
35953650
/* Fill in the head and tail entries in the procedure linkage table. */
35963651
if (splt->size > 0)
35973652
{
3598-
int i;
3599-
uint32_t plt_header[PLT_HEADER_INSNS];
3600-
ret = riscv_make_plt_header (output_bfd,
3601-
sec_addr (htab->elf.sgotplt),
3602-
sec_addr (splt), plt_header);
3653+
ret = htab->make_plt_header (output_bfd, htab);
36033654
if (!ret)
36043655
return ret;
36053656

3606-
for (i = 0; i < PLT_HEADER_INSNS; i++)
3607-
bfd_putl32 (plt_header[i], splt->contents + 4*i);
3608-
36093657
elf_section_data (splt->output_section)->this_hdr.sh_entsize
3610-
= PLT_ENTRY_SIZE;
3658+
= htab->plt_entry_size;
36113659
}
36123660
}
36133661

@@ -3661,7 +3709,15 @@ static bfd_vma
36613709
riscv_elf_plt_sym_val (bfd_vma i, const asection *plt,
36623710
const arelent *rel ATTRIBUTE_UNUSED)
36633711
{
3664-
return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE;
3712+
unsigned plt_type = _bfd_riscv_elf_tdata (plt->owner)->plt_type;
3713+
switch (plt_type)
3714+
{
3715+
case PLT_NORMAL:
3716+
return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);
3717+
3718+
default:
3719+
abort ();
3720+
}
36653721
}
36663722

36673723
/* Used to decide how to sort relocs in an optimal manner for the

bfd/elfxx-riscv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727

2828
#define RISCV_UNKNOWN_VERSION -1
2929

30+
typedef enum
31+
{
32+
PLT_NORMAL = 0x0, /* Normal plts. */
33+
} riscv_plt_type;
34+
3035
struct riscv_elf_params
3136
{
3237
/* Whether to relax code sequences to GP-relative addressing. */

0 commit comments

Comments
 (0)