Assume this code: extern int f(void); void alt1(void) { } void alt2(void) { } static void (*resolve (void)) (void) { return f() ? alt1 : alt2; } void fct(void) __attribute__ ((ifunc ("resolve"))); extern __typeof(fct) int_fct __attribute__ ((alias("fct"))); void g(void) { int_fct(); } And this linker map: { global: fct; local: *; }; Compiling using gcc -shared -fpic bug.c -Wl,--version-script,bug.map The problem is the .rela.plt / .rel.plt section. On my x86-64 system it looks like this: 0x0000000000200858 X86_64_JUMP_SLOT 000000000000000000 +0 __cxa_finalize 0x0000000000200860 X86_64_IRELATIVE 000000000000000000 +1304 0x0000000000200868 X86_64_JUMP_SLOT 000000000000000000 +0 f This is a problem, the ifunc for the IRELATIVE relocation calls f. That PLT slot isn't set up yet. There is no problem with an ifunc callback to call another function. Therefore IRELATIVE relocation should all be moved to the back of the section. There are no drawbacks to doing this and carefully designed DSOs can call functions in ifunc callbacks.
Created attachment 6016 [details] A patch Please try this.
Created attachment 6023 [details] A patch This patch can build glibc on ia32 and x86-64.
CVSROOT: /cvs/src Module name: src Changes by: hjl@sourceware.org 2011-10-21 15:13:37 Modified files: bfd : ChangeLog elf32-i386.c elf64-x86-64.c ld/testsuite : ChangeLog Added files: ld/testsuite/ld-ifunc: ifunc-16-i386.d ifunc-16-x86-64.d ifunc-16-x86.s Log message: Put IRELATIVE relocations after JUMP_SLOT. bfd/ 2011-10-21 H.J. Lu <hongjiu.lu@intel.com> PR ld/13302 * elf32-i386.c (elf_i386_link_hash_table): Add next_jump_slot_index and next_irelative_index. (elf_i386_link_hash_table_create): Initialize next_jump_slot_index and next_irelative_index. (elf_i386_allocate_dynrelocs): Increment reloc_count instead of next_tls_desc_index. (elf_i386_size_dynamic_sections): Set next_tls_desc_index and next_irelative_index from reloc_count. (elf_i386_finish_dynamic_symbol): Put R_386_IRELATIVE after R_386_JUMP_SLOT. * elf64-x86-64.c (elf_x86_64_link_hash_table): Add next_jump_slot_index and next_irelative_index. (elf_x86_64_link_hash_table_create): Initialize next_jump_slot_index and next_irelative_index. (elf_x86_64_size_dynamic_sections): Set next_irelative_index from reloc_count. (elf_x86_64_finish_dynamic_symbol): Put R_X86_64_IRELATIVE after R_X86_64_JUMP_SLOT. ld/testsuite/ 2011-10-21 H.J. Lu <hongjiu.lu@intel.com> PR ld/13302 * ld-ifunc/ifunc-16-i386.d: New. * ld-ifunc/ifunc-16-x86-64.d: Likewise. * ld-ifunc/ifunc-16-x86.s: Likewise. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5497&r2=1.5498 http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.262&r2=1.263 http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf64-x86-64.c.diff?cvsroot=src&r1=1.241&r2=1.242 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ChangeLog.diff?cvsroot=src&r1=1.1472&r2=1.1473 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-i386.d.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-x86-64.d.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-ifunc/ifunc-16-x86.s.diff?cvsroot=src&r1=NONE&r2=1.1
Another problem: [hjl@gnu-6 pr13302b]$ cat x.c void alt2(void) { } static void (*resolve (void)) (void) { return alt2; } void fct(void) __attribute__ ((ifunc ("resolve"))); extern __typeof(fct) int_fct __attribute__ ((alias("fct"))); void (*g)(void) = int_fct; int main () { g (); return 0; } [hjl@gnu-6 pr13302b]$ make /usr/gcc-4.7.0-x32/bin/gcc -fpie -c -o x.o x.c /usr/gcc-4.7.0-x32/bin/gcc -pie -o x x.o readelf -r --wide x Relocation section '.rela.dyn' at offset 0x498 contains 10 entries: Offset Info Type Symbol's Value Symbol's Name + Addend 00000000002008c8 0000000000000008 R_X86_64_RELATIVE 00000000000006a0 00000000002008d0 0000000000000008 R_X86_64_RELATIVE 0000000000000670 0000000000200ab0 0000000000000008 R_X86_64_RELATIVE 0000000000000790 0000000000200ac0 0000000000000008 R_X86_64_RELATIVE 0000000000000700 0000000000200ac8 0000000000000008 R_X86_64_RELATIVE 00000000000006df 0000000000200b18 0000000000000008 R_X86_64_RELATIVE 0000000000200b18 0000000000200ab8 0000000500000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0 0000000000200ad0 0000000a00000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0 0000000000200ad8 0000000b00000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize + 0 0000000000200b20 0000000000000025 R_X86_64_IRELATIVE 00000000000006d2 Relocation section '.rela.plt' at offset 0x588 contains 3 entries: Offset Info Type Symbol's Value Symbol's Name + Addend 0000000000200af8 0000000400000007 R_X86_64_JUMP_SLOT 0000000000000000 __libc_start_main + 0 0000000000200b08 0000000b00000007 R_X86_64_JUMP_SLOT 0000000000000000 __cxa_finalize + 0 0000000000200b00 0000000000000025 R_X86_64_IRELATIVE 00000000000006d2 [hjl@gnu-6 pr13302b]$ We have R_X86_64_IRELATIVE in .rela.dyn.
CVSROOT: /cvs/src Module name: src Changes by: hjl@sourceware.org 2011-10-21 19:37:15 Modified files: bfd : ChangeLog elf32-i386.c elf64-x86-64.c ld/testsuite : ChangeLog ld/testsuite/ld-i386: i386.exp ld/testsuite/ld-x86-64: pr13082-5b.d pr13082-6a.d pr13082-6b.d Added files: ld/testsuite/ld-i386: pr13302.d pr13302.s Log message: Replace IRELATIVE relocations with RELATIVE in .rel.dyn. bfd/ 2011-10-21 H.J. Lu <hongjiu.lu@intel.com> PR ld/13302 * elf32-i386.c (elf_i386_relocate_section): Replace R_386_IRELATIVE with R_386_RELATIVE. * elf64-x86-64.c (elf_x86_64_relocate_section): Replace R_X86_64_IRELATIVE with R_X86_64_RELATIVE. ld/testsuite/ 2011-10-21 H.J. Lu <hongjiu.lu@intel.com> PR ld/13302 * ld-i386/i386.exp: Run pr13302. * ld-i386/pr13302.d: New. * ld-i386/pr13302.s: Likewise. * ld-x86-64/pr13082-5b.d: Updated. * ld-x86-64/pr13082-6a.d: Likewise. * ld-x86-64/pr13082-6b.d: Likewise. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5499&r2=1.5500 http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.264&r2=1.265 http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf64-x86-64.c.diff?cvsroot=src&r1=1.243&r2=1.244 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ChangeLog.diff?cvsroot=src&r1=1.1473&r2=1.1474 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/pr13302.d.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/pr13302.s.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/i386.exp.diff?cvsroot=src&r1=1.40&r2=1.41 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-5b.d.diff?cvsroot=src&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-6a.d.diff?cvsroot=src&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-x86-64/pr13082-6b.d.diff?cvsroot=src&r1=1.1&r2=1.2
Fixed.
Only fixed x86 and x86_64. arm, ppc32, ppc64, and sparc all support ifunc too.
*** Bug 19368 has been marked as a duplicate of this bug. ***
The master branch has been updated by H.J. Lu <hjl@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5e2ac45d561dffec63af4c83a545b46db032c70c commit 5e2ac45d561dffec63af4c83a545b46db032c70c Author: H.J. Lu <hjl.tools@gmail.com> Date: Sat Sep 2 07:37:05 2017 -0700 x86: Add _bfd_x86_elf_size_dynamic_sections elf_i386_size_dynamic_sections and elf_x86_64_size_dynamic_sections are very similar, except for the followings: 1. elf_i386_size_dynamic_sections checks GOT_TLS_IE and GOT_TLS_IE_BOTH. elf_x86_64_size_dynamic_sections checks only GOT_TLS_IE. Since GOT_TLS_IE_BOTH is never true for x86-64, it is OK to check GOT_TLS_IE for both i386 and x86-64. 2, x86-64 sets tlsdesc_plt, but i386 doesn't. We set tlsdesc_plt only if target_id == X86_64_ELF_DATA. 3. x86-64 has if (s != htab->elf.srelplt) s->reloc_count = 0; and i386 has s->reloc_count = 0; i386 did have if (s != htab->srelplt) s->reloc_count = 0; in the original commit: commit 67a4f2b710581acc83afecff55424af285ecbc28 Author: Alexandre Oliva <aoliva@redhat.com> Date: Wed Jan 18 21:07:51 2006 +0000 But it was removed by commit 5ae0bfb60a576344d7f701605346282c1144499e Author: Richard Sandiford <rdsandiford@googlemail.com> Date: Tue Feb 28 07:16:12 2006 +0000 bfd/ * elf32-i386.c (elf_i386_link_hash_table): Add next_tls_desc_index. (elf_i386_link_hash_table_create): Initialize it. (elf_i386_compute_jump_table_size): Use it instead of srelplt->reloc_count. (allocate_dynrelocs): Likewise. (elf_i386_size_dynamic_sections): Likewise. (elf_i386_relocate_section): Likewise. A later commit: commit e1f987424b7b3f5ac63a2a6ae044a202a44b8ff8 Author: H.J. Lu <hjl.tools@gmail.com> Date: Fri Oct 21 15:13:37 2011 +0000 Put IRELATIVE relocations after JUMP_SLOT. bfd/ 2011-10-21 H.J. Lu <hongjiu.lu@intel.com> PR ld/13302 * elf32-i386.c (elf_i386_link_hash_table): Add next_jump_slot_index and next_irelative_index. (elf_i386_link_hash_table_create): Initialize next_jump_slot_index and next_irelative_index. (elf_i386_allocate_dynrelocs): Increment reloc_count instead of next_tls_desc_index. (elf_i386_size_dynamic_sections): Set next_tls_desc_index and next_irelative_index from reloc_count. (elf_i386_finish_dynamic_symbol): Put R_386_IRELATIVE after R_386_JUMP_SLOT. changed it back to use reloc_count again. So it is correct to use if (s != htab->elf.srelplt) s->reloc_count = 0; for both i386 and x86-64 now. 4. i386 and x86-64 use different DT_XXXs. They are handled by adding them to elf_x86_link_hash_table. With these changes, we can share _bfd_x86_elf_size_dynamic_sections in elf32-i386.c and elf64-x86-64.c. * elf32-i386.c (elf_i386_convert_load): Renamed to ... (_bfd_i386_elf_convert_load): This. Remove static. (elf_i386_size_dynamic_sections): Removed. (elf_backend_size_dynamic_sections): Likewise. * elf64-x86-64.c (elf_x86_64_convert_load): Renamed to ... (_bfd_x86_64_elf_convert_load): This. Remove static. (elf_x86_64_size_dynamic_sections): Removed. (elf_backend_size_dynamic_sections): Likewise. * elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): Renamed to ... (elf_x86_allocate_dynrelocs): This. Make it static. (_bfd_x86_elf_allocate_local_dynrelocs): Renamed to ... (elf_x86_allocate_local_dynreloc): This. Make it static. (elf_i386_is_reloc_section): New function. (elf_x86_64_is_reloc_section): Likewise. (_bfd_x86_elf_link_hash_table_create): Initialize convert_load, is_reloc_section, dt_reloc, dt_reloc_sz and dt_reloc_ent. Rearrange got_entry_size initialization. (_bfd_x86_elf_size_dynamic_sections): New function. * elfxx-x86.h (elf_x86_link_hash_table): Add convert_load, is_reloc_section, dt_reloc, dt_reloc_sz and dt_reloc_ent. (_bfd_i386_elf_convert_load): New. (_bfd_x86_64_elf_convert_load): Likewise. (_bfd_x86_elf_size_dynamic_sections): Likewise. (elf_backend_size_dynamic_sections): Likewise. (_bfd_x86_elf_allocate_dynrelocs): Removed. (_bfd_x86_elf_allocate_local_dynrelocs): Likewise.
Fixed on targets mentioned in comment #7, aarch64, csky and loongarch. s390 and riscv might still be susceptible to irelative ordering problems.
For riscv, in the allocate_dynrelocs, all STT_GNU_IFUNC will be handled until allocate_ifunc_dynrelocs and allocate_local_ifunc_dynrelocs, so the offset of plt and got entries for ifunc symbols should be at last. Besides, in the finish_dynamic_symbol, riscv inserts the dynamic relocations in the order of plt and got entry offset. Therefore, all the dynamic relocations of ifunc should be come last in the dynamic sections. I think the only potential risk is - if dynamic relocation of ifunc won't be IRELATIVE, it's JUMP_SLOT/32/64 relocs, then once ifunc may calls another ifunc, it is only possible for riscv to meet the order problem here. If that so, then arm's solution cannot work for riscv since IRELATIVE not only added into rel.dyn, they can be added into rel.plt, rel.got, ... just like what x86 did. Therefore, similar to x86, riscv also needs flags to insert the IRELATIVE at the last the dynamic relocation sections in the finish_dynamic_symbol, and probably needs more since not only rel.plt are used.