Skip to content

Commit d62a2a4

Browse files
committed
RISC-V: Look up lpad values from lpadinfo for func-sig PLT entries
Implement lpadinfo reading in the linker to support function signature based landing pads. The riscv_make_plt_zicfilp_func_sig_entry() now queries the lpadinfo hash table to get the correct lpad value for each PLT symbol. Key changes: - Add riscv_lpadinfo_entry hash table to link hash table - Read lpadinfo from input BFDs in merge_private_bfd_data - Update make_plt_entry function pointer to include h and info params - Default lpad value changed from 1 to 0 - riscv_lpadinfo_lookup() returns bool to distinguish "not found" from "value is 0", preventing false warnings for symbols with lpad_value=0 Ref: - riscv-non-isa/riscv-elf-psabi-doc#452
1 parent 75fa61d commit d62a2a4

13 files changed

+568
-19
lines changed

bfd/elfnn-riscv.c

Lines changed: 252 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ typedef struct
301301
const char *name;
302302
} riscv_jvt_htab_entry;
303303

304+
/* Hash table entry for lpadinfo: maps symbol name to lpad value. */
305+
typedef struct
306+
{
307+
const char *name;
308+
uint32_t lpad_value;
309+
} riscv_lpadinfo_entry;
310+
304311
struct riscv_elf_link_hash_table
305312
{
306313
struct elf_link_hash_table elf;
@@ -336,6 +343,9 @@ struct riscv_elf_link_hash_table
336343

337344
riscv_jvt_htab_t *jvt_htab;
338345

346+
/* Hash table for lpadinfo: symbol name -> lpad value. */
347+
htab_t lpadinfo_htab;
348+
339349
/* Find compact relocations in check_relocs. */
340350
bool compact_relocs;
341351

@@ -346,7 +356,9 @@ struct riscv_elf_link_hash_table
346356
/* Functions to make PLT header and entries. */
347357
bool (*make_plt_header) (bfd *output_bfd, struct riscv_elf_link_hash_table *htab);
348358
bool (*make_plt_entry) (bfd *output_bfd, asection *got, bfd_vma got_offset,
349-
asection *plt, bfd_vma plt_offset);
359+
asection *plt, bfd_vma plt_offset,
360+
struct elf_link_hash_entry *h,
361+
struct bfd_link_info *info);
350362
};
351363

352364
/* Instruction access functions. */
@@ -378,26 +390,32 @@ static bool
378390
riscv_make_plt_header (bfd *, struct riscv_elf_link_hash_table *);
379391

380392
static bool
381-
riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
393+
riscv_make_plt_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma,
394+
struct elf_link_hash_entry *, struct bfd_link_info *);
382395

383396
static bool riscv_make_plt_compact_header (bfd *,
384397
struct riscv_elf_link_hash_table *);
385398

386399
static bool riscv_make_plt_compact_entry (bfd *, asection *, bfd_vma,
387-
asection *, bfd_vma);
400+
asection *, bfd_vma,
401+
struct elf_link_hash_entry *,
402+
struct bfd_link_info *);
388403

389404
static bool
390405
riscv_make_plt_zicfilp_header (bfd *, struct riscv_elf_link_hash_table *);
391406

392407
static bool
393-
riscv_make_plt_zicfilp_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
408+
riscv_make_plt_zicfilp_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma,
409+
struct elf_link_hash_entry *, struct bfd_link_info *);
394410

395411
static bool
396412
riscv_make_plt_zicfilp_func_sig_header (bfd *, struct riscv_elf_link_hash_table *);
397413

398414
static bool
399-
riscv_make_plt_zicfilp_func_sig_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma);
415+
riscv_make_plt_zicfilp_func_sig_entry (bfd *, asection *, bfd_vma, asection *, bfd_vma,
416+
struct elf_link_hash_entry *, struct bfd_link_info *);
400417

418+
static bool riscv_lpadinfo_lookup (htab_t, const char *, uint32_t *);
401419

402420
static void
403421
setup_plt_values (struct bfd_link_info *link_info,
@@ -947,7 +965,9 @@ riscv_make_plt_zicfilp_func_sig_header (bfd *output_bfd,
947965

948966
static bool
949967
riscv_make_plt_entry (bfd *output_bfd, asection *got, bfd_vma got_offset,
950-
asection *plt, bfd_vma plt_offset)
968+
asection *plt, bfd_vma plt_offset,
969+
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
970+
struct bfd_link_info *info ATTRIBUTE_UNUSED)
951971
{
952972
bfd_vma got_entry_addr = sec_addr(got) + got_offset;
953973
/* RVE has no t3 register, so this won't work, and is not supported. */
@@ -995,7 +1015,9 @@ riscv_make_plt_entry (bfd *output_bfd, asection *got, bfd_vma got_offset,
9951015
static bool
9961016
riscv_make_plt_compact_entry (bfd *output_bfd, asection *got ATTRIBUTE_UNUSED,
9971017
bfd_vma got_offset, asection *plt,
998-
bfd_vma plt_offset)
1018+
bfd_vma plt_offset,
1019+
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
1020+
struct bfd_link_info *info ATTRIBUTE_UNUSED)
9991021
{
10001022
bfd_vma plt_addr = sec_addr (plt);
10011023
/* RVE has no t3 register, so this won't work, and is not supported. */
@@ -1054,7 +1076,9 @@ riscv_make_plt_compact_entry (bfd *output_bfd, asection *got ATTRIBUTE_UNUSED,
10541076

10551077
static bool
10561078
riscv_make_plt_zicfilp_entry (bfd *output_bfd ATTRIBUTE_UNUSED, asection *got,
1057-
bfd_vma got_offset, asection *plt, bfd_vma plt_offset)
1079+
bfd_vma got_offset, asection *plt, bfd_vma plt_offset,
1080+
struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
1081+
struct bfd_link_info *info ATTRIBUTE_UNUSED)
10581082
{
10591083
/* lpad 0
10601084
1: auipc t3, %pcrel_hi(function@.got.plt)
@@ -1080,11 +1104,25 @@ riscv_make_plt_zicfilp_entry (bfd *output_bfd ATTRIBUTE_UNUSED, asection *got,
10801104
static bool
10811105
riscv_make_plt_zicfilp_func_sig_entry (bfd *output_bfd ATTRIBUTE_UNUSED, asection *got,
10821106
bfd_vma got_offset, asection *plt,
1083-
bfd_vma plt_offset)
1107+
bfd_vma plt_offset,
1108+
struct elf_link_hash_entry *h,
1109+
struct bfd_link_info *info)
10841110
{
1085-
/* FIXME: Use 1 for landing pad label now, need use from
1086-
.riscv.lpadinfo section. */
1087-
int64_t lpl = 1 << 12;
1111+
struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
1112+
uint32_t lpad_value = 0;
1113+
1114+
/* Look up lpad_value from lpadinfo hash table. */
1115+
if (htab->lpadinfo_htab != NULL && h != NULL)
1116+
{
1117+
const char *name = h->root.root.string;
1118+
if (!riscv_lpadinfo_lookup (htab->lpadinfo_htab, name, &lpad_value))
1119+
_bfd_error_handler
1120+
(_("warning: no lpadinfo for PLT symbol `%s', using default value 0"),
1121+
name);
1122+
}
1123+
1124+
/* The lpad value is placed in bits [31:12] of the instruction. */
1125+
int64_t lpl = (int64_t) lpad_value << 12;
10881126

10891127
/* lpad <value>
10901128
auipc t3, %hi(function@.got.plt)
@@ -1235,6 +1273,198 @@ riscv_free_jvt_htab (riscv_jvt_htab_t *htab)
12351273
htab_delete (htab->jalt_htab);
12361274
}
12371275

1276+
/* Hash function for lpadinfo entries (by symbol name). */
1277+
1278+
static hashval_t
1279+
riscv_lpadinfo_htab_hash (const void *entry)
1280+
{
1281+
const riscv_lpadinfo_entry *e = entry;
1282+
return htab_hash_string (e->name);
1283+
}
1284+
1285+
/* Equality function for lpadinfo entries. */
1286+
1287+
static int
1288+
riscv_lpadinfo_htab_eq (const void *entry1, const void *entry2)
1289+
{
1290+
const riscv_lpadinfo_entry *e1 = entry1, *e2 = entry2;
1291+
return strcmp (e1->name, e2->name) == 0;
1292+
}
1293+
1294+
/* Look up lpad_value for a symbol in the lpadinfo hash table.
1295+
Returns true if found, false otherwise. The lpad_value is stored
1296+
in *VALUE_OUT if found. */
1297+
1298+
static bool
1299+
riscv_lpadinfo_lookup (htab_t htab, const char *name, uint32_t *value_out)
1300+
{
1301+
if (htab == NULL || name == NULL)
1302+
return false;
1303+
1304+
riscv_lpadinfo_entry search = { .name = name, .lpad_value = 0 };
1305+
riscv_lpadinfo_entry *entry = htab_find (htab, &search);
1306+
1307+
if (entry != NULL)
1308+
{
1309+
*value_out = entry->lpad_value;
1310+
return true;
1311+
}
1312+
return false;
1313+
}
1314+
1315+
/* Read .riscv.lpadinfo section from an input BFD and populate the
1316+
lpadinfo hash table with symbol name -> lpad_value mappings. */
1317+
1318+
static bool
1319+
riscv_read_lpadinfo_section (bfd *abfd, struct bfd_link_info *info)
1320+
{
1321+
struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
1322+
asection *sec;
1323+
bfd_byte *contents = NULL;
1324+
Elf_Internal_Shdr *symtab_hdr;
1325+
Elf_Internal_Sym *isymbuf = NULL;
1326+
char *strtab = NULL;
1327+
size_t strtab_size = 0;
1328+
uint32_t num_entries;
1329+
uint32_t entry_size = RISCV_LPADINFO_ENTRY_SIZE; /* lpi_sym + lpi_value + lpi_sig */
1330+
bool ret = true;
1331+
1332+
if (htab == NULL)
1333+
return false;
1334+
1335+
/* Find the .riscv.lpadinfo section. */
1336+
sec = bfd_get_section_by_name (abfd, ".riscv.lpadinfo");
1337+
if (sec == NULL || sec->size == 0)
1338+
return true; /* No lpadinfo section, not an error. */
1339+
1340+
/* Verify section type. */
1341+
if (elf_section_data (sec)->this_hdr.sh_type != SHT_RISCV_LANDING_PAD_INFO)
1342+
return true;
1343+
1344+
/* Create the hash table if needed. */
1345+
if (htab->lpadinfo_htab == NULL)
1346+
{
1347+
htab->lpadinfo_htab = htab_try_create (64, riscv_lpadinfo_htab_hash,
1348+
riscv_lpadinfo_htab_eq, free);
1349+
if (htab->lpadinfo_htab == NULL)
1350+
return false;
1351+
}
1352+
1353+
/* Read section contents. */
1354+
if (!bfd_malloc_and_get_section (abfd, sec, &contents))
1355+
{
1356+
ret = false;
1357+
goto cleanup;
1358+
}
1359+
1360+
/* Get number of entries from sh_info. */
1361+
num_entries = elf_section_data (sec)->this_hdr.sh_info;
1362+
if (num_entries == 0 || num_entries * entry_size > sec->size)
1363+
goto cleanup;
1364+
1365+
/* Read the symbol table. */
1366+
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1367+
if (symtab_hdr->sh_info != 0)
1368+
{
1369+
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1370+
if (isymbuf == NULL)
1371+
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
1372+
symtab_hdr->sh_info, 0,
1373+
NULL, NULL, NULL);
1374+
}
1375+
1376+
/* Read the string table. */
1377+
if (symtab_hdr->sh_link != 0)
1378+
{
1379+
unsigned int strndx = symtab_hdr->sh_link;
1380+
Elf_Internal_Shdr *strtab_hdr = elf_elfsections (abfd)[strndx];
1381+
strtab = (char *) bfd_elf_get_str_section (abfd, strndx);
1382+
strtab_size = strtab_hdr->sh_size;
1383+
}
1384+
1385+
/* Process each entry. */
1386+
for (uint32_t i = 0; i < num_entries; i++)
1387+
{
1388+
bfd_byte *ptr = contents + i * entry_size;
1389+
uint32_t sym_index = bfd_get_32 (abfd, ptr);
1390+
uint32_t lpad_value = bfd_get_32 (abfd, ptr + 4);
1391+
const char *sym_name = NULL;
1392+
1393+
/* Get symbol name. */
1394+
if (sym_index < symtab_hdr->sh_info && isymbuf != NULL)
1395+
{
1396+
/* Local symbol. */
1397+
Elf_Internal_Sym *isym = isymbuf + sym_index;
1398+
if (isym->st_name < strtab_size && strtab != NULL)
1399+
sym_name = strtab + isym->st_name;
1400+
}
1401+
else
1402+
{
1403+
/* Global symbol - look up in hash table. */
1404+
unsigned int sym_hash_idx = sym_index - symtab_hdr->sh_info;
1405+
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
1406+
unsigned int symcount = ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym))
1407+
- symtab_hdr->sh_info);
1408+
if (sym_hashes != NULL && sym_hash_idx < symcount)
1409+
{
1410+
struct elf_link_hash_entry *h = sym_hashes[sym_hash_idx];
1411+
if (h != NULL)
1412+
sym_name = h->root.root.string;
1413+
}
1414+
}
1415+
1416+
if (sym_name == NULL || sym_name[0] == '\0')
1417+
continue;
1418+
1419+
/* Check if entry already exists. */
1420+
riscv_lpadinfo_entry search = { .name = sym_name, .lpad_value = 0 };
1421+
riscv_lpadinfo_entry *existing = htab_find (htab->lpadinfo_htab, &search);
1422+
1423+
if (existing != NULL)
1424+
{
1425+
/* Entry exists, check for conflict. */
1426+
if (existing->lpad_value != lpad_value)
1427+
{
1428+
_bfd_error_handler
1429+
(_("%pB: conflicting lpadinfo values for `%s': "
1430+
"0x%x vs 0x%x"),
1431+
abfd, sym_name, existing->lpad_value, lpad_value);
1432+
}
1433+
continue;
1434+
}
1435+
1436+
/* Insert new entry. */
1437+
riscv_lpadinfo_entry **slot = (riscv_lpadinfo_entry **)
1438+
htab_find_slot (htab->lpadinfo_htab, &search, INSERT);
1439+
1440+
if (*slot == NULL)
1441+
{
1442+
*slot = (riscv_lpadinfo_entry *) bfd_malloc (sizeof (riscv_lpadinfo_entry));
1443+
if (*slot == NULL)
1444+
{
1445+
ret = false;
1446+
goto cleanup;
1447+
}
1448+
(*slot)->name = bfd_strdup (sym_name);
1449+
if ((*slot)->name == NULL)
1450+
{
1451+
free (*slot);
1452+
*slot = NULL;
1453+
ret = false;
1454+
goto cleanup;
1455+
}
1456+
(*slot)->lpad_value = lpad_value;
1457+
}
1458+
}
1459+
1460+
cleanup:
1461+
free (contents);
1462+
if (isymbuf != NULL && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents)
1463+
free (isymbuf);
1464+
1465+
return ret;
1466+
}
1467+
12381468
/* Update table jump hash entry. */
12391469

12401470
static bool
@@ -1354,6 +1584,9 @@ riscv_elf_link_hash_table_free (bfd *obfd)
13541584
free (ret->jvt_htab);
13551585
}
13561586

1587+
if (ret->lpadinfo_htab)
1588+
htab_delete (ret->lpadinfo_htab);
1589+
13571590
_bfd_elf_link_hash_table_free (obfd);
13581591
}
13591592

@@ -4445,7 +4678,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
44454678

44464679
/* Fill in the PLT entry itself. */
44474680
if (! htab->make_plt_entry (output_bfd, gotplt, got_offset,
4448-
plt, h->plt.offset))
4681+
plt, h->plt.offset, h, info))
44494682
return false;
44504683

44514684

@@ -5397,7 +5630,8 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
53975630
{
53985631
elf_flags_init (obfd) = true;
53995632
elf_elfheader (obfd)->e_flags = new_flags;
5400-
return true;
5633+
/* Still need to read lpadinfo section. */
5634+
return riscv_read_lpadinfo_section (ibfd, info);
54015635
}
54025636

54035637
/* Disallow linking different float ABIs. */
@@ -5424,6 +5658,10 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
54245658
/* Allow linking TSO and non-TSO, and keep the TSO flag. */
54255659
elf_elfheader (obfd)->e_flags |= new_flags & EF_RISCV_TSO;
54265660

5661+
/* Read lpadinfo section for PLT generation. */
5662+
if (!riscv_read_lpadinfo_section (ibfd, info))
5663+
goto fail;
5664+
54275665
return true;
54285666

54295667
fail:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ if [istarget "riscv*-*-*"] {
292292

293293
run_dump_test "zicfilp-unlabeled-plt"
294294
run_dump_test "zicfilp-func-sig-plt"
295+
run_dump_test "zicfilp-lpadinfo-plt"
296+
run_dump_test "zicfilp-lpadinfo-zero"
297+
run_dump_test "zicfilp-lpadinfo-multi"
298+
run_dump_test "zicfilp-lpadinfo-conflict"
295299

296300
# IFUNC testcases.
297301
# Check IFUNC by single type relocs.

0 commit comments

Comments
 (0)