aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog9
-rw-r--r--bfd/elfnn-riscv.c46
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-exe.rd4
-rw-r--r--ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pic.rd8
-rw-r--r--ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pie.rd7
-rw-r--r--ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.d19
-rw-r--r--ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s38
-rw-r--r--ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp7
9 files changed, 140 insertions, 7 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index b0cd8b8..7fb6181 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,14 @@
2020-10-16 Nelson Chu <nelson.chu@sifive.com>
+ * elfnn-riscv.c (riscv_elf_link_hash_table): Add last_iplt_index.
+ (riscv_elf_size_dynamic_sections): Initialize the last_iplt_index.
+ (riscv_elf_relocate_section): Use riscv_elf_append_rela.
+ (riscv_elf_finish_dynamic_symbol): If the use_elf_append_rela is
+ false, then we should add the dynamic relocs from the last of
+ the .rela.iplt, and don't use the riscv_elf_append_rela to add.
+
+2020-10-16 Nelson Chu <nelson.chu@sifive.com>
+
* elfnn-riscv.c: Include "objalloc.h" since we need objalloc_alloc.
(riscv_elf_link_hash_table): Add loc_hash_table and loc_hash_memory
for local STT_GNU_IFUNC symbols.
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index a26cd3f..a5b2c8a 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -120,6 +120,9 @@ struct riscv_elf_link_hash_table
/* Used by local STT_GNU_IFUNC symbols. */
htab_t loc_hash_table;
void * loc_hash_memory;
+
+ /* The index of the last unused .rel.iplt slot. */
+ bfd_vma last_iplt_index;
};
@@ -1424,6 +1427,11 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
local ifunc symbols. */
htab_traverse (htab->loc_hash_table, allocate_local_ifunc_dynrelocs, info);
+ /* Used to resolve the dynamic relocs overwite problems when
+ generating static executable. */
+ if (htab->elf.irelplt)
+ htab->last_iplt_index = htab->elf.irelplt->reloc_count - 1;
+
if (htab->elf.sgotplt)
{
struct elf_link_hash_entry *got;
@@ -2904,6 +2912,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
asection *sgot;
asection *srela;
Elf_Internal_Rela rela;
+ bfd_boolean use_elf_append_rela = TRUE;
/* This symbol has an entry in the GOT. Set it up. */
@@ -2920,12 +2929,18 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
if (h->plt.offset == (bfd_vma) -1)
{
/* STT_GNU_IFUNC is referenced without PLT. */
+
if (htab->elf.splt == NULL)
{
- /* use .rel[a].iplt section to store .got relocations
+ /* Use .rela.iplt section to store .got relocations
in static executable. */
srela = htab->elf.irelplt;
+
+ /* Do not use riscv_elf_append_rela to add dynamic
+ relocs. */
+ use_elf_append_rela = FALSE;
}
+
if (SYMBOL_REFERENCES_LOCAL (info, h))
{
info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
@@ -2973,14 +2988,14 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
return TRUE;
}
}
- /* If this is a local symbol reference, we just want to emit a RELATIVE
- reloc. This can happen if it is a -Bsymbolic link, or a pie link, or
- the symbol was forced to be local because of a version file.
- The entry in the global offset table will already have been
- initialized in the relocate_section function. */
else if (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
+ /* If this is a local symbol reference, we just want to emit
+ a RELATIVE reloc. This can happen if it is a -Bsymbolic link,
+ or a pie link, or the symbol was forced to be local because
+ of a version file. The entry in the global offset table will
+ already have been initialized in the relocate_section function. */
BFD_ASSERT((h->got.offset & 1) != 0);
asection *sec = h->root.u.def.section;
rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
@@ -2998,7 +3013,24 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
bfd_put_NN (output_bfd, 0,
sgot->contents + (h->got.offset & ~(bfd_vma) 1));
- riscv_elf_append_rela (output_bfd, srela, &rela);
+
+ if (use_elf_append_rela)
+ riscv_elf_append_rela (output_bfd, srela, &rela);
+ else
+ {
+ /* Use riscv_elf_append_rela to add the dynamic relocs into
+ .rela.iplt may cause the overwrite problems. Since we insert
+ the relocs for PLT didn't handle the reloc_index of .rela.iplt,
+ but the riscv_elf_append_rela adds the relocs to the place
+ that are calculated from the reloc_index (in seqential).
+
+ One solution is that add these dynamic relocs (GOT IFUNC)
+ from the last of .rela.iplt section. */
+ bfd_vma iplt_idx = htab->last_iplt_index--;
+ bfd_byte *loc = srela->contents
+ + iplt_idx * sizeof (ElfNN_External_Rela);
+ bed->s->swap_reloca_out (output_bfd, &rela, loc);
+ }
}
if (h->needs_copy)
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 3a9d381..780bb4b 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,14 @@
2020-10-16 Nelson Chu <nelson.chu@sifive.com>
+ * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s: New testcase.
+ * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.d: Likewise.
+ * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-exe.rd: Likewise.
+ * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pic.rd: Likewise.
+ * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pie.rd: Likewise.
+ * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
+
+2020-10-16 Nelson Chu <nelson.chu@sifive.com>
+
* emulparams/elf32lriscv-defs.sh: Add IREL_IN_PLT.
* testsuite/ld-ifunc/ifunc.exp: Enable ifunc tests for RISC-V.
* testsuite/ld-riscv-elf/ld-riscv-elf.exp (run_dump_test_ifunc):
diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-exe.rd
new file mode 100644
index 0000000..0de47a4
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-exe.rd
@@ -0,0 +1,4 @@
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pic.rd
new file mode 100644
index 0000000..f65d789
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pic.rd
@@ -0,0 +1,8 @@
+Relocation section '.rela.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo2\(\)[ ]+foo2 \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo1\(\)[ ]+foo1 \+ 0
+#...
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo1\(\)[ ]+foo1 \+ 0
diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pie.rd
new file mode 100644
index 0000000..32e66f0
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite-pie.rd
@@ -0,0 +1,7 @@
+Relocation section '.rela.got' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.d b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.d
new file mode 100644
index 0000000..333dea3
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.d
@@ -0,0 +1,19 @@
+#...
+Disassembly of section .plt:
+#...
+0+[0-9a-f]+ <(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>:
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <foo_resolver>:
+#...
+0+[0-9a-f]+ <bar>:
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<(_GLOBAL_OFFSET_TABLE_.*|.*)>
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(.*plt.*)>
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(.*plt.*)>
+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<(_GLOBAL_OFFSET_TABLE_.*|.*)>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s
new file mode 100644
index 0000000..6c2f8e8
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s
@@ -0,0 +1,38 @@
+ .text
+
+ .type foo_resolver, @function
+foo_resolver:
+ ret
+ .size foo_resolver, .-foo_resolver
+
+ .globl foo1
+ .type foo1, %gnu_indirect_function
+ .set foo1, foo_resolver
+
+ .globl foo2
+ .type foo2, %gnu_indirect_function
+ .set foo2, foo_resolver
+
+ .globl bar
+ .type bar, @function
+bar:
+.L1:
+ auipc x1, %got_pcrel_hi (foo1)
+.ifdef __64_bit__
+ ld x1, %pcrel_lo (.L1) (x1)
+.else
+ lw x1, %pcrel_lo (.L1) (x1)
+.endif
+
+ call foo1
+ call foo1@plt
+
+.L2:
+ auipc x2, %got_pcrel_hi (foo2)
+.ifdef __64_bit__
+ ld x2, %pcrel_lo (.L2) (x2)
+.else
+ lw x2, %pcrel_lo (.L2) (x2)
+.endif
+ ret
+ .size bar, .-bar
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index b82e092..9834041 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -175,6 +175,13 @@ if [istarget "riscv*-*-*"] {
run_dump_test_ifunc "ifunc-plt-02" rv64 exe
run_dump_test_ifunc "ifunc-plt-02" rv64 pie
run_dump_test_ifunc "ifunc-plt-02" rv64 pic
+ # Check the .rela.iplt overwrite issue.
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 exe
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 pie
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv32 pic
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 exe
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pie
+ run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pic
# Setup shared libraries.
run_ld_link_tests {