+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.
/* 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;
};
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;
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. */
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"),
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);
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)
+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.
--- /dev/null
+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]*
--- /dev/null
+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
--- /dev/null
+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]*
--- /dev/null
+#...
+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_.*|.*)>
+#...
--- /dev/null
+ .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
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 {