Module Name: src Committed By: joerg Date: Sat Aug 12 09:03:28 UTC 2017
Modified Files: src/libexec/ld.elf_so: rtld.c rtld.h src/libexec/ld.elf_so/arch/sparc: mdreloc.c src/libexec/ld.elf_so/arch/sparc64: mdreloc.c src/sys/arch/sparc/include: elf_machdep.h src/sys/arch/sparc64/include: elf_machdep.h src/tests/libexec/ld.elf_so: t_ifunc.c src/tests/libexec/ld.elf_so/helper_ifunc_dso: h_helper_ifunc.c Log Message: Add sparc/sparc64 support for irelative relocations. To generate a diff of this commit: cvs rdiff -u -r1.186 -r1.187 src/libexec/ld.elf_so/rtld.c cvs rdiff -u -r1.130 -r1.131 src/libexec/ld.elf_so/rtld.h cvs rdiff -u -r1.51 -r1.52 src/libexec/ld.elf_so/arch/sparc/mdreloc.c cvs rdiff -u -r1.64 -r1.65 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c cvs rdiff -u -r1.8 -r1.9 src/sys/arch/sparc/include/elf_machdep.h cvs rdiff -u -r1.12 -r1.13 src/sys/arch/sparc64/include/elf_machdep.h cvs rdiff -u -r1.3 -r1.4 src/tests/libexec/ld.elf_so/t_ifunc.c cvs rdiff -u -r1.5 -r1.6 \ src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/ld.elf_so/rtld.c diff -u src/libexec/ld.elf_so/rtld.c:1.186 src/libexec/ld.elf_so/rtld.c:1.187 --- src/libexec/ld.elf_so/rtld.c:1.186 Thu Aug 10 19:03:25 2017 +++ src/libexec/ld.elf_so/rtld.c Sat Aug 12 09:03:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.c,v 1.186 2017/08/10 19:03:25 joerg Exp $ */ +/* $NetBSD: rtld.c,v 1.187 2017/08/12 09:03:27 joerg Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -40,7 +40,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: rtld.c,v 1.186 2017/08/10 19:03:25 joerg Exp $"); +__RCSID("$NetBSD: rtld.c,v 1.187 2017/08/12 09:03:27 joerg Exp $"); #endif /* not lint */ #include <sys/param.h> @@ -276,7 +276,11 @@ restart: /* First pass: objects with IRELATIVE relocations. */ SIMPLEQ_FOREACH(elm, &initlist, link) { Obj_Entry * const obj = elm->obj; - if (obj->ifunc_remaining) { + if (obj->ifunc_remaining +#ifdef __sparc__ + || obj->ifunc_remaining_nonplt +#endif + ) { _rtld_call_ifunc(obj, mask, cur_objgen); if (_rtld_objgen != cur_objgen) { dbg(("restarting init iteration")); Index: src/libexec/ld.elf_so/rtld.h diff -u src/libexec/ld.elf_so/rtld.h:1.130 src/libexec/ld.elf_so/rtld.h:1.131 --- src/libexec/ld.elf_so/rtld.h:1.130 Thu Aug 10 19:03:25 2017 +++ src/libexec/ld.elf_so/rtld.h Sat Aug 12 09:03:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.h,v 1.130 2017/08/10 19:03:25 joerg Exp $ */ +/* $NetBSD: rtld.h,v 1.131 2017/08/12 09:03:27 joerg Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -300,6 +300,10 @@ typedef struct Struct_Obj_Entry { size_t fini_arraysz; /* # of entries in it */ /* IRELATIVE relocations */ size_t ifunc_remaining; +#ifdef __sparc__ + /* On SPARC, the PLT variant is called JMP_IREL and counted above. */ + size_t ifunc_remaining_nonplt; +#endif size_t cxa_refcount; /* For TLS destructors. */ #ifdef __ARM_EABI__ void *exidx_start; Index: src/libexec/ld.elf_so/arch/sparc/mdreloc.c diff -u src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.51 src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.52 --- src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.51 Thu Aug 10 19:03:26 2017 +++ src/libexec/ld.elf_so/arch/sparc/mdreloc.c Sat Aug 12 09:03:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mdreloc.c,v 1.51 2017/08/10 19:03:26 joerg Exp $ */ +/* $NetBSD: mdreloc.c,v 1.52 2017/08/12 09:03:27 joerg Exp $ */ /*- * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: mdreloc.c,v 1.51 2017/08/10 19:03:26 joerg Exp $"); +__RCSID("$NetBSD: mdreloc.c,v 1.52 2017/08/12 09:03:27 joerg Exp $"); #endif /* not lint */ #include <errno.h> @@ -220,6 +220,13 @@ _rtld_relocate_nonplt_objects(Obj_Entry if (type == R_TYPE(JMP_SLOT)) continue; + /* IFUNC relocations are handled in _rtld_call_ifunc */ + if (type == R_TYPE(IRELATIVE)) { + if (obj->ifunc_remaining_nonplt == 0) + obj->ifunc_remaining_nonplt = rela - obj->rela + 1; + continue; + } + /* COPY relocs are also handled elsewhere */ if (type == R_TYPE(COPY)) continue; @@ -387,7 +394,74 @@ _rtld_relocate_nonplt_objects(Obj_Entry int _rtld_relocate_plt_lazy(Obj_Entry *obj) { - return (0); + const Elf_Rela *rela; + + if (!obj->relocbase) + return 0; + + for (rela = obj->pltrelalim; rela-- > obj->pltrela; ) { + if (ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_IREL)) + obj->ifunc_remaining = obj->pltrelalim - rela + 1; + } + + return 0; +} + +static inline void +_rtld_write_plt(Elf_Word *where, Elf_Addr value) +{ + /* + * At the PLT entry pointed at by `where', we now construct + * a direct transfer to the now fully resolved function + * address. The resulting code in the jump slot is: + * + * sethi %hi(roffset), %g1 + * sethi %hi(addr), %g1 + * jmp %g1+%lo(addr) + * + * We write the third instruction first, since that leaves the + * previous `b,a' at the second word in place. Hence the whole + * PLT slot can be atomically change to the new sequence by + * writing the `sethi' instruction at word 2. + */ + const uint32_t SETHI = 0x03000000U; + const uint32_t JMP = 0x81c06000U; + where[2] = JMP | (value & 0x000003ff); + where[1] = SETHI | ((value >> 10) & 0x003fffff); + __asm volatile("iflush %0+8" : : "r" (where)); + __asm volatile("iflush %0+4" : : "r" (where)); +} + +void +_rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) +{ + const Elf_Rela *rela; + Elf_Addr *where, target; + + while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) { + rela = obj->pltrelalim - --obj->ifunc_remaining; + if (ELF_R_TYPE(rela->r_info) != R_TYPE(JMP_IREL)) + continue; + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + target = (Elf_Addr)(obj->relocbase + rela->r_addend); + _rtld_exclusive_exit(mask); + target = _rtld_resolve_ifunc2(obj, target); + _rtld_exclusive_enter(mask); + _rtld_write_plt(where, target); + } + + while (obj->ifunc_remaining_nonplt > 0 && _rtld_objgen == cur_objgen) { + rela = obj->relalim - --obj->ifunc_remaining_nonplt; + if (ELF_R_TYPE(rela->r_info) != R_TYPE(IRELATIVE)) + continue; + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + target = (Elf_Addr)(obj->relocbase + rela->r_addend); + _rtld_exclusive_exit(mask); + target = _rtld_resolve_ifunc2(obj, target); + _rtld_exclusive_enter(mask); + if (*where != target) + *where = target; + } } caddr_t @@ -429,6 +503,9 @@ _rtld_relocate_plt_object(const Obj_Entr Elf_Addr value; unsigned long info = rela->r_info; + if (ELF_R_TYPE(info) == R_TYPE(JMP_IREL)) + return 0; + assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); @@ -447,27 +524,7 @@ _rtld_relocate_plt_object(const Obj_Entr rdbg(("bind now/fixup in %s --> new=%p", defobj->strtab + def->st_name, (void *)value)); - /* - * At the PLT entry pointed at by `where', we now construct - * a direct transfer to the now fully resolved function - * address. The resulting code in the jump slot is: - * - * sethi %hi(roffset), %g1 - * sethi %hi(addr), %g1 - * jmp %g1+%lo(addr) - * - * We write the third instruction first, since that leaves the - * previous `b,a' at the second word in place. Hence the whole - * PLT slot can be atomically change to the new sequence by - * writing the `sethi' instruction at word 2. - */ -#define SETHI 0x03000000 -#define JMP 0x81c06000 -#define NOP 0x01000000 - where[2] = JMP | (value & 0x000003ff); - where[1] = SETHI | ((value >> 10) & 0x003fffff); - __asm volatile("iflush %0+8" : : "r" (where)); - __asm volatile("iflush %0+4" : : "r" (where)); + _rtld_write_plt(where, value); if (tp) *tp = value; Index: src/libexec/ld.elf_so/arch/sparc64/mdreloc.c diff -u src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.64 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.65 --- src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.64 Thu Aug 10 19:03:26 2017 +++ src/libexec/ld.elf_so/arch/sparc64/mdreloc.c Sat Aug 12 09:03:27 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: mdreloc.c,v 1.64 2017/08/10 19:03:26 joerg Exp $ */ +/* $NetBSD: mdreloc.c,v 1.65 2017/08/12 09:03:27 joerg Exp $ */ /*- * Copyright (c) 2000 Eduardo Horvath. @@ -32,7 +32,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: mdreloc.c,v 1.64 2017/08/10 19:03:26 joerg Exp $"); +__RCSID("$NetBSD: mdreloc.c,v 1.65 2017/08/12 09:03:27 joerg Exp $"); #endif /* not lint */ #include <errno.h> @@ -332,6 +332,13 @@ _rtld_relocate_nonplt_objects(Obj_Entry if (type == R_TYPE(JMP_SLOT)) continue; + /* IFUNC relocations are handled in _rtld_call_ifunc */ + if (type == R_TYPE(IRELATIVE)) { + if (obj->ifunc_remaining_nonplt == 0) + obj->ifunc_remaining_nonplt = rela - obj->rela + 1; + continue; + } + /* COPY relocs are also handled elsewhere */ if (type == R_TYPE(COPY)) continue; @@ -507,7 +514,17 @@ _rtld_relocate_nonplt_objects(Obj_Entry int _rtld_relocate_plt_lazy(Obj_Entry *obj) { - return (0); + const Elf_Rela *rela; + + if (!obj->relocbase) + return 0; + + for (rela = obj->pltrelalim; rela-- > obj->pltrela; ) { + if (ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_IREL)) + obj->ifunc_remaining = obj->pltrelalim - rela + 1; + } + + return 0; } caddr_t @@ -568,37 +585,11 @@ _rtld_relocate_plt_objects(const Obj_Ent return 0; } -/* - * New inline function that is called by _rtld_relocate_plt_object and - * _rtld_bind - */ -static inline int -_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, - Elf_Addr *tp) +static inline void +_rtld_write_plt(Elf_Word *where, Elf_Addr value, const Elf_Rela *rela, + const Obj_Entry *obj) { - Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); - const Elf_Sym *def; - const Obj_Entry *defobj; - Elf_Addr value, offset, offBAA; - unsigned long info = rela->r_info; - - assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); - - def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); - if (__predict_false(def == NULL)) - return -1; - if (__predict_false(def == &_rtld_sym_zero)) - return 0; - - if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { - if (tp == NULL) - return 0; - value = _rtld_resolve_ifunc(defobj, def); - } else { - value = (Elf_Addr)(defobj->relocbase + def->st_value); - } - rdbg(("bind now/fixup in %s at %p --> new=%p", - defobj->strtab + def->st_name, (void*)where, (void *)value)); + Elf_Addr offset, offBAA; /* * At the PLT entry pointed at by `where', we now construct a direct @@ -625,8 +616,8 @@ _rtld_relocate_plt_object(const Obj_Entr */ offset = ((Elf_Addr)where) - value; - offBAA = value - (((Elf_Addr)where) +4); /* ba,a at where[1] */ - if (rela->r_addend) { + offBAA = value - (((Elf_Addr)where) + 4); /* ba,a at where[1] */ + if (rela && rela->r_addend) { Elf_Addr *ptr = (Elf_Addr *)where; /* * This entry is >= 32768. The relocations points to a @@ -634,7 +625,6 @@ _rtld_relocate_plt_object(const Obj_Entr * PLT section. Update it to point to the target function. */ ptr[0] += value - (Elf_Addr)obj->pltgot; - } else if (offBAA <= (1L<<20) && (Elf_SOff)offBAA >= -(1L<<20)) { /* * We're within 1MB -- we can use a direct branch insn. @@ -673,7 +663,6 @@ _rtld_relocate_plt_object(const Obj_Entr where[1] = SETHI | HIVAL(value, 10); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value <= 0 && (Elf_SOff)value > -(1L<<32)) { /* * We're within 32-bits of address -1. @@ -696,7 +685,6 @@ _rtld_relocate_plt_object(const Obj_Entr __asm volatile("iflush %0+12" : : "r" (where)); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((offset+8) <= (1L<<31) && (Elf_SOff)(offset+8) >= -((1L<<31) - 4)) { /* @@ -721,7 +709,6 @@ _rtld_relocate_plt_object(const Obj_Entr __asm volatile("iflush %0+12" : : "r" (where)); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value > 0 && value < (1L<<44)) { /* * We're within 44 bits. We can generate this pattern: @@ -746,7 +733,6 @@ _rtld_relocate_plt_object(const Obj_Entr __asm volatile("iflush %0+12" : : "r" (where)); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); - } else if ((Elf_SOff)value < 0 && (Elf_SOff)value > -(1L<<44)) { /* * We're within 44 bits. We can generate this pattern: @@ -774,7 +760,6 @@ _rtld_relocate_plt_object(const Obj_Entr __asm volatile("iflush %0+12" : : "r" (where)); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); - } else { /* * We need to load all 64-bits @@ -803,11 +788,82 @@ _rtld_relocate_plt_object(const Obj_Entr __asm volatile("iflush %0+12" : : "r" (where)); __asm volatile("iflush %0+8" : : "r" (where)); __asm volatile("iflush %0+4" : : "r" (where)); + } +} + +/* + * New inline function that is called by _rtld_relocate_plt_object and + * _rtld_bind + */ +static inline int +_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, + Elf_Addr *tp) +{ + Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr value; + unsigned long info = rela->r_info; + + if (ELF_R_TYPE(info) == R_TYPE(JMP_IREL)) + return 0; + + assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT)); + + def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL); + if (__predict_false(def == NULL)) + return -1; + if (__predict_false(def == &_rtld_sym_zero)) + return 0; + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + if (tp == NULL) + return 0; + value = _rtld_resolve_ifunc(defobj, def); + } else { + value = (Elf_Addr)(defobj->relocbase + def->st_value); } + rdbg(("bind now/fixup in %s at %p --> new=%p", + defobj->strtab + def->st_name, (void*)where, (void *)value)); + + _rtld_write_plt(where, value, rela, obj); if (tp) *tp = value; return 0; } + +void +_rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) +{ + const Elf_Rela *rela; + Elf_Addr *where; + Elf_Word *where2; + Elf_Addr target; + + while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) { + rela = obj->pltrelalim - --obj->ifunc_remaining; + if (ELF_R_TYPE(rela->r_info) != R_TYPE(JMP_IREL)) + continue; + where2 = (Elf_Word *)(obj->relocbase + rela->r_offset); + target = (Elf_Addr)(obj->relocbase + rela->r_addend); + _rtld_exclusive_exit(mask); + target = _rtld_resolve_ifunc2(obj, target); + _rtld_exclusive_enter(mask); + _rtld_write_plt(where2, target, NULL, obj); + } + + while (obj->ifunc_remaining_nonplt > 0 && _rtld_objgen == cur_objgen) { + rela = obj->relalim - --obj->ifunc_remaining_nonplt; + if (ELF_R_TYPE(rela->r_info) != R_TYPE(IRELATIVE)) + continue; + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + target = (Elf_Addr)(obj->relocbase + rela->r_addend); + _rtld_exclusive_exit(mask); + target = _rtld_resolve_ifunc2(obj, target); + _rtld_exclusive_enter(mask); + if (*where != target) + *where = target; + } +} Index: src/sys/arch/sparc/include/elf_machdep.h diff -u src/sys/arch/sparc/include/elf_machdep.h:1.8 src/sys/arch/sparc/include/elf_machdep.h:1.9 --- src/sys/arch/sparc/include/elf_machdep.h:1.8 Thu Feb 2 08:12:08 2017 +++ src/sys/arch/sparc/include/elf_machdep.h Sat Aug 12 09:03:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: elf_machdep.h,v 1.8 2017/02/02 08:12:08 martin Exp $ */ +/* $NetBSD: elf_machdep.h,v 1.9 2017/08/12 09:03:28 joerg Exp $ */ #define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB #define ELF32_MACHDEP_ID_CASES \ @@ -87,4 +87,7 @@ #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 + #define R_TYPE(name) __CONCAT(R_SPARC_,name) Index: src/sys/arch/sparc64/include/elf_machdep.h diff -u src/sys/arch/sparc64/include/elf_machdep.h:1.12 src/sys/arch/sparc64/include/elf_machdep.h:1.13 --- src/sys/arch/sparc64/include/elf_machdep.h:1.12 Tue Jan 31 16:13:56 2017 +++ src/sys/arch/sparc64/include/elf_machdep.h Sat Aug 12 09:03:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: elf_machdep.h,v 1.12 2017/01/31 16:13:56 martin Exp $ */ +/* $NetBSD: elf_machdep.h,v 1.13 2017/08/12 09:03:28 joerg Exp $ */ #define ELF32_MACHDEP_ENDIANNESS ELFDATA2MSB #define ELF32_MACHDEP_ID_CASES \ @@ -137,4 +137,7 @@ void sparc64_elf_mcmodel_check(struct ex #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 + #define R_TYPE(name) __CONCAT(R_SPARC_,name) Index: src/tests/libexec/ld.elf_so/t_ifunc.c diff -u src/tests/libexec/ld.elf_so/t_ifunc.c:1.3 src/tests/libexec/ld.elf_so/t_ifunc.c:1.4 --- src/tests/libexec/ld.elf_so/t_ifunc.c:1.3 Thu Aug 10 19:03:27 2017 +++ src/tests/libexec/ld.elf_so/t_ifunc.c Sat Aug 12 09:03:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ifunc.c,v 1.3 2017/08/10 19:03:27 joerg Exp $ */ +/* $NetBSD: t_ifunc.c,v 1.4 2017/08/12 09:03:28 joerg Exp $ */ /* * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -56,7 +56,7 @@ ATF_TC_BODY(rtld_ifunc, tc) const char *error; size_t i; -#if !defined( __arm__) && !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__) +#if !defined( __arm__) && !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__) && !defined(__sparc__) atf_tc_expect_fail("Missing linker support for hidden ifunc relocations"); #endif @@ -106,6 +106,7 @@ ATF_TC_BODY(rtld_hidden_ifunc, tc) }; void *handle; int (*sym)(void); + int (*(*sym2)(void))(void); int result; const char *error; size_t i; @@ -126,6 +127,15 @@ ATF_TC_BODY(rtld_hidden_ifunc, tc) result = (*sym)(); ATF_CHECK(result == expected_result[!i]); + sym2 = dlsym(handle, "ifunc_indirect"); + error = dlerror(); + ATF_CHECK(error == NULL); + ATF_CHECK(sym2 != NULL); + + sym = (*sym2)(); + result = (*sym)(); + ATF_CHECK(result == expected_result[!i]); + dlclose(handle); error = dlerror(); ATF_CHECK(error == NULL); Index: src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c diff -u src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c:1.5 src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c:1.6 --- src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c:1.5 Thu Aug 10 19:03:27 2017 +++ src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c Sat Aug 12 09:03:28 2017 @@ -66,3 +66,10 @@ int ifunc_plt(void) { return ifunc_hidden(); } + +int (*ifunc_indirect(void))(void); + +int (*ifunc_indirect(void))(void) +{ + return ifunc_hidden; +}