[PATCH] RISC-V: Support GNU indirect functions.
Fangrui Song
i@maskray.me
Wed Jul 8 07:22:22 GMT 2020
I think I know ifunc and its implementation in LLD quite well
(https://reviews.llvm.org/D74022 ). However, I know little about GNU ld
and its terminology, so please bear with me.
On 2020-07-07, Nelson Chu wrote:
>For now, the following relocations are supported for IFUNC in linker,
>
>* R_RISCV_32 or R_RISCV_64
>Store the IFUNC symbol into the data section. Consider the ifunc-10.s
>or others in the ld testsuite.
>
>* R_RISCV_HI20 and R_RISCV_LO12_I/S
>The LUI + ADDI/LW/SW patterns. The absolute access relocation. Originally,
>I thought we didn't need to care about them, until I noticed that the
>ld test suites "Build pr23169a" and "Build pr23169d" needed them. The
>test suites are in the ld/testsuite/ld-ifunc/ and need compiler
>support. I think the medlow model without -fPIC compiler option and
>-shared linker option will possibly generate them.
>
>* R_RISCV_CALL or R_RISCV_CALL_PLT
>I don't think the RISC-V compiler will generate R_RISCV_JAL directly
>to jump to an IFUNC. Besides, I disable the relaxations for the
>relocation referenced to IFUNC, so just handling the R_RISCV_CALL and
>R_RISCV_CALL_PLT should be enough. We also need to allocate the PLT
>entry for the R_RISCV_CALL if it is referenced to IFUNC symbol.
>
>For now, GNU GCC and Binutils handle the R_RISCV_CALL and R_RISCV_CALL_PLT
>separately. But they can (should) be handled identically, since RISC-V lld
>had made the same improvement. And so had GNU AARCH64, they has only
>R_AARCH64_CALL26 for calls. It will affect the current IFUNC implementation
>in this patch. Therefore, I prefer to improve both of them in the future
>patches, if everyone is OK.
>
>* 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.
>
>* R_RISCV_GOT_HI20 and R_RISCV_PCREL_LO12_I/S
>LA pattern with global PIC ifunc symbol. Also check if it is possible to
>generate the PLT entry for IFUNC GOT reference. This saves the PLT spaces,
>and also reduces the overload of glibc.
>
>Besides, consider the two commits,
>
>1. cebd6b8ac1c5a2a847a50e3efe932ff2d0867b3e
>IFUNC: Update IFUNC resolver check with DT_TEXTREL.
>
>2. 3084d7a27b8e4d13f0fdd0fac62ffadc9c2223b5
>ELF: Add _bfd_elf_add_dynamic_tags
>
>These two commits will warn users that they should recompile their code
>with -fPIC or -fPIE, otherwise the GNU indirect functions with DT_TEXTREL
>may result in a segfault at runtime. R_RISCV_HI20 and R_RISCV_32/64 should
>be fine here, since we don't allow the former when generating the shared
>library or PIE executable. And the later are used in the data section rather
>than the code for now. But R_RISCV_CALL and R_RISCV_PCREL_HI20 may cause the
>warning. Consider the ifunc-2 testsuite in the ld/testsuite/ld-riscv-elf/.
>For the ifunc-2, the dynamic relocation, which cause the TEXTREL, are all
>R_RISCV_NONE and do nothing in the glibc or other dynamic loaders.
>I believe this can be resolved by changing some checking rules in the
>riscv_elf_check_relocs.
>
> 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
> used by 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 relocation
> reference to IFUNC symbol.
> (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 testcases for riscv.
> * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add ifunc testcases.
> These testcases are ported from testsuite/ld-ifunc.
> * testsuite/ld-riscv-elf/ifunc-1-local.d: New testcase.
> * testsuite/ld-riscv-elf/ifunc-1-local.map: Likewise.
> * testsuite/ld-riscv-elf/ifunc-1-local.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-1.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-1.map: Likewise.
> * testsuite/ld-riscv-elf/ifunc-1.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-2-local.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-2-local.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-2.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-2.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-3a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-3b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-3.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-4-local.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-4-local.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-4.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-4.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5a-local.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5b-local.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5r-local.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5-local.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-5.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-6a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-6b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-6.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-7a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-7b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-7.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-8.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-8a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-8b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-9.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-9.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-10.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-10.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-11a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-11b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-11.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-12.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-12.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-13.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-13a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-13b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14c.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14d.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14e.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14f.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-14c.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-15.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-15.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-16-now.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-16.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-16.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-17a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-17b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-17a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-17b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-18a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-18b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-18a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-18b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-19a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-19b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-19a.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-19b.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-20.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-20.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-21.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-21.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-22.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-22.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-23a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-23b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-23c.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-23.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-24a.d: Likewise
> * testsuite/ld-riscv-elf/ifunc-24b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-24.s: Likewise.
> * testsuite/ld-riscv-elf/ifunc-25a.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-25b.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-25c.d: Likewise.
> * testsuite/ld-riscv-elf/ifunc-25.s: Likewise.
>---
> bfd/configure | 4 +-
> bfd/configure.ac | 4 +-
> bfd/elfnn-riscv.c | 715 ++++++++++++++++++++++++++--
> 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-1-local.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-1-local.map | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-1-local.s | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-1.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-1.map | 3 +
> ld/testsuite/ld-riscv-elf/ifunc-1.s | 16 +
> ld/testsuite/ld-riscv-elf/ifunc-10.d | 4 +
> ld/testsuite/ld-riscv-elf/ifunc-10.s | 43 ++
> ld/testsuite/ld-riscv-elf/ifunc-11.s | 44 ++
> ld/testsuite/ld-riscv-elf/ifunc-11a.d | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-11b.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-12.d | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-12.s | 42 ++
> ld/testsuite/ld-riscv-elf/ifunc-13.d | 9 +
> ld/testsuite/ld-riscv-elf/ifunc-13a.s | 12 +
> ld/testsuite/ld-riscv-elf/ifunc-13b.s | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-14a.d | 10 +
> ld/testsuite/ld-riscv-elf/ifunc-14a.s | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-14b.d | 10 +
> ld/testsuite/ld-riscv-elf/ifunc-14b.s | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-14c.d | 10 +
> ld/testsuite/ld-riscv-elf/ifunc-14c.s | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-14d.d | 10 +
> ld/testsuite/ld-riscv-elf/ifunc-14e.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-14f.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-15.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-15.s | 16 +
> ld/testsuite/ld-riscv-elf/ifunc-16-now.d | 8 +
> ld/testsuite/ld-riscv-elf/ifunc-16.d | 8 +
> ld/testsuite/ld-riscv-elf/ifunc-16.s | 17 +
> ld/testsuite/ld-riscv-elf/ifunc-17a.d | 8 +
> ld/testsuite/ld-riscv-elf/ifunc-17a.s | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-17b.d | 8 +
> ld/testsuite/ld-riscv-elf/ifunc-17b.s | 6 +
> ld/testsuite/ld-riscv-elf/ifunc-18a.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-18a.s | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-18b.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-18b.s | 15 +
> ld/testsuite/ld-riscv-elf/ifunc-19a.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-19a.s | 5 +
> ld/testsuite/ld-riscv-elf/ifunc-19b.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-19b.s | 15 +
> ld/testsuite/ld-riscv-elf/ifunc-2-local.d | 12 +
> ld/testsuite/ld-riscv-elf/ifunc-2-local.s | 16 +
> ld/testsuite/ld-riscv-elf/ifunc-2.d | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-2.s | 19 +
> ld/testsuite/ld-riscv-elf/ifunc-20.d | 12 +
> ld/testsuite/ld-riscv-elf/ifunc-20.s | 16 +
> ld/testsuite/ld-riscv-elf/ifunc-21.d | 20 +
> ld/testsuite/ld-riscv-elf/ifunc-21.s | 31 ++
> ld/testsuite/ld-riscv-elf/ifunc-22.d | 20 +
> ld/testsuite/ld-riscv-elf/ifunc-22.s | 32 ++
> ld/testsuite/ld-riscv-elf/ifunc-23.s | 12 +
> ld/testsuite/ld-riscv-elf/ifunc-23a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-23b.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-23c.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-24.s | 13 +
> ld/testsuite/ld-riscv-elf/ifunc-24a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-24b.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-25.s | 14 +
> ld/testsuite/ld-riscv-elf/ifunc-25a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-25b.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-25c.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-3.s | 16 +
> ld/testsuite/ld-riscv-elf/ifunc-3a.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-3b.d | 8 +
> ld/testsuite/ld-riscv-elf/ifunc-4-local.d | 6 +
> ld/testsuite/ld-riscv-elf/ifunc-4-local.s | 20 +
> ld/testsuite/ld-riscv-elf/ifunc-4.d | 6 +
> ld/testsuite/ld-riscv-elf/ifunc-4.s | 21 +
> ld/testsuite/ld-riscv-elf/ifunc-5-local.s | 24 +
> ld/testsuite/ld-riscv-elf/ifunc-5.s | 25 +
> ld/testsuite/ld-riscv-elf/ifunc-5a-local.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-5a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-5b-local.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-5b.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-5r-local.d | 10 +
> ld/testsuite/ld-riscv-elf/ifunc-6.s | 26 +
> ld/testsuite/ld-riscv-elf/ifunc-6a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-6b.d | 11 +
> ld/testsuite/ld-riscv-elf/ifunc-7.s | 28 ++
> ld/testsuite/ld-riscv-elf/ifunc-7a.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-7b.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-8.d | 9 +
> ld/testsuite/ld-riscv-elf/ifunc-8a.s | 18 +
> ld/testsuite/ld-riscv-elf/ifunc-8b.s | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-9.d | 7 +
> ld/testsuite/ld-riscv-elf/ifunc-9.s | 24 +
> ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 201 ++++++++
> 96 files changed, 2017 insertions(+), 51 deletions(-)
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1-local.map
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1-local.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1.map
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-1.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-10.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-10.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-11.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-11a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-11b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-12.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-12.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-13.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-13a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-13b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14c.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14c.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14d.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14e.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-14f.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-15.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-15.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-16-now.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-16.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-16.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-17a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-17a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-17b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-17b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-18a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-18a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-18b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-18b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-19a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-19a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-19b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-19b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-2-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-2-local.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-2.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-2.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-20.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-20.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-21.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-21.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-22.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-22.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-23.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-23a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-23b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-23c.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-24.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-24a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-24b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-25.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-25a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-25b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-25c.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-3.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-3a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-3b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-4-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-4-local.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-4.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-4.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5-local.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5a-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5b-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-5r-local.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-6.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-6a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-6b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-7.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-7a.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-7b.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-8.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-8a.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-8b.s
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-9.d
> create mode 100644 ld/testsuite/ld-riscv-elf/ifunc-9.s
The test naming is really terrible. It is difficult to understand the
purpose of individual files. Can they have more descriptive names?
ifunc-1.s and ifunc-3.s are identical except a visibility setting.
Can the tests be somehow combined? For example,
echo '.hidden foo' > a.s and then concatenate two assembly files
>diff --git a/bfd/configure b/bfd/configure
>index 47fd457..aa647dc 100755
>--- a/bfd/configure
>+++ b/bfd/configure
>@@ -14889,8 +14889,8 @@ do
> powerpc_pei_le_vec) tb="$tb pei-ppc.lo peigen.lo $coff" ;;
> 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 8e86f83..4989b25 100644
>--- a/bfd/configure.ac
>+++ b/bfd/configure.ac
>@@ -625,8 +625,8 @@ do
> powerpc_pei_le_vec) tb="$tb pei-ppc.lo peigen.lo $coff" ;;
> 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 a5fa415..ca0dd11 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)
>@@ -118,6 +119,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;
> };
>
>
>@@ -155,17 +160,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
>@@ -267,6 +268,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 *
>@@ -288,6 +369,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;
> }
>
>@@ -479,6 +574,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"),
>@@ -528,7 +626,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->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];
>@@ -537,6 +660,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:
The list has appears more than once with variance, I think a generic
relocation kind may help.
>+ /* 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:
>@@ -573,17 +722,25 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
> }
> break;
>
>- case R_RISCV_CALL:
> 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. */
> if (bfd_link_pic (info))
> break;
> goto static_reloc;
>
>+ case R_RISCV_CALL:
>+ case R_RISCV_PCREL_HI20:
>+ /* In shared libraries, these relocs are known to bind locally,
>+ except IFUNC symbol. */
>+ if (bfd_link_pic (info)
>+ && (h == NULL
>+ || h->type != STT_GNU_IFUNC))
>+ break;
>+ goto static_reloc;
>+
> case R_RISCV_TPREL_HI20:
> if (!bfd_link_executable (info))
> return bad_static_reloc (abfd, r_type, h);
>@@ -604,15 +761,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_executable (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,7 +800,10 @@ 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. */
> reloc_howto_type * r = riscv_elf_rtype_to_howto (abfd, r_type);
>
> if ((bfd_link_pic (info)
>@@ -649,7 +817,11 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *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 +958,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 +1074,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 +1267,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 +1406,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 +1449,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 +1883,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 +1901,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 +1926,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 +1967,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;
>+
>+ 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 +2492,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 +2522,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;
>@@ -2217,6 +2698,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);
>@@ -2300,23 +2782,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,
>@@ -2328,16 +2845,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. */
>+ 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)
>@@ -2370,13 +2908,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;
>@@ -2424,6 +3022,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
>@@ -2550,6 +3160,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;
> }
>
>@@ -4046,6 +4661,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
>@@ -4076,6 +4697,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 1570f1d..ce300e4 100644
>--- a/bfd/elfxx-riscv.c
>+++ b/bfd/elfxx-riscv.c
>@@ -854,6 +854,21 @@ static reloc_howto_type howto_table[] =
> 0, /* src_mask */
> MINUS_ONE, /* 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 */
On 64-bit this should be 64.
>+ 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 */
>+ MINUS_ONE, /* 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 08cc878..020b48e 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-*-*]
>@@ -730,7 +729,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-1-local.d b/ld/testsuite/ld-riscv-elf/ifunc-1-local.d
>new file mode 100644
>index 0000000..15faecc
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1-local.d
>@@ -0,0 +1,11 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv -z norelro
>+#objdump: -dw
>+#map: ifunc-1-local.map
>+
>+#...
>+0+[0-9a-f]+ <__GI_foo>:
>+#...
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-1-local.map b/ld/testsuite/ld-riscv-elf/ifunc-1-local.map
>new file mode 100644
>index 0000000..95313a5
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1-local.map
>@@ -0,0 +1,3 @@
>+#...
>+Local IFUNC function `__GI_foo' in tmpdir/ifunc-1-local.o
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-1-local.s b/ld/testsuite/ld-riscv-elf/ifunc-1-local.s
>new file mode 100644
>index 0000000..cdfe37a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1-local.s
>@@ -0,0 +1,13 @@
>+ .type foo, %gnu_indirect_function
>+ .set __GI_foo, foo
>+ .text
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+.globl bar
>+ .type bar, @function
>+bar:
>+ call __GI_foo@plt
>+ ret
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-1.d b/ld/testsuite/ld-riscv-elf/ifunc-1.d
>new file mode 100644
>index 0000000..ee495f0
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1.d
>@@ -0,0 +1,11 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv
>+#objdump: -dw
>+#map: ifunc-1.map
>+
>+#...
>+0+[0-9a-f]+ <foo>:
>+#...
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-1.map b/ld/testsuite/ld-riscv-elf/ifunc-1.map
>new file mode 100644
>index 0000000..c5077d9
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1.map
>@@ -0,0 +1,3 @@
>+#...
>+Local IFUNC function `__GI_foo' in tmpdir/ifunc-1.o
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-1.s b/ld/testsuite/ld-riscv-elf/ifunc-1.s
>new file mode 100644
>index 0000000..40922c2
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-1.s
>@@ -0,0 +1,16 @@
>+ .type foo, %gnu_indirect_function
>+ .global __GI_foo
>+ .hidden __GI_foo
>+ .set __GI_foo, foo
>+ .text
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+.globl bar
>+ .type bar, @function
>+bar:
>+ call __GI_foo@plt
>+ ret
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-10.d b/ld/testsuite/ld-riscv-elf/ifunc-10.d
>new file mode 100644
>index 0000000..7428057
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-10.d
>@@ -0,0 +1,4 @@
>+#ld: -e bar --gc-sections
>+#readelf: -r --wide
>+
>+There are no relocations in this file.
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-10.s b/ld/testsuite/ld-riscv-elf/ifunc-10.s
>new file mode 100644
>index 0000000..34ba4e5
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-10.s
>@@ -0,0 +1,43 @@
>+ .section .text.foo,"ax",@progbits
>+ .type foo, @function
>+foo:
>+ .global foo
>+.L1:
>+ auipc x1, %got_pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+.L2:
>+ auipc x1, %pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L2) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ call ifunc@plt
>+ call ifunc
>+.L3:
>+ auipc x1, %pcrel_hi (xxx)
>+ addi x1, x1, %pcrel_lo (.L3)
>+ ret
>+
>+ .section .text.bar,"ax",@progbits
>+ .type bar, @function
>+bar:
>+ .global bar
>+ ret
>+
>+ .section .text.ifunc,"ax",@progbits
>+ .type ifunc, @gnu_indirect_function
>+ifunc:
>+ ret
>+
>+ .section .data.foo,"aw",@progbits
>+xxx:
>+.ifdef __64_bit__
>+ .quad ifunc
>+.else
>+ .long ifunc
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-11.s b/ld/testsuite/ld-riscv-elf/ifunc-11.s
>new file mode 100644
>index 0000000..aeba5c2
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-11.s
>@@ -0,0 +1,44 @@
>+ .section .text.foo,"ax",@progbits
>+ .type foo, @function
>+foo:
>+ .global foo
>+.L1:
>+ auipc x1, %got_pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+.L2:
>+ auipc x1, %pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L2) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ call ifunc@plt
>+ call ifunc
>+.L3:
>+ auipc x1, %pcrel_hi (xxx)
>+ addi x1, x1, %pcrel_lo (.L3)
>+ ret
>+
>+ .section .text.bar,"ax",@progbits
>+ .type bar, @function
>+bar:
>+ .global bar
>+ ret
>+
>+ .section .text.ifunc,"ax",@progbits
>+ .type ifunc, @gnu_indirect_function
>+ .global ifunc
>+ifunc:
>+ ret
>+
>+ .section .data.foo,"aw",@progbits
>+xxx:
>+.ifdef __64_bit__
>+ .quad ifunc
>+.else
>+ .long ifunc
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-11a.d b/ld/testsuite/ld-riscv-elf/ifunc-11a.d
>new file mode 100644
>index 0000000..b72ea90
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-11a.d
>@@ -0,0 +1,5 @@
>+#source: ifunc-11.s
>+#ld: -e bar --gc-sections
>+#readelf: -r --wide
>+
>+There are no relocations in this file.
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-11b.d b/ld/testsuite/ld-riscv-elf/ifunc-11b.d
>new file mode 100644
>index 0000000..e41e61c
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-11b.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-11.s
>+#ld: -e bar
>+#readelf: -r --wide
>+
>+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-12.d b/ld/testsuite/ld-riscv-elf/ifunc-12.d
>new file mode 100644
>index 0000000..7d01e76
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-12.d
>@@ -0,0 +1,5 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared -e bar --gc-sections
>+#readelf: -r --wide
>+
>+There are no relocations in this file.
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-12.s b/ld/testsuite/ld-riscv-elf/ifunc-12.s
>new file mode 100644
>index 0000000..e341155
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-12.s
>@@ -0,0 +1,42 @@
>+ .section .text.foo,"ax",@progbits
>+ .type foo, @function
>+foo:
>+.L1:
>+ auipc x1, %got_pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+.L2:
>+ auipc x1, %pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L2) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ call ifunc@plt
>+ call ifunc
>+.L3:
>+ auipc x1, %pcrel_hi (xxx)
>+ addi x1, x1, %pcrel_lo (.L3)
>+ ret
>+
>+ .section .text.bar,"ax",@progbits
>+ .type bar, @function
>+bar:
>+ .global bar
>+ ret
>+
>+ .section .text.ifunc,"ax",@progbits
>+ .type ifunc, @gnu_indirect_function
>+ifunc:
>+ ret
>+
>+ .section .data.foo,"aw",@progbits
>+xxx:
>+.ifdef __64_bit__
>+ .quad ifunc
>+.else
>+ .long ifunc
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-13.d b/ld/testsuite/ld-riscv-elf/ifunc-13.d
>new file mode 100644
>index 0000000..475bc7b
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-13.d
>@@ -0,0 +1,9 @@
>+#source: ifunc-13a.s
>+#source: ifunc-13b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+Relocation section '.rela.ifunc' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+ifunc\(\)[ ]+ifunc \+ 0
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-13a.s b/ld/testsuite/ld-riscv-elf/ifunc-13a.s
>new file mode 100644
>index 0000000..ae5ef75
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-13a.s
>@@ -0,0 +1,12 @@
>+ .text
>+ .type foo, @function
>+ .global foo
>+foo:
>+.L1:
>+ auipc x1, %pcrel_hi (xxx)
>+ addi x1, x1, %pcrel_lo (.L1)
>+ ret
>+
>+ .data
>+xxx:
>+ .quad ifunc
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-13b.s b/ld/testsuite/ld-riscv-elf/ifunc-13b.s
>new file mode 100644
>index 0000000..3560394
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-13b.s
>@@ -0,0 +1,5 @@
>+ .text
>+ .type ifunc, @gnu_indirect_function
>+ .globl ifunc
>+ifunc:
>+ ret
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14a.d b/ld/testsuite/ld-riscv-elf/ifunc-14a.d
>new file mode 100644
>index 0000000..959b495
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14a.d
>@@ -0,0 +1,10 @@
>+#source: ifunc-14a.s
>+#source: ifunc-14b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -d
>+
>+#failif
>+#...
>+.*\(TEXTREL\).*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14a.s b/ld/testsuite/ld-riscv-elf/ifunc-14a.s
>new file mode 100644
>index 0000000..876988c
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14a.s
>@@ -0,0 +1,7 @@
>+ .text
>+ .globl bar
>+ .type bar, @function
>+bar:
>+ call foo@plt
>+ .size bar, .-bar
>+ .hidden foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14b.d b/ld/testsuite/ld-riscv-elf/ifunc-14b.d
>new file mode 100644
>index 0000000..ac4db0b
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14b.d
>@@ -0,0 +1,10 @@
>+#source: ifunc-14b.s
>+#source: ifunc-14a.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -d
>+
>+#failif
>+#...
>+.*\(TEXTREL\).*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14b.s b/ld/testsuite/ld-riscv-elf/ifunc-14b.s
>new file mode 100644
>index 0000000..bac22eb
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14b.s
>@@ -0,0 +1,5 @@
>+ .type foo, %gnu_indirect_function
>+ .globl foo
>+foo:
>+ ret
>+ .size foo, .-foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14c.d b/ld/testsuite/ld-riscv-elf/ifunc-14c.d
>new file mode 100644
>index 0000000..df86f62
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14c.d
>@@ -0,0 +1,10 @@
>+#source: ifunc-14a.s
>+#source: ifunc-14b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+#failif
>+#...
>+.* +R_RISCV_NONE +.*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14c.s b/ld/testsuite/ld-riscv-elf/ifunc-14c.s
>new file mode 100644
>index 0000000..8cf89c3
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14c.s
>@@ -0,0 +1,7 @@
>+ .text
>+ .globl xxx
>+ .type xxx, @function
>+xxx:
>+ call foo@plt
>+ .size xxx, .-xxx
>+ .hidden foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14d.d b/ld/testsuite/ld-riscv-elf/ifunc-14d.d
>new file mode 100644
>index 0000000..b186471
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14d.d
>@@ -0,0 +1,10 @@
>+#source: ifunc-14b.s
>+#source: ifunc-14a.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+#failif
>+#...
>+.* +R_RISCV_NONE +.*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14e.d b/ld/testsuite/ld-riscv-elf/ifunc-14e.d
>new file mode 100644
>index 0000000..f365724
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14e.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-14a.s
>+#source: ifunc-14c.s
>+#source: ifunc-14b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+#failif
>+#...
>+.* +R_RISCV_NONE +.*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-14f.d b/ld/testsuite/ld-riscv-elf/ifunc-14f.d
>new file mode 100644
>index 0000000..4d78ca7
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-14f.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-14a.s
>+#source: ifunc-14b.s
>+#source: ifunc-14c.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+#failif
>+#...
>+.* +R_RISCV_NONE +.*
>+#...
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-15.d b/ld/testsuite/ld-riscv-elf/ifunc-15.d
>new file mode 100644
>index 0000000..41a5caa
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-15.d
>@@ -0,0 +1,7 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+Relocation section '.rela.got' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+ifunc\(\)[ ]+ifunc \+ 0
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-15.s b/ld/testsuite/ld-riscv-elf/ifunc-15.s
>new file mode 100644
>index 0000000..963c517
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-15.s
>@@ -0,0 +1,16 @@
>+ .text
>+ .type foo, @function
>+ .global foo
>+foo:
>+.L1:
>+ auipc x1, %got_pcrel_hi (ifunc)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ ret
>+ .type ifunc, @gnu_indirect_function
>+ .globl ifunc
>+ifunc:
>+ ret
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-16-now.d b/ld/testsuite/ld-riscv-elf/ifunc-16-now.d
>new file mode 100644
>index 0000000..3b2bb21
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-16-now.d
>@@ -0,0 +1,8 @@
>+#source: ifunc-16.s
>+#ld: -z now -shared
>+#readelf: -r --wide
>+
>+Relocation section '.rela.plt' at .*
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+0+[ ]+ifunc \+ 0
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-16.d b/ld/testsuite/ld-riscv-elf/ifunc-16.d
>new file mode 100644
>index 0000000..787eb72
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-16.d
>@@ -0,0 +1,8 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared
>+#readelf: -r --wide
>+
>+Relocation section '.rela.plt' at .*
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+0+[ ]+ifunc \+ 0
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-16.s b/ld/testsuite/ld-riscv-elf/ifunc-16.s
>new file mode 100644
>index 0000000..bb7817a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-16.s
>@@ -0,0 +1,17 @@
>+ .text
>+ .globl fct
>+ .type fct, @gnu_indirect_function
>+ .set fct,resolve
>+ .hidden int_fct
>+ .globl int_fct
>+ .set int_fct,fct
>+ .p2align 4,,15
>+ .type resolve, @function
>+resolve:
>+ call ifunc@plt
>+ .size resolve, .-resolve
>+ .globl g
>+ .type g, @function
>+g:
>+ call int_fct@plt
>+ .size g, .-g
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-17a.d b/ld/testsuite/ld-riscv-elf/ifunc-17a.d
>new file mode 100644
>index 0000000..30d9f64
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-17a.d
>@@ -0,0 +1,8 @@
>+#source: ifunc-17a.s
>+#source: ifunc-17b.s
>+#ld: -static
>+#readelf: -s --wide
>+
>+#...
>+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-17a.s b/ld/testsuite/ld-riscv-elf/ifunc-17a.s
>new file mode 100644
>index 0000000..e0bde49
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-17a.s
>@@ -0,0 +1,11 @@
>+ .globl main
>+ .globl start
>+ .globl _start
>+ .globl __start
>+ .text
>+main:
>+start:
>+_start:
>+__start:
>+ .byte 0
>+ .common foo,4,4
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-17b.d b/ld/testsuite/ld-riscv-elf/ifunc-17b.d
>new file mode 100644
>index 0000000..fc58527
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-17b.d
>@@ -0,0 +1,8 @@
>+#source: ifunc-17b.s
>+#source: ifunc-17a.s
>+#ld: -static
>+#readelf: -s --wide
>+
>+#...
>+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-17b.s b/ld/testsuite/ld-riscv-elf/ifunc-17b.s
>new file mode 100644
>index 0000000..66abe04
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-17b.s
>@@ -0,0 +1,6 @@
>+ .weak foo
>+ .type foo, %gnu_indirect_function
>+ .size foo,1
>+ .text
>+foo:
>+ .byte 1
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-18a.d b/ld/testsuite/ld-riscv-elf/ifunc-18a.d
>new file mode 100644
>index 0000000..d15eb74
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-18a.d
>@@ -0,0 +1,13 @@
>+#source: ifunc-18a.s
>+#source: ifunc-18b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-18a.s b/ld/testsuite/ld-riscv-elf/ifunc-18a.s
>new file mode 100644
>index 0000000..f68c151
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-18a.s
>@@ -0,0 +1,5 @@
>+ .section .data.rel,"aw",@progbits
>+ .globl foo_ptr
>+ .type foo_ptr, @object
>+foo_ptr:
>+ .dc.a foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-18b.d b/ld/testsuite/ld-riscv-elf/ifunc-18b.d
>new file mode 100644
>index 0000000..93513df
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-18b.d
>@@ -0,0 +1,13 @@
>+#source: ifunc-18b.s
>+#source: ifunc-18a.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-18b.s b/ld/testsuite/ld-riscv-elf/ifunc-18b.s
>new file mode 100644
>index 0000000..b136348
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-18b.s
>@@ -0,0 +1,15 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+ .hidden foo
>+ .globl foo
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .globl bar
>+bar:
>+ call foo1@plt
>+ ret
>+ .size bar, .-bar
>+ .hidden foo1
>+ .globl foo1
>+ foo1 = foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-19a.d b/ld/testsuite/ld-riscv-elf/ifunc-19a.d
>new file mode 100644
>index 0000000..bc7bab5
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-19a.d
>@@ -0,0 +1,13 @@
>+#source: ifunc-19a.s
>+#source: ifunc-19b.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-19a.s b/ld/testsuite/ld-riscv-elf/ifunc-19a.s
>new file mode 100644
>index 0000000..3a3d0cd
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-19a.s
>@@ -0,0 +1,5 @@
>+ .section .data.rel,"aw",@progbits
>+ .globl foo_ptrt
>+ .type foo_ptr, @object
>+foo_ptr:
>+ .dc.a foo1
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-19b.d b/ld/testsuite/ld-riscv-elf/ifunc-19b.d
>new file mode 100644
>index 0000000..e018c62
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-19b.d
>@@ -0,0 +1,13 @@
>+#source: ifunc-19b.s
>+#source: ifunc-19a.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-19b.s b/ld/testsuite/ld-riscv-elf/ifunc-19b.s
>new file mode 100644
>index 0000000..b136348
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-19b.s
>@@ -0,0 +1,15 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+ .hidden foo
>+ .globl foo
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .globl bar
>+bar:
>+ call foo1@plt
>+ ret
>+ .size bar, .-bar
>+ .hidden foo1
>+ .globl foo1
>+ foo1 = foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-2-local.d b/ld/testsuite/ld-riscv-elf/ifunc-2-local.d
>new file mode 100644
>index 0000000..da16a04
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-2-local.d
>@@ -0,0 +1,12 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv
>+#objdump: -dw
>+
>+#...
>+0+[0-9a-f]+ <__GI_foo>:
>+#...
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-2-local.s b/ld/testsuite/ld-riscv-elf/ifunc-2-local.s
>new file mode 100644
>index 0000000..f1df863
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-2-local.s
>@@ -0,0 +1,16 @@
>+ .type foo, %gnu_indirect_function
>+ .set __GI_foo, foo
>+ .text
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+.globl bar
>+ .type bar, @function
>+bar:
>+ call __GI_foo
>+.L1:
>+ auipc x1, %pcrel_hi (__GI_foo)
>+ addi x1, x1, %pcrel_lo (.L1)
>+ ret
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-2.d b/ld/testsuite/ld-riscv-elf/ifunc-2.d
>new file mode 100644
>index 0000000..49320bd
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-2.d
>@@ -0,0 +1,13 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv
>+#objdump: -dw
>+#warning: GNU indirect functions with DT_TEXTREL may result in a segfault at runtime; recompile with -fPIC
>+
>+#...
>+0+[0-9a-f]+ <foo>:
>+#...
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-2.s b/ld/testsuite/ld-riscv-elf/ifunc-2.s
>new file mode 100644
>index 0000000..3287880
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-2.s
>@@ -0,0 +1,19 @@
>+ .type foo, %gnu_indirect_function
>+ .global __GI_foo
>+ .hidden __GI_foo
>+ .set __GI_foo, foo
>+ .text
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+.globl bar
>+ .type bar, @function
>+bar:
>+ call __GI_foo
>+.L1:
>+ auipc x1, %pcrel_hi (__GI_foo)
>+ addi x1, x1, %pcrel_lo (.L1)
>+ ret
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-20.d b/ld/testsuite/ld-riscv-elf/ifunc-20.d
>new file mode 100644
>index 0000000..71461fb
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-20.d
>@@ -0,0 +1,12 @@
>+#source: ifunc-20.s
>+#target: [check_shared_lib_support]
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+Relocation section '.rela.ifunc' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+ifunc\(\)[ ]+ifunc \+ 0
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_JUMP_SLOT[ ]+ifunc\(\)[ ]+ifunc \+ 0
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-20.s b/ld/testsuite/ld-riscv-elf/ifunc-20.s
>new file mode 100644
>index 0000000..0e85fed
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-20.s
>@@ -0,0 +1,16 @@
>+ .section .data.rel,"aw",@progbits
>+ .globl ifunc_ptrt
>+ .type ifunc_ptr, @object
>+ifunc_ptr:
>+ .dc.a ifunc
>+ .text
>+ .type ifunc, @gnu_indirect_function
>+ .globl ifunc
>+ifunc:
>+ ret
>+ .size ifunc, .-ifunc
>+ .type bar, @function
>+ .globl bar
>+bar:
>+ call ifunc@plt
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-21.d b/ld/testsuite/ld-riscv-elf/ifunc-21.d
>new file mode 100644
>index 0000000..2f7509e
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-21.d
>@@ -0,0 +1,20 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
>+#objdump: -dw
>+
>+.*: +file format .*
>+
>+Disassembly of section .text:
>+
>+.* <__start>:
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+ra,0x200
>+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<_GLOBAL_OFFSET_TABLE_\+.*>
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+ra,0x200
>+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.*<_GLOBAL_OFFSET_TABLE_\+.*>
>+
>+.* <foo>:
>+.*:[ ]+00008067[ ]+ret
>+
>+.* <bar>:
>+.*:[ ]+00008067[ ]+ret
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-21.s b/ld/testsuite/ld-riscv-elf/ifunc-21.s
>new file mode 100644
>index 0000000..6b1b556
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-21.s
>@@ -0,0 +1,31 @@
>+ .text
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+.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 x1, %got_pcrel_hi (bar)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L2) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ .type foo, %gnu_indirect_function
>+foo:
>+ ret
>+ .type bar, %function
>+bar:
>+ ret
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-22.d b/ld/testsuite/ld-riscv-elf/ifunc-22.d
>new file mode 100644
>index 0000000..58352a1
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-22.d
>@@ -0,0 +1,20 @@
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
>+#objdump: -dw
>+
>+.*: +file format .*
>+
>+Disassembly of section .text:
>+
>+.* <__start>:
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+ra,0x200
>+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.* <foo\+.*>
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+ra,0x200
>+.*:[ ]+[0-9a-f]+[ ]+(lw|ld)[ ]+.* <_GLOBAL_OFFSET_TABLE_\+.*>
>+
>+.* <foo>:
>+.*:[ ]+00008067[ ]+ret
>+
>+.* <bar>:
>+.*:[ ]+00008067[ ]+ret
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-22.s b/ld/testsuite/ld-riscv-elf/ifunc-22.s
>new file mode 100644
>index 0000000..9e97d05
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-22.s
>@@ -0,0 +1,32 @@
>+ .text
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+.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 x1, %got_pcrel_hi (bar)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L2) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>+ .type foo, %gnu_indirect_function
>+ .globl foo
>+foo:
>+ ret
>+ .type bar, %function
>+bar:
>+ ret
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-23.s b/ld/testsuite/ld-riscv-elf/ifunc-23.s
>new file mode 100644
>index 0000000..00b60c5
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-23.s
>@@ -0,0 +1,12 @@
>+ .type foo,%gnu_indirect_function
>+foo:
>+ ret
>+ .globl _start
>+_start:
>+ ret
>+ .globl __start
>+__start:
>+ .global _main
>+_main:
>+ .data
>+ .dc.a foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-23a.d b/ld/testsuite/ld-riscv-elf/ifunc-23a.d
>new file mode 100644
>index 0000000..855b67a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-23a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-23.s
>+#ld:
>+#readelf: -r --wide
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-23b.d b/ld/testsuite/ld-riscv-elf/ifunc-23b.d
>new file mode 100644
>index 0000000..08009ac
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-23b.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-23.s
>+#ld: -pie
>+#readelf: -r --wide
>+
>+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-23c.d b/ld/testsuite/ld-riscv-elf/ifunc-23c.d
>new file mode 100644
>index 0000000..f32f0a3
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-23c.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-23.s
>+#ld: -shared
>+#readelf: -r --wide
>+
>+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-24.s b/ld/testsuite/ld-riscv-elf/ifunc-24.s
>new file mode 100644
>index 0000000..eb51312
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-24.s
>@@ -0,0 +1,13 @@
>+ .text
>+ .type foo,%gnu_indirect_function
>+foo:
>+ ret
>+ .globl _start
>+_start:
>+ call foo@plt
>+ .globl __start
>+__start:
>+ .global _main
>+_main:
>+ .data
>+ .dc.a foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-24a.d b/ld/testsuite/ld-riscv-elf/ifunc-24a.d
>new file mode 100644
>index 0000000..eef0a9d
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-24a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-24.s
>+#ld:
>+#readelf: -r --wide
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-24b.d b/ld/testsuite/ld-riscv-elf/ifunc-24b.d
>new file mode 100644
>index 0000000..9069c70
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-24b.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-24.s
>+#ld: -pie
>+#readelf: -r --wide
>+
>+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-25.s b/ld/testsuite/ld-riscv-elf/ifunc-25.s
>new file mode 100644
>index 0000000..fafc920
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-25.s
>@@ -0,0 +1,14 @@
>+ .text
>+ .globl foo
>+ .type foo,%gnu_indirect_function
>+foo:
>+ ret
>+ .globl _start
>+_start:
>+ call foo@plt
>+ .globl __start
>+__start:
>+ .global _main
>+_main:
>+ .data
>+ .dc.a foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-25a.d b/ld/testsuite/ld-riscv-elf/ifunc-25a.d
>new file mode 100644
>index 0000000..a3c8e96
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-25a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-25.s
>+#ld:
>+#readelf: -r --wide
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-25b.d b/ld/testsuite/ld-riscv-elf/ifunc-25b.d
>new file mode 100644
>index 0000000..c1940c6
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-25b.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-25.s
>+#ld: -pie
>+#readelf: -r --wide
>+
>+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-25c.d b/ld/testsuite/ld-riscv-elf/ifunc-25c.d
>new file mode 100644
>index 0000000..f4ca0a3
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-25c.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-25.s
>+#ld: -shared
>+#readelf: -r --wide
>+
>+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_(32|64)[ ]+foo\(\)[ ]+foo \+ 0
>+
>+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
>+[ ]+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-3.s b/ld/testsuite/ld-riscv-elf/ifunc-3.s
>new file mode 100644
>index 0000000..5b2ff25
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-3.s
>@@ -0,0 +1,16 @@
>+ .type foo, %gnu_indirect_function
>+ .global __GI_foo
>+ .protected __GI_foo
>+ .set __GI_foo, foo
>+ .text
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+.globl bar
>+ .type bar, @function
>+bar:
>+ call __GI_foo@plt
>+ ret
>+ .size bar, .-bar
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-3a.d b/ld/testsuite/ld-riscv-elf/ifunc-3a.d
>new file mode 100644
>index 0000000..7465cf9
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-3a.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-3.s
>+#target: [check_shared_lib_support]
>+#ld: -shared --hash-style=sysv
>+#objdump: -dw
>+
>+#...
>+0+[0-9a-f]+ <__GI_foo>:
>+#...
>+.*:[ ]+[0-9a-f]+[ ]+auipc[ ]+.*
>+.*:[ ]+[0-9a-f]+[ ]+jalr[ ]+.*<\*ABS\*\+0x[0-9a-f]+@plt>
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-3b.d b/ld/testsuite/ld-riscv-elf/ifunc-3b.d
>new file mode 100644
>index 0000000..1d27913
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-3b.d
>@@ -0,0 +1,8 @@
>+#source: ifunc-3.s
>+#target: [check_shared_lib_support]
>+#ld: -shared
>+#readelf: -r --wide
>+
>+#...
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-4-local.d b/ld/testsuite/ld-riscv-elf/ifunc-4-local.d
>new file mode 100644
>index 0000000..23772b9
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-4-local.d
>@@ -0,0 +1,6 @@
>+#ld:
>+#readelf: -r --wide
>+
>+#...
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-4-local.s b/ld/testsuite/ld-riscv-elf/ifunc-4-local.s
>new file mode 100644
>index 0000000..76ba885
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-4-local.s
>@@ -0,0 +1,20 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ .global _main
>+_main:
>+ call foo
>+ #.dword foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-4.d b/ld/testsuite/ld-riscv-elf/ifunc-4.d
>new file mode 100644
>index 0000000..23772b9
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-4.d
>@@ -0,0 +1,6 @@
>+#ld:
>+#readelf: -r --wide
>+
>+#...
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_IRELATIVE[ ]+[0-9a-f]*
>+#pass
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-4.s b/ld/testsuite/ld-riscv-elf/ifunc-4.s
>new file mode 100644
>index 0000000..0ff6d1a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-4.s
>@@ -0,0 +1,21 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+.global foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ .global _main
>+_main:
>+ call foo
>+ #.dword foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-5-local.s b/ld/testsuite/ld-riscv-elf/ifunc-5-local.s
>new file mode 100644
>index 0000000..c48ceaf
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5-local.s
>@@ -0,0 +1,24 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ call foo@plt
>+.L1:
>+ auipc x1, %got_pcrel_hi (foo)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-5.s b/ld/testsuite/ld-riscv-elf/ifunc-5.s
>new file mode 100644
>index 0000000..7fd4ae7
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5.s
>@@ -0,0 +1,25 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ call foo@plt
>+.L1:
>+ auipc x1, %got_pcrel_hi (foo)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-5a-local.d b/ld/testsuite/ld-riscv-elf/ifunc-5a-local.d
>new file mode 100644
>index 0000000..2216bb2
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5a-local.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-5-local.s
>+#ld:
>+#readelf: -r --wide
>+
>+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-5a.d b/ld/testsuite/ld-riscv-elf/ifunc-5a.d
>new file mode 100644
>index 0000000..bdc1f50
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-5.s
>+#ld:
>+#readelf: -r --wide
>+
>+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-5b-local.d b/ld/testsuite/ld-riscv-elf/ifunc-5b-local.d
>new file mode 100644
>index 0000000..aa3e00a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5b-local.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-5-local.s
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-5b.d b/ld/testsuite/ld-riscv-elf/ifunc-5b.d
>new file mode 100644
>index 0000000..d8fb901
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5b.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-5.s
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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-5r-local.d b/ld/testsuite/ld-riscv-elf/ifunc-5r-local.d
>new file mode 100644
>index 0000000..223ac64
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-5r-local.d
>@@ -0,0 +1,10 @@
>+#source: ifunc-5-local.s
>+#as: --mno-relax
>+#ld: -r
>+#readelf: -r --wide
>+
>+Relocation section '.rela.text' at .*
>+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_CALL_PLT[ ]+foo\(\)[ ]+foo \+ 0
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_GOT_HI20[ ]+foo\(\)[ ]+foo \+ 0
>+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_PCREL_LO12_I[ ]+[0-9a-f]+[ ]+.L1 \+ 0
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-6.s b/ld/testsuite/ld-riscv-elf/ifunc-6.s
>new file mode 100644
>index 0000000..5bf3f66
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-6.s
>@@ -0,0 +1,26 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .protected foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ call foo@plt
>+.L1:
>+ auipc x1, %got_pcrel_hi (foo)
>+.ifdef __64_bits__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-6a.d b/ld/testsuite/ld-riscv-elf/ifunc-6a.d
>new file mode 100644
>index 0000000..24af75e
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-6a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-6.s
>+#ld:
>+#readelf: -r --wide
>+
>+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-6b.d b/ld/testsuite/ld-riscv-elf/ifunc-6b.d
>new file mode 100644
>index 0000000..360901a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-6b.d
>@@ -0,0 +1,11 @@
>+#source: ifunc-6.s
>+#ld: -shared -z nocombreloc
>+#readelf: -r --wide
>+
>+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_IRELATIVE[ ]+[0-9a-f]*
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-7.s b/ld/testsuite/ld-riscv-elf/ifunc-7.s
>new file mode 100644
>index 0000000..2348f39
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-7.s
>@@ -0,0 +1,28 @@
>+ .text
>+ #nop
>+ #nop
>+ .type foo, %gnu_indirect_function
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .hidden foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+ call foo@plt
>+.L1:
>+ auipc x1, %got_pcrel_hi (foo)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-7a.d b/ld/testsuite/ld-riscv-elf/ifunc-7a.d
>new file mode 100644
>index 0000000..69d43fc
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-7a.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-7.s
>+#ld:
>+#readelf: -r --wide
>+
>+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-7b.d b/ld/testsuite/ld-riscv-elf/ifunc-7b.d
>new file mode 100644
>index 0000000..c324105
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-7b.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-7.s
>+#ld: -shared
>+#readelf: -r --wide
>+
>+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-8.d b/ld/testsuite/ld-riscv-elf/ifunc-8.d
>new file mode 100644
>index 0000000..18c0ee2
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-8.d
>@@ -0,0 +1,9 @@
>+#source: ifunc-8a.s
>+#source: ifunc-8b.s
>+#as:
>+#ld:
>+#readelf: -r --wide
>+
>+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-8a.s b/ld/testsuite/ld-riscv-elf/ifunc-8a.s
>new file mode 100644
>index 0000000..9518b3a
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-8a.s
>@@ -0,0 +1,18 @@
>+ .text
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+.L1:
>+ auipc x1, %got_pcrel_hi (foo)
>+.ifdef __64_bit__
>+ ld x1, %pcrel_lo (.L1) (x1)
>+.else
>+ lw x1, %pcrel_lo (.L1) (x1)
>+.endif
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-8b.s b/ld/testsuite/ld-riscv-elf/ifunc-8b.s
>new file mode 100644
>index 0000000..1f108f8
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-8b.s
>@@ -0,0 +1,7 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>diff --git a/ld/testsuite/ld-riscv-elf/ifunc-9.d b/ld/testsuite/ld-riscv-elf/ifunc-9.d
>new file mode 100644
>index 0000000..c140818
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-9.d
>@@ -0,0 +1,7 @@
>+#source: ifunc-9.s
>+#ld: --export-dynamic
>+#readelf: -r --wide
>+
>+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-9.s b/ld/testsuite/ld-riscv-elf/ifunc-9.s
>new file mode 100644
>index 0000000..453bcfe
>--- /dev/null
>+++ b/ld/testsuite/ld-riscv-elf/ifunc-9.s
>@@ -0,0 +1,24 @@
>+ .text
>+ .type foo, %gnu_indirect_function
>+.globl foo
>+ .type foo, @function
>+foo:
>+ ret
>+ .size foo, .-foo
>+ .type start,"function"
>+ .global start
>+start:
>+ .type _start,"function"
>+ .global _start
>+_start:
>+ .type __start,"function"
>+ .global __start
>+__start:
>+ .type __start,"function"
>+.L1:
>+ auipc x1, %pcrel_hi (data_p)
>+ addi x1, x1, %pcrel_lo (.L1)
>+
>+ .data
>+data_p:
>+ .long foo
>diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>index 1a0c68f..049f573 100644
>--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>@@ -87,4 +87,205 @@ if [istarget "riscv*-*-*"] {
> {} "lib-nopic-01a.so" }
> }
> run_dump_test "lib-nopic-01b"
>+
>+ # IFUNC testcases.
>+ run_dump_test "ifunc-1"
>+ run_dump_test "ifunc-1-local"
>+ run_dump_test "ifunc-2"
>+ run_dump_test "ifunc-2-local"
>+ run_dump_test "ifunc-3a"
>+ run_dump_test "ifunc-3b"
>+ run_dump_test "ifunc-4"
>+ run_dump_test "ifunc-4-local"
>+ run_ld_link_tests {
>+ { "ifunc-5a"
>+ "" ""
>+ "" {ifunc-5.s}
>+ {{readelf {-r --wide} ifunc-5a.d}} "ifunc-5a"}
>+ { "ifunc-5b"
>+ "-shared -z nocombreloc" ""
>+ "" {ifunc-5.s}
>+ {{readelf {-r --wide} ifunc-5b.d}} "ifunc-5b"}
>+ { "ifunc-5a-local"
>+ "" ""
>+ "" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5a-local.d}} "ifunc-5a-local"}
>+ { "ifunc-5b-local"
>+ "-shared -z nocombreloc" ""
>+ "" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5b-local.d}} "ifunc-5b-local"}
>+ { "ifunc-5r-local"
>+ "-r" ""
>+ "--mno-relax" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5r-local.d}} "ifunc-5r-local"}
>+
>+ { "ifunc-5a (rv64)"
>+ "-melf64lriscv" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-5.s}
>+ {{readelf {-r --wide} ifunc-5a.d}} "ifunc-5a-rv64"}
>+ { "ifunc-5b (rv64)"
>+ "-melf64lriscv -shared -z nocombreloc" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-5.s}
>+ {{readelf {-r --wide} ifunc-5b.d}} "ifunc-5b-rv64"}
>+ { "ifunc-5a-local (rv64)"
>+ "-melf64lriscv" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5a-local.d}} "ifunc-5a-local-rv64"}
>+ { "ifunc-5b-local (rv64)"
>+ "-melf64lriscv -shared -z nocombreloc" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5b-local.d}} "ifunc-5b-local-rv64"}
>+ { "ifunc-5r-local (rv64)"
>+ "-melf64lriscv -r" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1 --mno-relax" {ifunc-5-local.s}
>+ {{readelf {-r --wide} ifunc-5r-local.d}} "ifunc-5r-local-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-6a"
>+ "" ""
>+ "" {ifunc-6.s}
>+ {{readelf {-r --wide} ifunc-6a.d}} "ifunc-6a"}
>+ { "ifunc-6b"
>+ "-shared -z nocombreloc" ""
>+ "" {ifunc-6.s}
>+ {{readelf {-r --wide} ifunc-6b.d}} "ifunc-6b"}
>+
>+ { "ifunc-6a (rv64)"
>+ "-melf64lriscv" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-6.s}
>+ {{readelf {-r --wide} ifunc-6a.d}} "ifunc-6a-rv64"}
>+ { "ifunc-6b (rv64)"
>+ "-melf64lriscv -shared -z nocombreloc" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-6.s}
>+ {{readelf {-r --wide} ifunc-6b.d}} "ifunc-6b-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-7a"
>+ "" ""
>+ "" {ifunc-7.s}
>+ {{readelf {-r --wide} ifunc-7a.d}} "ifunc-7a"}
>+ { "ifunc-7b"
>+ "-shared" ""
>+ "" {ifunc-7.s}
>+ {{readelf {-r --wide} ifunc-7b.d}} "ifunc-7b"}
>+
>+ { "ifunc-7a (rv64)"
>+ "-melf64lriscv" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-7.s}
>+ {{readelf {-r --wide} ifunc-7a.d}} "ifunc-7a-rv64"}
>+ { "ifunc-7b (rv64)"
>+ "-melf64lriscv -shared" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-7.s}
>+ {{readelf {-r --wide} ifunc-7b.d}} "ifunc-7b-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-8"
>+ "" ""
>+ "" {ifunc-8a.s ifunc-8b.s}
>+ {{readelf {-r --wide} ifunc-8.d}} "ifunc-8"}
>+
>+ { "ifunc-8 (rv64)"
>+ "" ""
>+ "" {ifunc-8a.s ifunc-8b.s}
>+ {{readelf {-r --wide} ifunc-8.d}} "ifunc-8-rv64"}
>+ }
>+ run_dump_test "ifunc-9"
>+ run_ld_link_tests {
>+ { "ifunc-10"
>+ "-e bar --gc-sections" ""
>+ "" {ifunc-10.s}
>+ {{readelf {-r --wide} ifunc-10.d}} "ifunc-10"}
>+
>+ { "ifunc-10 (rv64)"
>+ "-melf64lriscv -e bar --gc-sections" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-10.s}
>+ {{readelf {-r --wide} ifunc-10.d}} "ifunc-10-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-11a"
>+ "-e bar --gc-sections" ""
>+ "" {ifunc-11.s}
>+ {{readelf {-r --wide} ifunc-11a.d}} "ifunc-11a"}
>+ { "ifunc-11b"
>+ "-e bar" ""
>+ "" {ifunc-11.s}
>+ {{readelf {-r --wide} ifunc-11b.d}} "ifunc-11b"}
>+
>+ { "ifunc-11a (rv64)"
>+ "-melf64lriscv -e bar --gc-sections" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-11.s}
>+ {{readelf {-r --wide} ifunc-11a.d}} "ifunc-11a-rv64"}
>+ { "ifunc-11b (rv64)"
>+ "-melf64lriscv -e bar" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-11.s}
>+ {{readelf {-r --wide} ifunc-11b.d}} "ifunc-11b-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-12"
>+ "-shared -e bar --gc-sections" ""
>+ "" {ifunc-12.s}
>+ {{readelf {-r --wide} ifunc-12.d}} "ifunc-12"}
>+
>+ { "ifunc-12 (rv64)"
>+ "-melf64lriscv -shared -e bar --gc-sections" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-12.s}
>+ {{readelf {-r --wide} ifunc-12.d}} "ifunc-12-rv64"}
>+ }
>+ run_dump_test "ifunc-13"
>+ run_dump_test "ifunc-14a"
>+ run_dump_test "ifunc-14b"
>+ run_dump_test "ifunc-14c"
>+ run_dump_test "ifunc-14d"
>+ run_dump_test "ifunc-14e"
>+ run_dump_test "ifunc-14f"
>+ run_ld_link_tests {
>+ { "ifunc-15"
>+ "-shared -z nocombreloc" ""
>+ "" {ifunc-15.s}
>+ {{readelf {-r --wide} ifunc-15.d}} "ifunc-15"}
>+
>+ { "ifunc-15 (rv64)"
>+ "-melf64lriscv -shared -z nocombreloc" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-15.s}
>+ {{readelf {-r --wide} ifunc-15.d}} "ifunc-15-rv64"}
>+ }
>+ run_dump_test "ifunc-16"
>+ run_dump_test "ifunc-16-now"
>+ run_dump_test "ifunc-17a"
>+ run_dump_test "ifunc-17b"
>+ run_dump_test "ifunc-18a"
>+ run_dump_test "ifunc-18b"
>+ run_dump_test "ifunc-19a"
>+ run_dump_test "ifunc-19b"
>+ run_dump_test "ifunc-20"
>+ run_ld_link_tests {
>+ { "ifunc-21"
>+ "-shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code" ""
>+ "" {ifunc-21.s}
>+ {{objdump -dw ifunc-21.d}} "ifunc-21"}
>+
>+ { "ifunc-21 (rv64)"
>+ "-melf64lriscv -shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-21.s}
>+ {{objdump -dw ifunc-21.d}} "ifunc-21-rv64"}
>+ }
>+ run_ld_link_tests {
>+ { "ifunc-22"
>+ "-shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code" ""
>+ "" {ifunc-22.s}
>+ {{objdump -dw ifunc-22.d}} "ifunc-22"}
>+
>+ { "ifunc-22 (rv64)"
>+ "-melf64lriscv -shared --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code" ""
>+ "-march=rv64i -mabi=lp64 -defsym __64_bit__=1" {ifunc-22.s}
>+ {{objdump -dw ifunc-22.d}} "ifunc-22-rv64"}
>+ }
>+ run_dump_test "ifunc-23a"
>+ run_dump_test "ifunc-23b"
>+ run_dump_test "ifunc-23c"
>+ run_dump_test "ifunc-24a"
>+ run_dump_test "ifunc-24b"
>+ run_dump_test "ifunc-25a"
>+ run_dump_test "ifunc-25b"
>+ run_dump_test "ifunc-25c"
> }
>--
>2.7.4
>
(Off-topic
I think -z separate-code being default on linux x86 since binutils 2.31
is not the best choice. GNU ld should have --rosegment like gold and LLD.
-z separate-code should be responsible for overlapping p_offset
https://reviews.llvm.org/D64903)
More information about the Binutils
mailing list