[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