Skip to content

Commit 5d714ab

Browse files
kito-chenglgaver2
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 63ae53f commit 5d714ab

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
@@ -177,6 +177,9 @@ struct _bfd_riscv_elf_obj_tdata
177177

178178
/* tls_type for each local got entry. */
179179
char *local_got_tls_type;
180+
181+
/* PLT type. */
182+
riscv_plt_type plt_type;
180183
};
181184

182185
#define _bfd_riscv_elf_tdata(abfd) \
@@ -233,6 +236,15 @@ struct riscv_elf_link_hash_table
233236

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

238250
/* Instruction access functions. */
@@ -255,6 +267,12 @@ struct riscv_elf_link_hash_table
255267
&& elf_hash_table_id (elf_hash_table (p)) == RISCV_ELF_DATA) \
256268
? (struct riscv_elf_link_hash_table *) (p)->hash : NULL)
257269

270+
/* Forward declaration PLT related functions. */
271+
static bool
272+
riscv_make_plt_header (bfd *, struct riscv_elf_link_hash_table *);
273+
static bool
274+
riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
275+
258276
void
259277
riscv_elfNN_set_options (struct bfd_link_info *link_info,
260278
struct riscv_elf_params *params)
@@ -322,9 +340,14 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
322340
/* Generate a PLT header. */
323341

324342
static bool
325-
riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
326-
uint32_t *entry)
343+
riscv_make_plt_header (bfd *output_bfd, struct riscv_elf_link_hash_table *htab)
327344
{
345+
asection *splt = htab->elf.splt;
346+
bfd_vma addr = sec_addr (splt);
347+
348+
asection *sgotplt = htab->elf.sgotplt;
349+
bfd_vma gotplt_addr = sec_addr (sgotplt);
350+
328351
bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, addr);
329352
bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, addr);
330353

@@ -345,6 +368,7 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
345368
l[w|d] t0, PTRSIZE(t0) # link map
346369
jr t3 */
347370

371+
uint32_t entry[PLT_HEADER_INSNS];
348372
entry[0] = RISCV_UTYPE (AUIPC, X_T2, gotplt_offset_high);
349373
entry[1] = RISCV_RTYPE (SUB, X_T1, X_T1, X_T3);
350374
entry[2] = RISCV_ITYPE (LREG, X_T3, X_T2, gotplt_offset_low);
@@ -354,15 +378,20 @@ riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
354378
entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
355379
entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0);
356380

381+
for (int i = 0; i < PLT_HEADER_INSNS; i++)
382+
bfd_putl32 (entry[i], splt->contents + 4 * i);
383+
357384
return true;
358385
}
359386

360387
/* Generate a PLT entry. */
361388

362389
static bool
363-
riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
364-
uint32_t *entry)
390+
riscv_make_plt_entry (bfd *output_bfd, asection *gotsec, bfd_vma got_offset,
391+
asection *pltsec, bfd_vma plt_offset)
365392
{
393+
bfd_vma got = sec_addr (gotsec) + got_offset;
394+
bfd_vma addr = sec_addr (pltsec) + plt_offset;
366395
/* RVE has no t3 register, so this won't work, and is not supported. */
367396
if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
368397
{
@@ -376,11 +405,16 @@ riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
376405
jalr t1, t3
377406
nop */
378407

408+
uint32_t entry[PLT_ENTRY_INSNS];
379409
entry[0] = RISCV_UTYPE (AUIPC, X_T3, RISCV_PCREL_HIGH_PART (got, addr));
380410
entry[1] = RISCV_ITYPE (LREG, X_T3, X_T3, RISCV_PCREL_LOW_PART (got, addr));
381411
entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
382412
entry[3] = RISCV_NOP;
383413

414+
bfd_byte *loc = pltsec->contents + plt_offset;
415+
for (int i = 0; i < PLT_ENTRY_INSNS; i++)
416+
bfd_putl32 (entry[i], loc + 4 * i);
417+
384418
return true;
385419
}
386420

@@ -494,6 +528,31 @@ riscv_elf_link_hash_table_free (bfd *obfd)
494528
_bfd_elf_link_hash_table_free (obfd);
495529
}
496530

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

499558
static struct bfd_link_hash_table *
@@ -516,6 +575,8 @@ riscv_elf_link_hash_table_create (bfd *abfd)
516575
ret->max_alignment = (bfd_vma) -1;
517576
ret->max_alignment_for_gp = (bfd_vma) -1;
518577

578+
setup_plt_values (abfd, ret, PLT_NORMAL);
579+
519580
/* Create hash table for local ifunc. */
520581
ret->loc_hash_table = htab_try_create (1024,
521582
riscv_elf_local_htab_hash,
@@ -1266,12 +1327,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
12661327
asection *s = htab->elf.splt;
12671328

12681329
if (s->size == 0)
1269-
s->size = PLT_HEADER_SIZE;
1330+
s->size = htab->plt_header_size;
12701331

12711332
h->plt.offset = s->size;
12721333

12731334
/* Make room for this entry. */
1274-
s->size += PLT_ENTRY_SIZE;
1335+
s->size += htab->plt_entry_size;
12751336

12761337
/* We also need to make an entry in the .got.plt section. */
12771338
htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
@@ -1463,6 +1524,7 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
14631524
void *inf)
14641525
{
14651526
struct bfd_link_info *info;
1527+
struct riscv_elf_link_hash_table *htab;
14661528

14671529
if (h->root.type == bfd_link_hash_indirect)
14681530
return true;
@@ -1471,15 +1533,16 @@ allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
14711533
h = (struct elf_link_hash_entry *) h->root.u.i.link;
14721534

14731535
info = (struct bfd_link_info *) inf;
1536+
htab = riscv_elf_hash_table (info);
14741537

14751538
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
14761539
here if it is defined and referenced in a non-shared object. */
14771540
if (h->type == STT_GNU_IFUNC
14781541
&& h->def_regular)
14791542
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
14801543
&h->dyn_relocs,
1481-
PLT_ENTRY_SIZE,
1482-
PLT_HEADER_SIZE,
1544+
htab->plt_entry_size,
1545+
htab->plt_header_size,
14831546
GOT_ENTRY_SIZE,
14841547
true);
14851548
return true;
@@ -2487,14 +2550,14 @@ riscv_elf_relocate_section (bfd *output_bfd,
24872550

24882551
if (htab->elf.splt != NULL)
24892552
{
2490-
plt_idx = (h->plt.offset - PLT_HEADER_SIZE)
2491-
/ PLT_ENTRY_SIZE;
2553+
plt_idx = (h->plt.offset - htab->plt_header_size)
2554+
/ htab->plt_entry_size;
24922555
off = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
24932556
base_got = htab->elf.sgotplt;
24942557
}
24952558
else
24962559
{
2497-
plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
2560+
plt_idx = h->plt.offset / htab->plt_entry_size;
24982561
off = plt_idx * GOT_ENTRY_SIZE;
24992562
base_got = htab->elf.igotplt;
25002563
}
@@ -3266,8 +3329,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
32663329
{
32673330
/* We've decided to create a PLT entry for this symbol. */
32683331
bfd_byte *loc;
3269-
bfd_vma i, header_address, plt_idx, got_offset, got_address;
3270-
uint32_t plt_entry[PLT_ENTRY_INSNS];
3332+
bfd_vma plt_idx, got_offset, got_address;
32713333
Elf_Internal_Rela rela;
32723334
asection *plt, *gotplt, *relplt;
32733335

@@ -3297,36 +3359,29 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
32973359
|| relplt == NULL)
32983360
abort ();
32993361

3300-
/* Calculate the address of the PLT header. */
3301-
header_address = sec_addr (plt);
3302-
33033362
/* Calculate the index of the entry and the offset of .got.plt entry.
33043363
For static executables, we don't reserve anything. */
33053364
if (plt == htab->elf.splt)
33063365
{
3307-
plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
3366+
plt_idx = (h->plt.offset - htab->plt_header_size)
3367+
/ htab->plt_entry_size;
33083368
got_offset = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
33093369
}
33103370
else
33113371
{
3312-
plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
3372+
plt_idx = h->plt.offset / htab->plt_entry_size;
33133373
got_offset = plt_idx * GOT_ENTRY_SIZE;
33143374
}
33153375

33163376
/* Calculate the address of the .got.plt entry. */
33173377
got_address = sec_addr (gotplt) + got_offset;
33183378

3319-
/* Find out where the .plt entry should go. */
3320-
loc = plt->contents + h->plt.offset;
33213379

33223380
/* Fill in the PLT entry itself. */
3323-
if (! riscv_make_plt_entry (output_bfd, got_address,
3324-
header_address + h->plt.offset,
3325-
plt_entry))
3381+
if (! htab->make_plt_entry (output_bfd, gotplt, got_offset,
3382+
plt, h->plt.offset))
33263383
return false;
33273384

3328-
for (i = 0; i < PLT_ENTRY_INSNS; i++)
3329-
bfd_putl32 (plt_entry[i], loc + 4*i);
33303385

33313386
/* Fill in the initial value of the .got.plt entry. */
33323387
loc = gotplt->contents + (got_address - sec_addr (gotplt));
@@ -3614,19 +3669,12 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
36143669
/* Fill in the head and tail entries in the procedure linkage table. */
36153670
if (splt->size > 0)
36163671
{
3617-
int i;
3618-
uint32_t plt_header[PLT_HEADER_INSNS];
3619-
ret = riscv_make_plt_header (output_bfd,
3620-
sec_addr (htab->elf.sgotplt),
3621-
sec_addr (splt), plt_header);
3672+
ret = htab->make_plt_header (output_bfd, htab);
36223673
if (!ret)
36233674
return ret;
36243675

3625-
for (i = 0; i < PLT_HEADER_INSNS; i++)
3626-
bfd_putl32 (plt_header[i], splt->contents + 4*i);
3627-
36283676
elf_section_data (splt->output_section)->this_hdr.sh_entsize
3629-
= PLT_ENTRY_SIZE;
3677+
= htab->plt_entry_size;
36303678
}
36313679
}
36323680

@@ -3689,7 +3737,15 @@ static bfd_vma
36893737
riscv_elf_plt_sym_val (bfd_vma i, const asection *plt,
36903738
const arelent *rel ATTRIBUTE_UNUSED)
36913739
{
3692-
return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE;
3740+
unsigned plt_type = _bfd_riscv_elf_tdata (plt->owner)->plt_type;
3741+
switch (plt_type)
3742+
{
3743+
case PLT_NORMAL:
3744+
return plt->vma + (PLT_HEADER_SIZE) + (i * PLT_ENTRY_SIZE);
3745+
3746+
default:
3747+
abort ();
3748+
}
36933749
}
36943750

36953751
/* 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)