[PATCH v3 1/2] RISC-V: Support GNU indirect functions.
Fangrui Song
i@maskray.me
Wed Jan 6 06:46:32 GMT 2021
On Tue, Oct 6, 2020 at 8:48 PM Nelson Chu <nelson.chu@sifive.com> wrote:
>
> Generally, glibc dynamic linker should have two ways to deal with ifunc
> - one is to handle the IRELATIVE relocations for the non-preemtive ifunc
> symbols, the other is to handle the R_RISCV_32/64 and R_RISCV_JUMP_SLOT
> relocations with the STT_IFUNC preemtive symbols. No matter which method
> is used, both of them should get the resolved ifunc symbols at runtime.
> Therefore, linker needs to generate the correct dynamic relocations for
> ifunc to make sure the the dynamic linker works well. For now, there are
> thirteen relocations are supported for ifunc in GNU ld,
>
> * R_RISCV_CALL and R_RISCV_CALL_PLT:
> The RISC-V compiler won't generate R_RISCV_JAL directly to jump to an
> ifunc. Besides, we disable the relaxations for the relocation referenced
> to ifunc, so just handling the R_RISCV_CALL and R_RISCV_CALL_PLT should be
> enough. Linker should generate a .plt entry and a .got.plt entry for it,
> and also needs to insert a dynamic IRELATIVE in the .got.plt enrty, or
> insert a R_RISCV_JUMP_SLOT when generating shared library.
>
> * R_RISCV_PCREL_HI20 and R_RISCV_PCREL_LO12_I/S:
> LA/LLA pattern with local fPIC ifunc symbol, or any non-PIC ifunc symbol.
> The PC-relative relocation. The current linker will deal with them in
> the same way as R_RISCV_CALL_PLT.
>
> * R_RISCV_GOT_HI20 and R_RISCV_PCREL_LO12_I/S:
> LA pattern with global PIC ifunc symbol. Linker should insert a dynamic
> IRELATIVE in the .got entry, or insert a R_RISCV_32/64 when generating
> shared library.
>
> * R_RISCV_32 and R_RISCV_64:
> Store the ifunc symbol into the data section. Linker should insert a
> dynamic IRELATIVE in the data section, or insert a R_RISCV_32/64 when
> generating shared library.
>
> * R_RISCV_HI20 and R_RISCV_LO12_I/S:
> The LUI + ADDI/LW/SW patterns. The absolute access relocation. The
> medlow model without the -fPIC compiler option should generate them.
> The ld ifunc testsuites "Build pr23169a" and "Build pr23169d" need the
> relocations, they are in the ld/testsuite/ld-ifunc/, and need compiler
> support.
>
> However, we also made some optimizations with reference to x86,
>
> * If GOT and PLT relocations refer to the same ifunc symbol when generating
> pie, then they can actually share a .got entry without creating two entries
> to store the same value and relocation.
>
> * If GOT, PLT and DATA relocations refer to the same ifunc symbol when
> generating position dependency executable, then linker will fill the address
> of .plt entry into the corresponding .got entry and data section, without
> insert any dynamic relocations for the GOT and DATA relocations.
>
> For the ifunc testcases, there are three types of them,
>
> 1. ifunc-reloc-*: Only check the single type of relocation refers to
> ifunc symbol.
> * ifunc-reloc-call: R_RISCV_CALL and R_RISCV_CALL_PLT.
> * ifunc-reloc-data: R_RISCV_32 and R_RISCV_64.
> * ifunc-reloc-got: R_RISCV_GOT_HI20 and R_RISCV_PCREL_LO_I/S.
> * ifunc-reloc-pcrel: R_RISCV_PCREL_HI20 and R_RISCV_PCREL_LO_I/S.
>
> 2. ifunc-[nonplt|plt]-*: If we don't have PLT relocs, then don't need to
> create the PLT and it's .plt entries.
> * ifunc-nonplt: Combine R_RISCV_GOT_HI20 and R_RISCV_32/64.
> * ifunc-plt: Combine all ifunc relocations.
>
> 3. ifunc-seperate-*: If we link the ifunc caller and resolver into the
> same module (link the objects), then the results are the same as the
> ifunc-reloc-* and ifunc-[noplt|plt]-* testcases. Consider the cases that
> the ifunc callers and resolver are in the different modules, that is, we
> compile the ifunc resolver to the shared library first, and then link it
> with the ifunc callers. The output of ifunc callers should be the same as
> the normal STT_FUNC cases, and the shared ifunc resolver should define the
> symbols as STT_IFUNC.
>
> The R_RISCV_PCREL_HI20 reloc is special. It should be linked and resolved
> locally, so if the ifunc resolver is defined in other modules (other shared
> libraries), then the R_RISCV_PCREL_HI20 is unresolvable, and linker should
> issue an unresolvable reloc error.
>
> bfd/
> * 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.
> (riscv_elf_got_plt_val): Removed.
> (riscv_elf_local_htab_hash, riscv_elf_local_htab_eq): New functions.
> Use to compare local hash entries.
> (riscv_elf_get_local_sym_hash): New function. Find a hash entry for
> local symbol, and create a new one if needed.
> (riscv_elf_link_hash_table_free): New function. Destroy an riscv
> elf linker hash table.
> (riscv_elf_link_hash_table_create): Create hash table for local ifunc.
> (riscv_elf_check_relocs): Create a fake global symbol to track the
> local ifunc symbol. Add support to check and handle the relocations
> reference to ifunc symbols.
> (allocate_dynrelocs): Let allocate_ifunc_dynrelocs and
> allocate_local_ifunc_dynrelocs to handle the ifunc symbols if they
> are defined and referenced in a non-shared object.
> (allocate_ifunc_dynrelocs): New function. Allocate space in .plt,
> .got and associated reloc sections for ifunc dynamic relocs.
> (allocate_local_ifunc_dynrelocs): Likewise, but for local ifunc
> dynamic relocs.
> (riscv_elf_relocate_section): Add support to handle the relocation
> referenced to ifunc symbols.
> (riscv_elf_size_dynamic_sections): Updated.
> (riscv_elf_adjust_dynamic_symbol): Updated.
> (riscv_elf_finish_dynamic_symbol): Finish up the ifunc handling,
> including fill the PLT and GOT entries for ifunc symbols.
> (riscv_elf_finish_local_dynamic_symbol): New function. Called by
> riscv_elf_finish_dynamic_symbol to handle the local ifunc symbols.
> (_bfd_riscv_relax_section): Don't do the relaxation for ifunc.
> * elfxx-riscv.c: Add R_RISCV_IRELATIVE.
> * configure.ac: Link elf-ifunc.lo to use the generic ifunc support.
> * configure: Regenerated.
>
> include/
> * elf/riscv.h: Add R_RISCV_IRELATIVE to 58.
>
> ld/
> * 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):
> New dump test for ifunc. There are two arguments, 'target` and
> `output`. The `target` is rv32 or rv64, and the `output` is used
> to choose which output you want to test (exe, pie or .so).
> * testsuite/ld-riscv-elf/ifunc-reloc-call-01.s: New testcase.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-01.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-01-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-01-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-01-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-02.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-02.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-02-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-02-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-call-02-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-data.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-data.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-data-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-got.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-got.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-got-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-pcrel.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-nonplt.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-nonplt.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-nonplt-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-nonplt-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-nonplt-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-01.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-01.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-01-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-02.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-02.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-02-pic.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-resolver.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-caller.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-exe.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-pic.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-pie.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-caller-pcrel.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pic.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pie.d: Likewise.
> ---
> bfd/configure | 4 +-
> bfd/configure.ac | 4 +-
> bfd/elfnn-riscv.c | 725 +++++++++++++++++++--
> bfd/elfxx-riscv.c | 15 +
> include/elf/riscv.h | 1 +
> ld/emulparams/elf32lriscv-defs.sh | 1 +
> ld/testsuite/ld-ifunc/ifunc.exp | 4 +-
> ld/testsuite/ld-riscv-elf/ifunc-nonplt-exe.rd | 4 +
> ld/testsuite/ld-riscv-elf/ifunc-nonplt-pic.rd | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-nonplt-pie.rd | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-nonplt.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-nonplt.s | 39 ++
> ld/testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-01-pic.rd | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-01.d | 19 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-01.s | 31 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-02-pic.rd | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-02.d | 21 +
> ld/testsuite/ld-riscv-elf/ifunc-plt-02.s | 46 ++
> .../ld-riscv-elf/ifunc-reloc-call-01-exe.rd | 3 +
> .../ld-riscv-elf/ifunc-reloc-call-01-pic.rd | 3 +
> .../ld-riscv-elf/ifunc-reloc-call-01-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.s | 17 +
> .../ld-riscv-elf/ifunc-reloc-call-02-exe.rd | 3 +
> .../ld-riscv-elf/ifunc-reloc-call-02-pic.rd | 3 +
> .../ld-riscv-elf/ifunc-reloc-call-02-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.d | 15 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.s | 18 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pic.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-data.d | 9 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-data.s | 31 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pic.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-got.d | 9 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-got.s | 23 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pic.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.d | 15 +
> ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s | 26 +
> .../ld-riscv-elf/ifunc-seperate-caller-nonplt.s | 23 +
> .../ld-riscv-elf/ifunc-seperate-caller-pcrel.s | 14 +
> .../ld-riscv-elf/ifunc-seperate-caller-plt.s | 26 +
> .../ld-riscv-elf/ifunc-seperate-nonplt-exe.d | 14 +
> .../ld-riscv-elf/ifunc-seperate-nonplt-pic.d | 13 +
> .../ld-riscv-elf/ifunc-seperate-nonplt-pie.d | 14 +
> .../ld-riscv-elf/ifunc-seperate-pcrel-pic.d | 5 +
> .../ld-riscv-elf/ifunc-seperate-pcrel-pie.d | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-exe.d | 14 +
> ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pic.d | 17 +
> ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pie.d | 18 +
> .../ld-riscv-elf/ifunc-seperate-resolver.s | 11 +
> ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 111 ++++
> 60 files changed, 1426 insertions(+), 53 deletions(-)
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-nonplt-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-nonplt-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-nonplt-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-nonplt.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-nonplt.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-01-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-01.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-01.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-02-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-02.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-plt-02.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-data.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-data.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-got.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-got.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pic.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-pcrel.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-exe.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pic.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pie.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pic.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pie.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-exe.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pic.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pie.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-seperate-resolver.s
>
> diff --git a/bfd/configure b/bfd/configure
> index 636f338..5d84aed 100755
> --- a/bfd/configure
> +++ b/bfd/configure
> @@ -14917,8 +14917,8 @@ do
> powerpc_elf64_fbsd_le_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;;
> powerpc_xcoff_vec) tb="$tb coff-rs6000.lo $xcoff" ;;
> pru_elf32_vec) tb="$tb elf32-pru.lo elf32.lo $elf" ;;
> - riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf" ;;
> - riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf"; target_size=64 ;;
> + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;;
> + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;;
> rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;;
> rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;;
> rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;;
> diff --git a/bfd/configure.ac b/bfd/configure.ac
> index cecb0fb..5ec4d4f 100644
> --- a/bfd/configure.ac
> +++ b/bfd/configure.ac
> @@ -623,8 +623,8 @@ do
> powerpc_elf64_fbsd_le_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;;
> powerpc_xcoff_vec) tb="$tb coff-rs6000.lo $xcoff" ;;
> pru_elf32_vec) tb="$tb elf32-pru.lo elf32.lo $elf" ;;
> - riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf" ;;
> - riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf"; target_size=64 ;;
> + riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf" ;;
> + riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;;
> rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;;
> rs6000_xcoff64_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;;
> rs6000_xcoff64_aix_vec) tb="$tb coff64-rs6000.lo aix5ppc-core.lo $xcoff"; target_size=64 ;;
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index c088278..a26cd3f 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -31,6 +31,7 @@
> #include "elfxx-riscv.h"
> #include "elf/riscv.h"
> #include "opcode/riscv.h"
> +#include "objalloc.h"
>
> /* Internal relocations used exclusively by the relaxation pass. */
> #define R_RISCV_DELETE (R_RISCV_max + 1)
> @@ -115,6 +116,10 @@ struct riscv_elf_link_hash_table
>
> /* The max alignment of output sections. */
> bfd_vma max_alignment;
> +
> + /* Used by local STT_GNU_IFUNC symbols. */
> + htab_t loc_hash_table;
> + void * loc_hash_memory;
> };
>
>
> @@ -153,17 +158,13 @@ riscv_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
>
> #define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
>
> +/* Reserve two entries of GOTPLT for ld.so, one is used for PLT resolver,
> + the other is used for link map. Other targets also reserve one more
> + entry used for runtime profile? */
> #define GOTPLT_HEADER_SIZE (2 * GOT_ENTRY_SIZE)
>
> #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
>
> -static bfd_vma
> -riscv_elf_got_plt_val (bfd_vma plt_index, struct bfd_link_info *info)
> -{
> - return sec_addr (riscv_elf_hash_table (info)->elf.sgotplt)
> - + GOTPLT_HEADER_SIZE + (plt_index * GOT_ENTRY_SIZE);
> -}
> -
> #if ARCH_SIZE == 32
> # define MATCH_LREG MATCH_LW
> #else
> @@ -265,6 +266,86 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
> return entry;
> }
>
> +/* Compute a hash of a local hash entry. We use elf_link_hash_entry
> + for local symbol so that we can handle local STT_GNU_IFUNC symbols
> + as global symbol. We reuse indx and dynstr_index for local symbol
> + hash since they aren't used by global symbols in this backend. */
> +
> +static hashval_t
> +riscv_elf_local_htab_hash (const void *ptr)
> +{
> + struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) ptr;
> + return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
> +}
> +
> +/* Compare local hash entries. */
> +
> +static int
> +riscv_elf_local_htab_eq (const void *ptr1, const void *ptr2)
> +{
> + struct elf_link_hash_entry *h1 = (struct elf_link_hash_entry *) ptr1;
> + struct elf_link_hash_entry *h2 = (struct elf_link_hash_entry *) ptr2;
> +
> + return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
> +}
> +
> +/* Find and/or create a hash entry for local symbol. */
> +
> +static struct elf_link_hash_entry *
> +riscv_elf_get_local_sym_hash (struct riscv_elf_link_hash_table *htab,
> + bfd *abfd, const Elf_Internal_Rela *rel,
> + bfd_boolean create)
> +{
> + struct riscv_elf_link_hash_entry eh, *ret;
> + asection *sec = abfd->sections;
> + hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
> + ELFNN_R_SYM (rel->r_info));
> + void **slot;
> +
> + eh.elf.indx = sec->id;
> + eh.elf.dynstr_index = ELFNN_R_SYM (rel->r_info);
> + slot = htab_find_slot_with_hash (htab->loc_hash_table, &eh, h,
> + create ? INSERT : NO_INSERT);
> +
> + if (!slot)
> + return NULL;
> +
> + if (*slot)
> + {
> + ret = (struct riscv_elf_link_hash_entry *) *slot;
> + return &ret->elf;
> + }
> +
> + ret = (struct riscv_elf_link_hash_entry *)
> + objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
> + sizeof (struct riscv_elf_link_hash_entry));
> + if (ret)
> + {
> + memset (ret, 0, sizeof (*ret));
> + ret->elf.indx = sec->id;
> + ret->elf.dynstr_index = ELFNN_R_SYM (rel->r_info);
> + ret->elf.dynindx = -1;
> + *slot = ret;
> + }
> + return &ret->elf;
> +}
> +
> +/* Destroy a RISC-V elf linker hash table. */
> +
> +static void
> +riscv_elf_link_hash_table_free (bfd *obfd)
> +{
> + struct riscv_elf_link_hash_table *ret
> + = (struct riscv_elf_link_hash_table *) obfd->link.hash;
> +
> + if (ret->loc_hash_table)
> + htab_delete (ret->loc_hash_table);
> + if (ret->loc_hash_memory)
> + objalloc_free ((struct objalloc *) ret->loc_hash_memory);
> +
> + _bfd_elf_link_hash_table_free (obfd);
> +}
> +
> /* Create a RISC-V ELF linker hash table. */
>
> static struct bfd_link_hash_table *
> @@ -286,6 +367,20 @@ riscv_elf_link_hash_table_create (bfd *abfd)
> }
>
> ret->max_alignment = (bfd_vma) -1;
> +
> + /* Create hash table for local ifunc. */
> + ret->loc_hash_table = htab_try_create (1024,
> + riscv_elf_local_htab_hash,
> + riscv_elf_local_htab_eq,
> + NULL);
> + ret->loc_hash_memory = objalloc_create ();
> + if (!ret->loc_hash_table || !ret->loc_hash_memory)
> + {
> + riscv_elf_link_hash_table_free (abfd);
> + return NULL;
> + }
> + ret->elf.root.hash_table_free = riscv_elf_link_hash_table_free;
> +
> return &ret->elf.root;
> }
>
> @@ -477,6 +572,9 @@ bad_static_reloc (bfd *abfd, unsigned r_type, struct elf_link_hash_entry *h)
> {
> reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type);
>
> + /* We propably can improve the information to tell users that they
> + should be recompile the code with -fPIC or -fPIE, just like what
> + x86 does. */
> (*_bfd_error_handler)
> (_("%pB: relocation %s against `%s' can not be used when making a shared "
> "object; recompile with -fPIC"),
> @@ -526,7 +624,32 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> }
>
> if (r_symndx < symtab_hdr->sh_info)
> - h = NULL;
> + {
> + /* A local symbol. */
> + Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
> + abfd, r_symndx);
> + if (isym == NULL)
> + return FALSE;
> +
> + /* Check relocation against local STT_GNU_IFUNC symbol. */
> + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
> + {
> + h = riscv_elf_get_local_sym_hash (htab, abfd, rel, TRUE);
> + if (h == NULL)
> + return FALSE;
> +
> + /* Fake STT_GNU_IFUNC global symbol. */
> + h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr,
> + isym, NULL);
> + h->type = STT_GNU_IFUNC;
> + h->def_regular = 1;
> + h->ref_regular = 1;
> + h->forced_local = 1;
> + h->root.type = bfd_link_hash_defined;
> + }
> + else
> + h = NULL;
> + }
> else
> {
> h = sym_hashes[r_symndx - symtab_hdr->sh_info];
> @@ -535,6 +658,32 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> h = (struct elf_link_hash_entry *) h->root.u.i.link;
> }
>
> + if (h != NULL)
> + {
> + switch (r_type)
> + {
> + case R_RISCV_32:
> + case R_RISCV_64:
> + case R_RISCV_CALL:
> + case R_RISCV_CALL_PLT:
> + case R_RISCV_HI20:
> + case R_RISCV_GOT_HI20:
> + case R_RISCV_PCREL_HI20:
> + /* Create the ifunc sections, iplt and ipltgot, for static
> + executables. */
> + if (h->type == STT_GNU_IFUNC
> + && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
> + return FALSE;
> + break;
> +
> + default:
> + break;
> + }
> +
> + /* It is referenced by a non-shared object. */
> + h->ref_regular = 1;
> + }
> +
> switch (r_type)
> {
> case R_RISCV_TLS_GD_HI20:
> @@ -574,12 +723,26 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> h->plt.refcount += 1;
> break;
>
> + case R_RISCV_PCREL_HI20:
> + if (h != NULL
> + && h->type == STT_GNU_IFUNC)
> + {
> + h->non_got_ref = 1;
> + h->pointer_equality_needed = 1;
> +
> + /* We don't use the PCREL_HI20 in the data section,
> + so we always need the plt when it refers to
> + ifunc symbol. */
> + h->plt.refcount += 1;
> + }
> + /* Fall through. */
> +
> case R_RISCV_JAL:
> case R_RISCV_BRANCH:
> case R_RISCV_RVC_BRANCH:
> case R_RISCV_RVC_JUMP:
> - case R_RISCV_PCREL_HI20:
> - /* In shared libraries, these relocs are known to bind locally. */
> + /* In shared libraries and pie, these relocs are known
> + to bind locally. */
> if (bfd_link_pic (info))
> break;
> goto static_reloc;
> @@ -604,15 +767,23 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> /* Fall through. */
>
> static_reloc:
> - /* This reloc might not bind locally. */
> - if (h != NULL)
> - h->non_got_ref = 1;
>
> - if (h != NULL && !bfd_link_pic (info))
> + if (h != NULL
> + && (!bfd_link_pic (info)
> + || h->type == STT_GNU_IFUNC))
> {
> - /* We may need a .plt entry if the function this reloc
> - refers to is in a shared lib. */
> - h->plt.refcount += 1;
> + /* This reloc might not bind locally. */
> + h->non_got_ref = 1;
> + h->pointer_equality_needed = 1;
> +
> + if (!h->def_regular
> + || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
> + {
> + /* We may need a .plt entry if the symbol is a function
> + defined in a shared lib or is a function referenced
> + from the code or read-only section. */
> + h->plt.refcount += 1;
> + }
> }
>
> /* If we are creating a shared library, and this is a reloc
> @@ -635,21 +806,28 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> If on the other hand, we are creating an executable, we
> may need to keep relocations for symbols satisfied by a
> dynamic library if we manage to avoid copy relocs for the
> - symbol. */
> + symbol.
> +
> + Generate dynamic pointer relocation against STT_GNU_IFUNC
> + symbol in the non-code section (R_RISCV_32/R_RISCV_64). */
> reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type);
>
> if ((bfd_link_pic (info)
> && (sec->flags & SEC_ALLOC) != 0
> - && ((r != NULL && ! r->pc_relative)
> + && ((r != NULL && !r->pc_relative)
> || (h != NULL
> - && (! info->symbolic
> + && (!info->symbolic
> || h->root.type == bfd_link_hash_defweak
> || !h->def_regular))))
> || (!bfd_link_pic (info)
> && (sec->flags & SEC_ALLOC) != 0
> && h != NULL
> && (h->root.type == bfd_link_hash_defweak
> - || !h->def_regular)))
> + || !h->def_regular))
> + || (!bfd_link_pic (info)
> + && h != NULL
> + && h->type == STT_GNU_IFUNC
> + && (sec->flags & SEC_CODE) == 0))
> {
> struct elf_dyn_relocs *p;
> struct elf_dyn_relocs **head;
> @@ -786,9 +964,10 @@ riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
> if (h->type == STT_FUNC || h->type == STT_GNU_IFUNC || h->needs_plt)
> {
> if (h->plt.refcount <= 0
> - || SYMBOL_CALLS_LOCAL (info, h)
> - || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
> - && h->root.type == bfd_link_hash_undefweak))
> + || (h->type != STT_GNU_IFUNC
> + && (SYMBOL_CALLS_LOCAL (info, h)
> + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
> + && h->root.type == bfd_link_hash_undefweak))))
> {
> /* This case can occur if we saw a R_RISCV_CALL_PLT reloc in an
> input file, but the symbol was never referred to by a dynamic
> @@ -901,8 +1080,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> htab = riscv_elf_hash_table (info);
> BFD_ASSERT (htab != NULL);
>
> - if (htab->elf.dynamic_sections_created
> - && h->plt.refcount > 0)
> + /* Since STT_GNU_IFUNC symbols must go through PLT, we handle them
> + in the allocate_ifunc_dynrelocs and allocate_local_ifunc_dynrelocs,
> + if they are defined and referenced in a non-shared object. */
> + if (h->type == STT_GNU_IFUNC
> + && h->def_regular)
> + return TRUE;
> + else if (htab->elf.dynamic_sections_created
> + && h->plt.refcount > 0)
> {
> /* Make sure this symbol is output as a dynamic symbol.
> Undefined weak syms won't yet be marked as dynamic. */
> @@ -1088,6 +1273,55 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> return TRUE;
> }
>
> +/* Allocate space in .plt, .got and associated reloc sections for
> + ifunc dynamic relocs. */
> +
> +static bfd_boolean
> +allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
> + void *inf)
> +{
> + struct bfd_link_info *info;
> +
> + if (h->root.type == bfd_link_hash_indirect)
> + return TRUE;
> +
> + if (h->root.type == bfd_link_hash_warning)
> + h = (struct elf_link_hash_entry *) h->root.u.i.link;
> +
> + info = (struct bfd_link_info *) inf;
> +
> + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
> + here if it is defined and referenced in a non-shared object. */
> + if (h->type == STT_GNU_IFUNC
> + && h->def_regular)
> + return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
> + &h->dyn_relocs,
> + PLT_ENTRY_SIZE,
> + PLT_HEADER_SIZE,
> + GOT_ENTRY_SIZE,
> + TRUE);
> + return TRUE;
> +}
> +
> +/* Allocate space in .plt, .got and associated reloc sections for
> + local ifunc dynamic relocs. */
> +
> +static bfd_boolean
> +allocate_local_ifunc_dynrelocs (void **slot, void *inf)
> +{
> + struct elf_link_hash_entry *h
> + = (struct elf_link_hash_entry *) *slot;
> +
> + if (h->type != STT_GNU_IFUNC
> + || !h->def_regular
> + || !h->ref_regular
> + || !h->forced_local
> + || h->root.type != bfd_link_hash_defined)
> + abort ();
> +
> + return allocate_ifunc_dynrelocs (h, inf);
> +}
> +
> static bfd_boolean
> riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> {
> @@ -1178,10 +1412,18 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> }
> }
>
> - /* Allocate global sym .plt and .got entries, and space for global
> - sym dynamic relocs. */
> + /* Allocate .plt and .got entries and space dynamic relocs for
> + global symbols. */
> elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
>
> + /* Allocate .plt and .got entries and space dynamic relocs for
> + global ifunc symbols. */
> + elf_link_hash_traverse (&htab->elf, allocate_ifunc_dynrelocs, info);
> +
> + /* Allocate .plt and .got entries and space dynamic relocs for
> + local ifunc symbols. */
> + htab_traverse (htab->loc_hash_table, allocate_local_ifunc_dynrelocs, info);
> +
> if (htab->elf.sgotplt)
> {
> struct elf_link_hash_entry *got;
> @@ -1213,6 +1455,8 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
> if (s == htab->elf.splt
> || s == htab->elf.sgot
> || s == htab->elf.sgotplt
> + || s == htab->elf.iplt
> + || s == htab->elf.igotplt
> || s == htab->elf.sdynbss
> || s == htab->elf.sdynrelro
> || s == htab->sdyntdata)
> @@ -1645,7 +1889,6 @@ riscv_elf_relocate_section (bfd *output_bfd,
> Elf_Internal_Rela *relend;
> riscv_pcrel_relocs pcrel_relocs;
> bfd_boolean ret = FALSE;
> - asection *sreloc = elf_section_data (input_section)->sreloc;
> struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
> Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
> struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
> @@ -1664,7 +1907,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
> asection *sec;
> bfd_vma relocation;
> bfd_reloc_status_type r = bfd_reloc_ok;
> - const char *name;
> + const char *name = NULL;
> bfd_vma off, ie_off;
> bfd_boolean unresolved_reloc, is_ie = FALSE;
> bfd_vma pc = sec_addr (input_section) + rel->r_offset;
> @@ -1689,6 +1932,19 @@ riscv_elf_relocate_section (bfd *output_bfd,
> sym = local_syms + r_symndx;
> sec = local_sections[r_symndx];
> relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
> +
> + /* Relocate against local STT_GNU_IFUNC symbol. */
> + if (!bfd_link_relocatable (info)
> + && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
> + {
> + h = riscv_elf_get_local_sym_hash (htab, input_bfd, rel, FALSE);
> + if (h == NULL)
> + abort ();
> +
> + /* Set STT_GNU_IFUNC symbol value. */
> + h->root.u.def.value = sym->st_value;
> + h->root.u.def.section = sec;
> + }
> }
> else
> {
> @@ -1717,6 +1973,235 @@ riscv_elf_relocate_section (bfd *output_bfd,
> if (bfd_link_relocatable (info))
> continue;
>
> + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle
> + it here if it is defined in a non-shared object. */
> + if (h != NULL
> + && h->type == STT_GNU_IFUNC
> + && h->def_regular)
> + {
> + asection *plt, *base_got;
> +
> + if ((input_section->flags & SEC_ALLOC) == 0)
> + {
> + /* If this is a SHT_NOTE section without SHF_ALLOC, treat
> + STT_GNU_IFUNC symbol as STT_FUNC. */
> + if (elf_section_type (input_section) == SHT_NOTE)
> + goto skip_ifunc;
> +
> + /* Dynamic relocs are not propagated for SEC_DEBUGGING
> + sections because such sections are not SEC_ALLOC and
> + thus ld.so will not process them. */
> + if ((input_section->flags & SEC_DEBUGGING) != 0)
> + continue;
> +
> + abort ();
> + }
> + else if (h->plt.offset == (bfd_vma) -1
> + /* The following relocation may not need the .plt entries
> + when all references to a STT_GNU_IFUNC symbols are done
> + via GOT or static function pointers. */
> + && r_type != R_RISCV_32
> + && r_type != R_RISCV_64
> + && r_type != R_RISCV_HI20
> + && r_type != R_RISCV_GOT_HI20
> + && r_type != R_RISCV_LO12_I
> + && r_type != R_RISCV_LO12_S)
> + goto bad_ifunc_reloc;
> +
> + /* STT_GNU_IFUNC symbol must go through PLT. */
> + plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
> + relocation = plt->output_section->vma
> + + plt->output_offset
> + + h->plt.offset;
> +
> + switch (r_type)
> + {
> + case R_RISCV_32:
> + case R_RISCV_64:
> + if (rel->r_addend != 0)
> + {
> + if (h->root.root.string)
> + name = h->root.root.string;
> + else
> + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL);
> +
> + _bfd_error_handler
> + /* xgettext:c-format */
> + (_("%pB: relocation %s against STT_GNU_IFUNC "
> + "symbol `%s' has non-zero addend: %" PRId64),
> + input_bfd, howto->name, name, (int64_t) rel->r_addend);
> + bfd_set_error (bfd_error_bad_value);
> + return FALSE;
> + }
> +
> + /* Generate dynamic relocation only when there is a non-GOT
> + reference in a shared object or there is no PLT. */
> + if ((bfd_link_pic (info) && h->non_got_ref)
> + || h->plt.offset == (bfd_vma) -1)
> + {
> + Elf_Internal_Rela outrel;
> + asection *sreloc;
> +
> + /* Need a dynamic relocation to get the real function
> + address. */
> + outrel.r_offset = _bfd_elf_section_offset (output_bfd,
> + info,
> + input_section,
> + rel->r_offset);
> + if (outrel.r_offset == (bfd_vma) -1
> + || outrel.r_offset == (bfd_vma) -2)
> + abort ();
> +
> + outrel.r_offset += input_section->output_section->vma
> + + input_section->output_offset;
> +
> + if (h->dynindx == -1
> + || h->forced_local
> + || bfd_link_executable (info))
> + {
> + info->callbacks->minfo
> + (_("Local IFUNC function `%s' in %pB\n"),
> + h->root.root.string,
> + h->root.u.def.section->owner);
> +
> + /* This symbol is resolved locally. */
> + outrel.r_info = ELFNN_R_INFO (0, R_RISCV_IRELATIVE);
> + outrel.r_addend = h->root.u.def.value
> + + h->root.u.def.section->output_section->vma
> + + h->root.u.def.section->output_offset;
> + }
> + else
> + {
> + outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
> + outrel.r_addend = 0;
> + }
> +
> + /* Dynamic relocations are stored in
> + 1. .rela.ifunc section in PIC object.
> + 2. .rela.got section in dynamic executable.
> + 3. .rela.iplt section in static executable. */
> + if (bfd_link_pic (info))
> + sreloc = htab->elf.irelifunc;
> + else if (htab->elf.splt != NULL)
> + sreloc = htab->elf.srelgot;
> + else
> + sreloc = htab->elf.irelplt;
> +
> + riscv_elf_append_rela (output_bfd, sreloc, &outrel);
> +
> + /* If this reloc is against an external symbol, we
> + do not want to fiddle with the addend. Otherwise,
> + we need to include the symbol value so that it
> + becomes an addend for the dynamic reloc. For an
> + internal symbol, we have updated addend. */
> + continue;
> + }
> + goto do_relocation;
> +
> + case R_RISCV_GOT_HI20:
> + base_got = htab->elf.sgot;
> + off = h->got.offset;
> +
> + if (base_got == NULL)
> + abort ();
> +
> + if (off == (bfd_vma) -1)
> + {
> + bfd_vma plt_idx;
> +
> + /* We can't use h->got.offset here to save state, or
> + even just remember the offset, as finish_dynamic_symbol
> + would use that as offset into .got. */
> +
> + if (htab->elf.splt != NULL)
> + {
> + plt_idx = (h->plt.offset - PLT_HEADER_SIZE)
> + / PLT_ENTRY_SIZE;
> + off = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
> + base_got = htab->elf.sgotplt;
> + }
> + else
> + {
> + plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
> + off = plt_idx * GOT_ENTRY_SIZE;
> + base_got = htab->elf.igotplt;
> + }
> +
> + if (h->dynindx == -1
> + || h->forced_local
> + || info->symbolic)
> + {
> + /* This references the local definition. We must
> + initialize this entry in the global offset table.
> + Since the offset must always be a multiple of 8,
> + we use the least significant bit to record
> + whether we have initialized it already.
> +
> + When doing a dynamic link, we create a .rela.got
> + relocation entry to initialize the value. This
> + is done in the finish_dynamic_symbol routine. */
> + if ((off & 1) != 0)
> + off &= ~1;
> + else
> + {
> + bfd_put_NN (output_bfd, relocation,
> + base_got->contents + off);
> + /* Note that this is harmless for the case,
> + as -1 | 1 still is -1. */
> + h->got.offset |= 1;
> + }
> + }
> + }
> +
> + relocation = base_got->output_section->vma
> + + base_got->output_offset + off;
> +
> + r_type = ELFNN_R_TYPE (rel->r_info);
> + howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
> + if (howto == NULL)
> + r = bfd_reloc_notsupported;
> + else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
> + relocation, FALSE))
> + r = bfd_reloc_overflow;
> + goto do_relocation;
> +
> + case R_RISCV_CALL:
> + case R_RISCV_CALL_PLT:
> + case R_RISCV_HI20:
> + case R_RISCV_LO12_I:
> + case R_RISCV_LO12_S:
> + goto do_relocation;
> +
> + case R_RISCV_PCREL_HI20:
> + r_type = ELFNN_R_TYPE (rel->r_info);
> + howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
> + if (howto == NULL)
> + r = bfd_reloc_notsupported;
> + else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
> + relocation, FALSE))
> + r = bfd_reloc_overflow;
> + goto do_relocation;
> +
> + default:
> + bad_ifunc_reloc:
> + if (h->root.root.string)
> + name = h->root.root.string;
> + else
> + /* The entry of local ifunc is fake in global hash table,
> + we should find the name by the original local symbol. */
> + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL);
> +
> + _bfd_error_handler
> + /* xgettext:c-format */
> + (_("%pB: relocation %s against STT_GNU_IFUNC "
> + "symbol `%s' isn't supported"), input_bfd,
> + howto->name, name);
> + bfd_set_error (bfd_error_bad_value);
> + return FALSE;
> + }
> + }
> +
> + skip_ifunc:
> if (h != NULL)
> name = h->root.root.string;
> else
> @@ -2013,6 +2498,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
> || h->root.type == bfd_link_hash_undefined)))
> {
> Elf_Internal_Rela outrel;
> + asection *sreloc;
> bfd_boolean skip_static_relocation, skip_dynamic_relocation;
>
> /* When generating a shared object, these relocations
> @@ -2042,6 +2528,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
> outrel.r_addend = relocation + rel->r_addend;
> }
>
> + sreloc = elf_section_data (input_section)->sreloc;
> riscv_elf_append_rela (output_bfd, sreloc, &outrel);
> if (skip_static_relocation)
> continue;
> @@ -2216,6 +2703,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
> r = bfd_reloc_notsupported;
> }
>
> + do_relocation:
> if (r == bfd_reloc_ok)
> r = perform_relocation (howto, rel, relocation, input_section,
> input_bfd, contents);
> @@ -2299,23 +2787,58 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
> {
> /* We've decided to create a PLT entry for this symbol. */
> bfd_byte *loc;
> - bfd_vma i, header_address, plt_idx, got_address;
> + bfd_vma i, header_address, plt_idx, got_offset, got_address;
> uint32_t plt_entry[PLT_ENTRY_INSNS];
> Elf_Internal_Rela rela;
> -
> - BFD_ASSERT (h->dynindx != -1);
> + asection *plt, *gotplt, *relplt;
> +
> + /* When building a static executable, use .iplt, .igot.plt and
> + .rela.iplt sections for STT_GNU_IFUNC symbols. */
> + if (htab->elf.splt != NULL)
> + {
> + plt = htab->elf.splt;
> + gotplt = htab->elf.sgotplt;
> + relplt = htab->elf.srelplt;
> + }
> + else
> + {
> + plt = htab->elf.iplt;
> + gotplt = htab->elf.igotplt;
> + relplt = htab->elf.irelplt;
> + }
> +
> + /* This symbol has an entry in the procedure linkage table. Set
> + it up. */
> + if ((h->dynindx == -1
> + && !((h->forced_local || bfd_link_executable (info))
> + && h->def_regular
> + && h->type == STT_GNU_IFUNC))
> + || plt == NULL
> + || gotplt == NULL
> + || relplt == NULL)
> + return FALSE;
>
> /* Calculate the address of the PLT header. */
> - header_address = sec_addr (htab->elf.splt);
> + header_address = sec_addr (plt);
>
> - /* Calculate the index of the entry. */
> - plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
> + /* Calculate the index of the entry and the offset of .got.plt entry.
> + For static executables, we don't reserve anything. */
> + if (plt == htab->elf.splt)
> + {
> + plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
> + got_offset = GOTPLT_HEADER_SIZE + (plt_idx * GOT_ENTRY_SIZE);
> + }
> + else
> + {
> + plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
> + got_offset = plt_idx * GOT_ENTRY_SIZE;
> + }
>
> /* Calculate the address of the .got.plt entry. */
> - got_address = riscv_elf_got_plt_val (plt_idx, info);
> + got_address = sec_addr (gotplt) + got_offset;
>
> /* Find out where the .plt entry should go. */
> - loc = htab->elf.splt->contents + h->plt.offset;
> + loc = plt->contents + h->plt.offset;
>
> /* Fill in the PLT entry itself. */
> if (! riscv_make_plt_entry (output_bfd, got_address,
> @@ -2327,16 +2850,37 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
> bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
>
> /* Fill in the initial value of the .got.plt entry. */
> - loc = htab->elf.sgotplt->contents
> - + (got_address - sec_addr (htab->elf.sgotplt));
> - bfd_put_NN (output_bfd, sec_addr (htab->elf.splt), loc);
> + loc = gotplt->contents + (got_address - sec_addr (gotplt));
> + bfd_put_NN (output_bfd, sec_addr (plt), loc);
>
> - /* Fill in the entry in the .rela.plt section. */
> rela.r_offset = got_address;
> - rela.r_addend = 0;
> - rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_JUMP_SLOT);
>
> - loc = htab->elf.srelplt->contents + plt_idx * sizeof (ElfNN_External_Rela);
> + if (h->dynindx == -1
> + || ((bfd_link_executable (info)
> + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
> + && h->def_regular
> + && h->type == STT_GNU_IFUNC))
> + {
> + info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
> + h->root.root.string,
> + h->root.u.def.section->owner);
> +
> + /* If an STT_GNU_IFUNC symbol is locally defined, generate
> + R_RISCV_IRELATIVE instead of R_RISCV_JUMP_SLOT. */
A local definition includes -Bsymbolic. Filed
https://sourceware.org/bugzilla/show_bug.cgi?id=27153 (very minor
issue).
The symbol representation needs a preemptible bit to avoid issues in
various backends.
> + asection *sec = h->root.u.def.section;
> + rela.r_info = ELFNN_R_INFO (0, R_RISCV_IRELATIVE);
> + rela.r_addend = h->root.u.def.value
> + + sec->output_section->vma
> + + sec->output_offset;
> + }
> + else
> + {
> + /* Fill in the entry in the .rela.plt section. */
> + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_JUMP_SLOT);
> + rela.r_addend = 0;
> + }
> +
> + loc = relplt->contents + plt_idx * sizeof (ElfNN_External_Rela);
> bed->s->swap_reloca_out (output_bfd, &rela, loc);
>
> if (!h->def_regular)
> @@ -2369,13 +2913,73 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
>
> rela.r_offset = sec_addr (sgot) + (h->got.offset &~ (bfd_vma) 1);
>
> + /* Handle the ifunc symbol in GOT entry. */
> + if (h->def_regular
> + && h->type == STT_GNU_IFUNC)
> + {
> + 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
> + in static executable. */
> + srela = htab->elf.irelplt;
> + }
> + if (SYMBOL_REFERENCES_LOCAL (info, h))
> + {
> + info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
> + h->root.root.string,
> + h->root.u.def.section->owner);
> +
> + rela.r_info = ELFNN_R_INFO (0, R_RISCV_IRELATIVE);
> + rela.r_addend = (h->root.u.def.value
> + + h->root.u.def.section->output_section->vma
> + + h->root.u.def.section->output_offset);
> + }
> + else
> + {
> + /* Generate R_RISCV_NN. */
> + BFD_ASSERT((h->got.offset & 1) == 0);
> + BFD_ASSERT (h->dynindx != -1);
> + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
> + rela.r_addend = 0;
> + }
> + }
> + else if (bfd_link_pic (info))
> + {
> + /* Generate R_RISCV_NN. */
> + BFD_ASSERT((h->got.offset & 1) == 0);
> + BFD_ASSERT (h->dynindx != -1);
> + rela.r_info = ELFNN_R_INFO (h->dynindx, R_RISCV_NN);
> + rela.r_addend = 0;
> + }
> + else
> + {
> + asection *plt;
> +
> + if (!h->pointer_equality_needed)
> + abort ();
> +
> + /* For non-shared object, we can't use .got.plt, which
> + contains the real function address if we need pointer
> + equality. We load the GOT entry with the PLT entry. */
> + plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
> + bfd_put_NN (output_bfd, (plt->output_section->vma
> + + plt->output_offset
> + + h->plt.offset),
> + htab->elf.sgot->contents
> + + (h->got.offset & ~(bfd_vma) 1));
> + 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. */
> - if (bfd_link_pic (info)
> - && SYMBOL_REFERENCES_LOCAL (info, h))
> + else if (bfd_link_pic (info)
> + && SYMBOL_REFERENCES_LOCAL (info, h))
> {
> BFD_ASSERT((h->got.offset & 1) != 0);
> asection *sec = h->root.u.def.section;
> @@ -2423,6 +3027,18 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
> return TRUE;
> }
>
> +/* Finish up local dynamic symbol handling. We set the contents of
> + various dynamic sections here. */
> +
> +static bfd_boolean
> +riscv_elf_finish_local_dynamic_symbol (void **slot, void *inf)
> +{
> + struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
> + struct bfd_link_info *info = (struct bfd_link_info *) inf;
> +
> + return riscv_elf_finish_dynamic_symbol (info->output_bfd, info, h, NULL);
> +}
> +
> /* Finish up the dynamic sections. */
>
> static bfd_boolean
> @@ -2549,6 +3165,11 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
> elf_section_data (output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE;
> }
>
> + /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
> + htab_traverse (htab->loc_hash_table,
> + riscv_elf_finish_local_dynamic_symbol,
> + info);
> +
> return TRUE;
> }
>
> @@ -4052,6 +4673,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
> reserve_size = (isym->st_size - rel->r_addend) > isym->st_size
> ? 0 : isym->st_size - rel->r_addend;
>
> + /* Relocate against local STT_GNU_IFUNC symbol. we have created
> + a fake global symbol entry for this, so deal with the local ifunc
> + as a global. */
> + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
> + continue;
> +
> if (isym->st_shndx == SHN_UNDEF)
> sym_sec = sec, symval = rel->r_offset;
> else
> @@ -4082,6 +4709,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
> || h->root.type == bfd_link_hash_warning)
> h = (struct elf_link_hash_entry *) h->root.u.i.link;
>
> + /* Disable the relaxation for ifunc. */
> + if (h != NULL && h->type == STT_GNU_IFUNC)
> + continue;
> +
> if (h->root.type == bfd_link_hash_undefweak
> && (relax_func == _bfd_riscv_relax_lui
> || relax_func == _bfd_riscv_relax_pc))
> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> index e5adea5..003df59 100644
> --- a/bfd/elfxx-riscv.c
> +++ b/bfd/elfxx-riscv.c
> @@ -854,6 +854,21 @@ static reloc_howto_type howto_table[] =
> 0, /* src_mask */
> 0xffffffff, /* dst_mask */
> FALSE), /* pcrel_offset */
> +
> + /* Relocation against a local ifunc symbol in a shared object. */
> + HOWTO (R_RISCV_IRELATIVE, /* type */
> + 0, /* rightshift */
> + 2, /* size */
> + 32, /* bitsize */
> + FALSE, /* pc_relative */
> + 0, /* bitpos */
> + complain_overflow_dont, /* complain_on_overflow */
> + bfd_elf_generic_reloc, /* special_function */
> + "R_RISCV_IRELATIVE", /* name */
> + FALSE, /* partial_inplace */
> + 0, /* src_mask */
> + 0xffffffff, /* dst_mask */
> + FALSE), /* pcrel_offset */
> };
>
> /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
> diff --git a/include/elf/riscv.h b/include/elf/riscv.h
> index 5062a49..98c7ac6 100644
> --- a/include/elf/riscv.h
> +++ b/include/elf/riscv.h
> @@ -88,6 +88,7 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
> RELOC_NUMBER (R_RISCV_SET16, 55)
> RELOC_NUMBER (R_RISCV_SET32, 56)
> RELOC_NUMBER (R_RISCV_32_PCREL, 57)
> + RELOC_NUMBER (R_RISCV_IRELATIVE, 58)
> END_RELOC_NUMBERS (R_RISCV_max)
>
> /* Processor specific flags for the ELF header e_flags field. */
> diff --git a/ld/emulparams/elf32lriscv-defs.sh b/ld/emulparams/elf32lriscv-defs.sh
> index bc46491..b823ced 100644
> --- a/ld/emulparams/elf32lriscv-defs.sh
> +++ b/ld/emulparams/elf32lriscv-defs.sh
> @@ -26,6 +26,7 @@ case "$target" in
> ;;
> esac
>
> +IREL_IN_PLT=
> TEXT_START_ADDR=0x10000
> MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
> COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
> diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp
> index 63ab18d..9ed4bd7 100644
> --- a/ld/testsuite/ld-ifunc/ifunc.exp
> +++ b/ld/testsuite/ld-ifunc/ifunc.exp
> @@ -39,7 +39,6 @@ if { ![is_elf_format] || ![supports_gnu_osabi]
> || [istarget nds32*-*-*]
> || [istarget nios2-*-*]
> || [istarget or1k-*-*]
> - || [istarget riscv*-*-*]
> || [istarget score*-*-*]
> || [istarget sh*-*-*]
> || [istarget tic6x-*-*]
> @@ -736,7 +735,8 @@ run_ld_link_exec_tests [list \
> if { [isnative]
> && !([istarget "powerpc-*-*"]
> || [istarget "aarch64*-*-*"]
> - || [istarget "sparc*-*-*"]) } {
> + || [istarget "sparc*-*-*"]
> + || [istarget "riscv*-*-*"]) } {
> run_ld_link_exec_tests [list \
> [list \
> "Run pr23169a" \
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-nonplt-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-exe.rd
> new file mode 100644
> index 0000000..0de47a4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-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-nonplt-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-pic.rd
> new file mode 100644
> index 0000000..e2e7ad9
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-pic.rd
> @@ -0,0 +1,7 @@
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-nonplt-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-pie.rd
> new file mode 100644
> index 0000000..f9fbd87
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-nonplt-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.ifunc' 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-nonplt.d b/ld/testsuite/ld-riscv-elf/ifunc-nonplt.d
> new file mode 100644
> index 0000000..e3517d3
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-nonplt.d
> @@ -0,0 +1,11 @@
> +#...
> +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]+[ ]+(lw|ld)[ ]+.*<(__DATA_BEGIN__|.*)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-nonplt.s b/ld/testsuite/ld-riscv-elf/ifunc-nonplt.s
> new file mode 100644
> index 0000000..ce6ca69
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-nonplt.s
> @@ -0,0 +1,39 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> +.ifdef __64_bit__
> + ld x1, %pcrel_lo (.L1) (x1)
> +.else
> + lw x1, %pcrel_lo (.L1) (x1)
> +.endif
> +
> +.L2:
> + auipc x2, %pcrel_hi (foo_addr)
> +.ifdef __64_bit__
> + ld x2, %pcrel_lo (.L2) (x2)
> +.else
> + lw x2, %pcrel_lo (.L2) (x2)
> +.endif
> + ret
> + .size bar, .-bar
> +
> + .data
> +foo_addr:
> +.ifdef __64_bit__
> + .quad foo
> +.else
> + .long foo
> +.endif
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-exe.rd
> @@ -0,0 +1,3 @@
> +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-01-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-pic.rd
> new file mode 100644
> index 0000000..6f5218b
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-pic.rd
> @@ -0,0 +1,7 @@
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-01-pie.rd
> @@ -0,0 +1,3 @@
> +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-01.d b/ld/testsuite/ld-riscv-elf/ifunc-plt-01.d
> new file mode 100644
> index 0000000..bed9fe6
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-01.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_.*|__DATA_BEGIN__.*|.*)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-01.s b/ld/testsuite/ld-riscv-elf/ifunc-plt-01.s
> new file mode 100644
> index 0000000..65c65cd
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-01.s
> @@ -0,0 +1,31 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> +.ifdef __64_bit__
> + ld x1, %pcrel_lo (.L1) (x1)
> +.else
> + lw x1, %pcrel_lo (.L1) (x1)
> +.endif
> +
> +.L2:
> + auipc x2, %pcrel_hi (foo)
> + addi x2, x2, %pcrel_lo (.L2)
> +
> + call foo
> + call foo@plt
> +
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-exe.rd
> @@ -0,0 +1,3 @@
> +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-02-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-pic.rd
> new file mode 100644
> index 0000000..3299aa4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-pic.rd
> @@ -0,0 +1,11 @@
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd
> new file mode 100644
> index 0000000..28a3c99
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-02-pie.rd
> @@ -0,0 +1,7 @@
> +Relocation section '.rela.ifunc' 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-02.d b/ld/testsuite/ld-riscv-elf/ifunc-plt-02.d
> new file mode 100644
> index 0000000..b8638b9
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-02.d
> @@ -0,0 +1,21 @@
> +#...
> +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]+[ ]+(lw|ld)[ ]+.*<(__DATA_BEGIN__.*|.*)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-plt-02.s b/ld/testsuite/ld-riscv-elf/ifunc-plt-02.s
> new file mode 100644
> index 0000000..c3022be
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-plt-02.s
> @@ -0,0 +1,46 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> +.ifdef __64_bit__
> + ld x1, %pcrel_lo (.L1) (x1)
> +.else
> + lw x1, %pcrel_lo (.L1) (x1)
> +.endif
> +
> +.L2:
> + auipc x2, %pcrel_hi (foo_addr)
> +.ifdef __64_bit__
> + ld x2, %pcrel_lo (.L2) (x2)
> +.else
> + lw x2, %pcrel_lo (.L2) (x2)
> +.endif
> +
> +.L3:
> + auipc x3, %pcrel_hi (foo)
> + addi x3, x3, %pcrel_lo (.L3)
> +
> + call foo
> + call foo@plt
> + ret
> + .size bar, .-bar
> +
> + .data
> +foo_addr:
> +.ifdef __64_bit__
> + .quad foo
> +.else
> + .long foo
> +.endif
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-exe.rd
> @@ -0,0 +1,3 @@
> +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-reloc-call-01-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pic.rd
> new file mode 100644
> index 0000000..7bfaa2d
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pic.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pie.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01-pie.rd
> @@ -0,0 +1,3 @@
> +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-reloc-call-01.d b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.d
> new file mode 100644
> index 0000000..d4457c9
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.d
> @@ -0,0 +1,13 @@
> +#...
> +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]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.s b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.s
> new file mode 100644
> index 0000000..89e6326
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-01.s
> @@ -0,0 +1,17 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> + call foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-exe.rd
> @@ -0,0 +1,3 @@
> +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-reloc-call-02-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pic.rd
> new file mode 100644
> index 0000000..7bfaa2d
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pic.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pie.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02-pie.rd
> @@ -0,0 +1,3 @@
> +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-reloc-call-02.d b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.d
> new file mode 100644
> index 0000000..40c0309
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.d
> @@ -0,0 +1,15 @@
> +#...
> +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]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.s b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.s
> new file mode 100644
> index 0000000..e493c47
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-call-02.s
> @@ -0,0 +1,18 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> + call foo@plt
> + call foo
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-exe.rd
> @@ -0,0 +1,3 @@
> +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-reloc-data-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pic.rd
> new file mode 100644
> index 0000000..9be346b
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pic.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.ifunc' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd
> new file mode 100644
> index 0000000..e14b02b
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data-pie.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.ifunc' 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-reloc-data.d b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data.d
> new file mode 100644
> index 0000000..1956cc3
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data.d
> @@ -0,0 +1,9 @@
> +#...
> +Disassembly of section .text:
> +#...
> +0+[0-9a-f]+ <foo_resolver>:
> +#...
> +0+[0-9a-f]+ <bar>:
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<(__DATA_BEGIN__.*|.*)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-data.s b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data.s
> new file mode 100644
> index 0000000..b49bda1
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-data.s
> @@ -0,0 +1,31 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %pcrel_hi (foo_addr)
> +.ifdef __64_bit__
> + ld x1, %pcrel_lo (.L1) (x1)
> +.else
> + lw x1, %pcrel_lo (.L1) (x1)
> +.endif
> + ret
> + .size bar, .-bar
> +
> + .data
> +foo_addr:
> +.ifdef __64_bit__
> + .quad foo
> +.else
> + .long foo
> +.endif
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-exe.rd
> @@ -0,0 +1,3 @@
> +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-reloc-got-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pic.rd
> new file mode 100644
> index 0000000..41cbc07
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pic.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd
> new file mode 100644
> index 0000000..cef1a77
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got-pie.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.got' 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-reloc-got.d b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got.d
> new file mode 100644
> index 0000000..3277e8f
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got.d
> @@ -0,0 +1,9 @@
> +#...
> +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_.*|.*)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-got.s b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got.s
> new file mode 100644
> index 0000000..eca16d5
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-got.s
> @@ -0,0 +1,23 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> +.ifdef __64_bit__
> + ld x1, %pcrel_lo (.L1) (x1)
> +.else
> + lw x1, %pcrel_lo (.L1) (x1)
> +.endif
> + ret
> + .size bar, .-bar
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-exe.rd
> @@ -0,0 +1,3 @@
> +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-reloc-pcrel-pic.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pic.rd
> new file mode 100644
> index 0000000..7bfaa2d
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pic.rd
> @@ -0,0 +1,3 @@
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+foo\(\)[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd
> new file mode 100644
> index 0000000..97461e4
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel-pie.rd
> @@ -0,0 +1,3 @@
> +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-reloc-pcrel.d b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.d
> new file mode 100644
> index 0000000..bc947e3
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.d
> @@ -0,0 +1,15 @@
> +#...
> +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]+[ ]+addi[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
> +.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<(\*ABS\*\+0x[0-9a-f]+@plt|foo@plt|.plt)>
> +#...
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s
> new file mode 100644
> index 0000000..7ea454c
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-reloc-pcrel.s
> @@ -0,0 +1,26 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> +
> + .globl bar
> + .type bar, @function
> +bar:
> +.L1:
> + auipc x1, %pcrel_hi (foo)
> + addi x1, x1, %pcrel_lo (.L1)
> +.L2:
> + auipc x2, %pcrel_hi (foo)
> +.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/ifunc-seperate-caller-nonplt.s b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s
> new file mode 100644
> index 0000000..23c7254
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s
> @@ -0,0 +1,23 @@
> + .text
> +
> + # Call the IFUNC `foo` which is defined in the other modules.
> + .globl foo
> + .type foo, %function
> +
> + .globl main
> + .type main, @function
> +main:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> + addi x1, x1, %pcrel_lo (.L1)
> +
> +.L2:
> + auipc x2, %pcrel_hi (foo_addr)
> + addi x2, x2, %pcrel_lo (.L2)
> +
> + ret
> + .size main, .-main
> +
> + .data
> +foo_addr:
> + .long foo
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-pcrel.s b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-pcrel.s
> new file mode 100644
> index 0000000..2d29bcd
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-pcrel.s
> @@ -0,0 +1,14 @@
> + .text
> +
> + # Call the IFUNC `foo` which is defined in the other modules.
> + .globl foo
> + .type foo, %function
> +
> + .globl main
> + .type main, @function
> +main:
> +.L1:
> + auipc x1, %pcrel_hi (foo)
> + addi x1, x1, %pcrel_lo (.L1)
> + ret
> + .size main, .-main
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s
> new file mode 100644
> index 0000000..8aa6403
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s
> @@ -0,0 +1,26 @@
> + .text
> +
> + # Call the IFUNC `foo` which is defined in the other modules.
> + .globl foo
> + .type foo, %function
> +
> + .globl main
> + .type main, @function
> +main:
> +.L1:
> + auipc x1, %got_pcrel_hi (foo)
> + addi x1, x1, %pcrel_lo (.L1)
> +
> +.L2:
> + auipc x2, %pcrel_hi (foo_addr)
> + addi x2, x2, %pcrel_lo (.L2)
> +
> + call foo
> + call foo@plt
> +
> + ret
> + .size main, .-main
> +
> + .data
> +foo_addr:
> + .long foo
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-exe.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-exe.d
> new file mode 100644
> index 0000000..540a21b
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-exe.d
> @@ -0,0 +1,14 @@
> +#name: Link shared ifunc resolver with non-PLT caller (exe)
> +#source: ifunc-seperate-caller-nonplt.s
> +#as:
> +#ld: -z nocombreloc tmpdir/ifunc-seperate-resolver.so
> +#warning: .*
> +#readelf: -rW
> +
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pic.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pic.d
> new file mode 100644
> index 0000000..3ed1812
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pic.d
> @@ -0,0 +1,13 @@
> +#name: Link shared ifunc resolver with non-PLT caller (pic)
> +#source: ifunc-seperate-caller-nonplt.s
> +#as:
> +#ld: -z nocombreloc -shared tmpdir/ifunc-seperate-resolver.so
> +#readelf: -rW
> +
> +Relocation section '.rela.data' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pie.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pie.d
> new file mode 100644
> index 0000000..c9c9eab
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-nonplt-pie.d
> @@ -0,0 +1,14 @@
> +#name: Link shared ifunc resolver with non-PLT caller (pie)
> +#source: ifunc-seperate-caller-nonplt.s
> +#as:
> +#ld: -z nocombreloc -pie tmpdir/ifunc-seperate-resolver.so
> +#warning: .*
> +#readelf: -rW
> +
> +Relocation section '.rela.data' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pic.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pic.d
> new file mode 100644
> index 0000000..1c11a2d
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pic.d
> @@ -0,0 +1,5 @@
> +#name: Link shared IFUNC resolver with PCREL caller (pic)
> +#source: ifunc-seperate-caller-pcrel.s
> +#as:
> +#ld: -z nocombreloc -shared tmpdir/ifunc-seperate-resolver.so
> +#error: .*unresolvable R_RISCV_PCREL_HI20 relocation.*
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pie.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pie.d
> new file mode 100644
> index 0000000..0d0e3cc
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-pcrel-pie.d
> @@ -0,0 +1,5 @@
> +#name: Link shared IFUNC resolver with PCREL caller (pie)
> +#source: ifunc-seperate-caller-pcrel.s
> +#as:
> +#ld: -z nocombreloc -pie tmpdir/ifunc-seperate-resolver.so
> +#error: .*unresolvable R_RISCV_PCREL_HI20 relocation.*
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-exe.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-exe.d
> new file mode 100644
> index 0000000..a538564
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-exe.d
> @@ -0,0 +1,14 @@
> +#name: Link shared ifunc resolver with PLT caller (exe)
> +#source: ifunc-seperate-caller-plt.s
> +#as:
> +#ld: -z nocombreloc tmpdir/ifunc-seperate-resolver.so
> +#warning: .*
> +#readelf: -rW
> +
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pic.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pic.d
> new file mode 100644
> index 0000000..9efa244
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pic.d
> @@ -0,0 +1,17 @@
> +#name: Link shared ifunc resolver with PLT caller (pic)
> +#source: ifunc-seperate-caller-plt.s
> +#as:
> +#ld: -z nocombreloc -shared tmpdir/ifunc-seperate-resolver.so
> +#readelf: -rW
> +
> +Relocation section '.rela.data' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pie.d b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pie.d
> new file mode 100644
> index 0000000..8349e61
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-plt-pie.d
> @@ -0,0 +1,18 @@
> +#name: Link shared ifunc resolver with PLT caller (pie)
> +#source: ifunc-seperate-caller-plt.s
> +#as:
> +#ld: -z nocombreloc -pie tmpdir/ifunc-seperate-resolver.so
> +#warning: .*
> +#readelf: -rW
> +
> +Relocation section '.rela.data' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.got' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+[0-9a-f]+[ ]+foo \+ 0
> +#...
> +Relocation section '.rela.plt' at .*
> +[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
> +[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+[0-9a-f]+[ ]+foo \+ 0
> diff --git a/ld/testsuite/ld-riscv-elf/ifunc-seperate-resolver.s b/ld/testsuite/ld-riscv-elf/ifunc-seperate-resolver.s
> new file mode 100644
> index 0000000..a222847
> --- /dev/null
> +++ b/ld/testsuite/ld-riscv-elf/ifunc-seperate-resolver.s
> @@ -0,0 +1,11 @@
> + .text
> +
> + .type foo_resolver, @function
> +foo_resolver:
> + ret
> + .size foo_resolver, .-foo_resolver
> +
> + # The ifunc `foo` is called by the ifunc-caller.
> + .globl foo
> + .type foo, %gnu_indirect_function
> + .set foo, foo_resolver
> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> index 2c008d4..b82e092 100644
> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> @@ -19,6 +19,47 @@
> # MA 02110-1301, USA.
> #
>
> +# target: rv32 or rv64.
> +# output: Which output you want? (exe, pie, .so)
> +proc run_dump_test_ifunc { name target output} {
> + set asflags ""
> + set ldflags "-z nocombreloc"
> +
> + switch -- $output {
> + exe {
> + set ext "exe"
> + }
> + pie {
> + set ext "pie"
> + set ldflags "$ldflags -pie"
> + }
> + pic {
> + set ext "so"
> + set ldflags "$ldflags -shared"
> + }
> + }
> +
> + switch -- $target {
> + rv32 {
> + set asflags "$asflags -march=rv32i -mabi=ilp32"
> + set ldflags "$ldflags -melf32lriscv"
> + }
> + rv64 {
> + set asflags "$asflags -march=rv64i -mabi=lp64 -defsym __64_bit__=1"
> + set ldflags "$ldflags -melf64lriscv"
> + }
> + }
> +
> + run_ld_link_tests [list \
> + [list "$name ($target-$output)" \
> + "$ldflags" "" \
> + "$asflags" \
> + [list "$name.s"] \
> + [concat [list "readelf -rW $name-$output.rd"] \
> + [list "objdump -dw $name.d"]] \
> + "$name-$target.$ext"]]
> +}
> +
> if [istarget "riscv*-*-*"] {
> run_dump_test "call-relax"
> run_dump_test "c-lui"
> @@ -88,4 +129,74 @@ if [istarget "riscv*-*-*"] {
> {} "lib-nopic-01a.so" }
> }
> run_dump_test "lib-nopic-01b"
> +
> + # IFUNC testcases.
> + # Check IFUNC by single type relocs.
> + run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
> + run_dump_test_ifunc "ifunc-reloc-call-01" rv32 pie
> + run_dump_test_ifunc "ifunc-reloc-call-01" rv32 pic
> + run_dump_test_ifunc "ifunc-reloc-call-02" rv32 exe
> + run_dump_test_ifunc "ifunc-reloc-call-02" rv32 pie
> + run_dump_test_ifunc "ifunc-reloc-call-02" rv32 pic
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 exe
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 pie
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv32 pic
> + run_dump_test_ifunc "ifunc-reloc-data" rv32 exe
> + run_dump_test_ifunc "ifunc-reloc-data" rv32 pie
> + run_dump_test_ifunc "ifunc-reloc-data" rv32 pic
> + run_dump_test_ifunc "ifunc-reloc-got" rv32 exe
> + run_dump_test_ifunc "ifunc-reloc-got" rv32 pie
> + run_dump_test_ifunc "ifunc-reloc-got" rv32 pic
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 exe
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 pie
> + run_dump_test_ifunc "ifunc-reloc-pcrel" rv64 pic
> + run_dump_test_ifunc "ifunc-reloc-data" rv64 exe
> + run_dump_test_ifunc "ifunc-reloc-data" rv64 pie
> + run_dump_test_ifunc "ifunc-reloc-data" rv64 pic
> + run_dump_test_ifunc "ifunc-reloc-got" rv64 exe
> + run_dump_test_ifunc "ifunc-reloc-got" rv64 pie
> + run_dump_test_ifunc "ifunc-reloc-got" rv64 pic
> + # Check the IFUNC PLT and non-PLT relocs.
> + run_dump_test_ifunc "ifunc-nonplt" rv32 exe
> + run_dump_test_ifunc "ifunc-nonplt" rv32 pie
> + run_dump_test_ifunc "ifunc-nonplt" rv32 pic
> + run_dump_test_ifunc "ifunc-plt-01" rv32 exe
> + run_dump_test_ifunc "ifunc-plt-01" rv32 pie
> + run_dump_test_ifunc "ifunc-plt-01" rv32 pic
> + run_dump_test_ifunc "ifunc-plt-02" rv32 exe
> + run_dump_test_ifunc "ifunc-plt-02" rv32 pie
> + run_dump_test_ifunc "ifunc-plt-02" rv32 pic
> + run_dump_test_ifunc "ifunc-nonplt" rv64 exe
> + run_dump_test_ifunc "ifunc-nonplt" rv64 pie
> + run_dump_test_ifunc "ifunc-nonplt" rv64 pic
> + run_dump_test_ifunc "ifunc-plt-01" rv64 exe
> + run_dump_test_ifunc "ifunc-plt-01" rv64 pie
> + run_dump_test_ifunc "ifunc-plt-01" rv64 pic
> + 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
> +
> + # Setup shared libraries.
> + run_ld_link_tests {
> + { "Build shared library for IFUNC non-PLT caller"
> + "-shared" "" "" {ifunc-seperate-caller-nonplt.s}
> + {} "ifunc-seperate-caller.so" }
> + { "Build shared library for IFUNC PLT caller"
> + "-shared" "" "" {ifunc-seperate-caller-plt.s}
> + {} "ifunc-seperate-caller.so" }
> + { "Build shared library for IFUNC resolver"
> + "-shared" "" "" {ifunc-seperate-resolver.s}
> + {} "ifunc-seperate-resolver.so" }
> + }
> + # The IFUNC resolver and caller are in the seperate modules.
> + # If IFUNC resolver and caller are linked to the same module,
> + # then the result are the same as the run_dump_test_ifunc.
> + run_dump_test "ifunc-seperate-nonplt-exe"
> + run_dump_test "ifunc-seperate-nonplt-pie"
> + run_dump_test "ifunc-seperate-nonplt-pic"
> + run_dump_test "ifunc-seperate-plt-exe"
> + run_dump_test "ifunc-seperate-plt-pie"
> + run_dump_test "ifunc-seperate-plt-pic"
> + run_dump_test "ifunc-seperate-pcrel-pie"
> + run_dump_test "ifunc-seperate-pcrel-pic"
> }
> --
> 2.7.4
>
More information about the Binutils
mailing list