ifunc_init.c (1614B)
1 /* IFUNC startup init for kit-ld static ELF binaries. 2 * 3 * The linker (src/link/link_layout.c::layout_iplt) materializes one 4 * iplt stub + one .igot.plt slot per defined STT_GNU_IFUNC symbol and 5 * also emits a parallel .iplt.pairs data section: alternating 6 * (resolver_ptr, slot_ptr) u64 pairs in the same order as the slots. 7 * For the ELF emit path, the linker additionally synthesizes a 8 * .init_array entry pointing at __kit_ifunc_init below; the 9 * freestanding _start (or any standard CRT) walks .init_array before 10 * user code, so by the time test_main / main runs, every slot holds 11 * the chosen implementation pointer and the iplt stub's load+branch 12 * tail-calls correctly. 13 * 14 * The JIT path doesn't hit this function: link_jit.c pre-resolves 15 * slots in-process at load time and intentionally skips the 16 * .init_array synthesis (so __kit_ifunc_init never becomes an undef 17 * ref the JIT user has to satisfy). 18 * 19 * The .iplt.pairs span symbols are weak so this object can also be 20 * linked into images that don't carry IFUNCs (or that were linked by 21 * a non-kit linker that doesn't synthesize __start_iplt_pairs / 22 * __stop_iplt_pairs) — the function is then a no-op. */ 23 24 extern void* __start_iplt_pairs[] __attribute__((weak)); 25 extern void* __stop_iplt_pairs[] __attribute__((weak)); 26 27 typedef void* (*kit_ifunc_resolver_t)(void); 28 29 void __kit_ifunc_init(void) { 30 void** p = __start_iplt_pairs; 31 void** end = __stop_iplt_pairs; 32 if (!p || !end) return; 33 for (; p < end; p += 2) { 34 kit_ifunc_resolver_t r = (kit_ifunc_resolver_t)p[0]; 35 void** slot = (void**)p[1]; 36 *slot = r(); 37 } 38 }