Module Name:    src
Committed By:   joerg
Date:           Mon Aug 25 20:40:53 UTC 2014

Modified Files:
        src/distrib/sets/lists/debug: mi shl.mi
        src/distrib/sets/lists/tests: mi shl.mi
        src/libexec/ld.elf_so: headers.c reloc.c rtld.c rtld.h
        src/libexec/ld.elf_so/arch/aarch64: mdreloc.c
        src/libexec/ld.elf_so/arch/alpha: alpha_reloc.c
        src/libexec/ld.elf_so/arch/arm: mdreloc.c
        src/libexec/ld.elf_so/arch/hppa: hppa_reloc.c
        src/libexec/ld.elf_so/arch/i386: mdreloc.c
        src/libexec/ld.elf_so/arch/m68k: mdreloc.c
        src/libexec/ld.elf_so/arch/mips: mips_reloc.c
        src/libexec/ld.elf_so/arch/powerpc: ppc_reloc.c
        src/libexec/ld.elf_so/arch/sh3: mdreloc.c
        src/libexec/ld.elf_so/arch/sparc: mdreloc.c
        src/libexec/ld.elf_so/arch/sparc64: mdreloc.c
        src/libexec/ld.elf_so/arch/vax: mdreloc.c
        src/libexec/ld.elf_so/arch/x86_64: mdreloc.c
        src/sys/sys: cdefs_elf.h exec_elf.h
        src/tests/libexec/ld.elf_so: Makefile
Added Files:
        src/tests/libexec/ld.elf_so: h_ifunc.c t_ifunc.c
        src/tests/libexec/ld.elf_so/helper_ifunc_dso: Makefile h_helper_ifunc.c

Log Message:
Add basic support for indirect functions. It allows providing a public
function symbol with an implementation choosen at run time.
Refactor calls to functions by address in ld.elf_so to create temporary
function descriptors on the stack, if the address is not leaked outside.

Limitations:
- no support for initialising static storage with function pointers
- no support for unnamed resolver functions

Inspired by FreeBSD's r228435 by [email protected].


To generate a diff of this commit:
cvs rdiff -u -r1.84 -r1.85 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.72 -r1.73 src/distrib/sets/lists/debug/shl.mi
cvs rdiff -u -r1.589 -r1.590 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.8 -r1.9 src/distrib/sets/lists/tests/shl.mi
cvs rdiff -u -r1.54 -r1.55 src/libexec/ld.elf_so/headers.c
cvs rdiff -u -r1.106 -r1.107 src/libexec/ld.elf_so/reloc.c
cvs rdiff -u -r1.173 -r1.174 src/libexec/ld.elf_so/rtld.c
cvs rdiff -u -r1.119 -r1.120 src/libexec/ld.elf_so/rtld.h
cvs rdiff -u -r1.1 -r1.2 src/libexec/ld.elf_so/arch/aarch64/mdreloc.c
cvs rdiff -u -r1.40 -r1.41 src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c
cvs rdiff -u -r1.37 -r1.38 src/libexec/ld.elf_so/arch/arm/mdreloc.c
cvs rdiff -u -r1.42 -r1.43 src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c
cvs rdiff -u -r1.35 -r1.36 src/libexec/ld.elf_so/arch/i386/mdreloc.c
cvs rdiff -u -r1.29 -r1.30 src/libexec/ld.elf_so/arch/m68k/mdreloc.c
cvs rdiff -u -r1.62 -r1.63 src/libexec/ld.elf_so/arch/mips/mips_reloc.c
cvs rdiff -u -r1.52 -r1.53 src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
cvs rdiff -u -r1.30 -r1.31 src/libexec/ld.elf_so/arch/sh3/mdreloc.c
cvs rdiff -u -r1.47 -r1.48 src/libexec/ld.elf_so/arch/sparc/mdreloc.c
cvs rdiff -u -r1.56 -r1.57 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c
cvs rdiff -u -r1.29 -r1.30 src/libexec/ld.elf_so/arch/vax/mdreloc.c
cvs rdiff -u -r1.40 -r1.41 src/libexec/ld.elf_so/arch/x86_64/mdreloc.c
cvs rdiff -u -r1.44 -r1.45 src/sys/sys/cdefs_elf.h
cvs rdiff -u -r1.142 -r1.143 src/sys/sys/exec_elf.h
cvs rdiff -u -r1.7 -r1.8 src/tests/libexec/ld.elf_so/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/libexec/ld.elf_so/h_ifunc.c \
    src/tests/libexec/ld.elf_so/t_ifunc.c
cvs rdiff -u -r0 -r1.1 src/tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile \
    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/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.84 src/distrib/sets/lists/debug/mi:1.85
--- src/distrib/sets/lists/debug/mi:1.84	Mon Aug 25 18:44:03 2014
+++ src/distrib/sets/lists/debug/mi	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.84 2014/08/25 18:44:03 pooka Exp $
+# $NetBSD: mi,v 1.85 2014/08/25 20:40:52 joerg Exp $
 
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib/i18n/libBIG5_g.a			comp-c-debuglib		debuglib
@@ -2131,11 +2131,13 @@
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_dl_symver_v0.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_dl_symver_v1.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_dl_symver_v2.debug	tests-libexec-debug	debug,atf,pic
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_ifunc.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_locking.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-cleared.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-false.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlinfo.debug		tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlvsym.debug		tests-libexec-debug	debug,atf,pic
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_ifunc.debug	tests-libexec-debug	debug,atf,pic
 ./usr/libdata/debug/usr/tests/net/bpf/t_bpf.debug		tests-net-debug		debug,atf,rump
 ./usr/libdata/debug/usr/tests/net/bpf/t_div-by-zero.debug		tests-net-debug		debug,atf,rump
 ./usr/libdata/debug/usr/tests/net/bpf/t_mbuf.debug		tests-net-debug		debug,atf,rump
@@ -2224,3 +2226,4 @@
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2/libh_helper_symver_dso_g.a	comp-c-debuglib	atf,debuglib
 ./usr/tests/libexec/ld.elf_so/libh_helper_dso1_g.a	comp-c-debuglib	atf,debuglib
 ./usr/tests/libexec/ld.elf_so/libh_helper_dso2_g.a	comp-c-debuglib	atf,debuglib
+./usr/tests/libexec/ld.elf_so/libh_helper_ifunc_dso_g.a	comp-c-debuglib	atf,debuglib

Index: src/distrib/sets/lists/debug/shl.mi
diff -u src/distrib/sets/lists/debug/shl.mi:1.72 src/distrib/sets/lists/debug/shl.mi:1.73
--- src/distrib/sets/lists/debug/shl.mi:1.72	Mon Aug 25 18:44:03 2014
+++ src/distrib/sets/lists/debug/shl.mi	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-# $NetBSD: shl.mi,v 1.72 2014/08/25 18:44:03 pooka Exp $
+# $NetBSD: shl.mi,v 1.73 2014/08/25 20:40:52 joerg Exp $
 ./usr/libdata/debug/lib/libc.so.12.193.debug		comp-sys-debug	debug
 ./usr/libdata/debug/lib/libcrypt.so.1.0.debug		comp-sys-debug	debug
 ./usr/libdata/debug/lib/libcrypto.so.8.3.debug		comp-sys-debug	debug
@@ -287,3 +287,4 @@
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_helper_symver_dso2/libh_helper_symver_dso.so.1.debug	tests-libexec-debug	debug,atf
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/libh_helper_dso1.so.1.debug	tests-libexec-debug	debug,atf
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/libh_helper_dso2.so.1.debug	tests-libexec-debug	debug,atf
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/libh_helper_ifunc_dso.so.1.debug	tests-libexec-debug	debug,atf

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.589 src/distrib/sets/lists/tests/mi:1.590
--- src/distrib/sets/lists/tests/mi:1.589	Sun Aug 24 11:52:45 2014
+++ src/distrib/sets/lists/tests/mi	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.589 2014/08/24 11:52:45 apb Exp $
+# $NetBSD: mi,v 1.590 2014/08/25 20:40:52 joerg Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -3068,6 +3068,7 @@
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso0	tests-libexec-tests	atf
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso1	tests-libexec-tests	atf
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2	tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/h_ifunc		tests-libexec-tests	atf,pic
 ./usr/tests/libexec/ld.elf_so/h_locking		tests-libexec-tests	atf,pic
 ./usr/tests/libexec/ld.elf_so/t_df_1_noopen	tests-libexec-tests	atf,pic
 ./usr/tests/libexec/ld.elf_so/t_dl_symver	tests-libexec-tests	atf,pic
@@ -3075,6 +3076,7 @@
 ./usr/tests/libexec/ld.elf_so/t_dlerror-false	tests-libexec-tests	atf,pic
 ./usr/tests/libexec/ld.elf_so/t_dlinfo		tests-libexec-tests	atf,pic
 ./usr/tests/libexec/ld.elf_so/t_dlvsym		tests-libexec-tests	atf,pic
+./usr/tests/libexec/ld.elf_so/t_ifunc		tests-libexec-tests	atf,pic
 ./usr/tests/modules				tests-sys-tests
 ./usr/tests/net					tests-net-tests
 ./usr/tests/net/Atffile				tests-net-tests		atf

Index: src/distrib/sets/lists/tests/shl.mi
diff -u src/distrib/sets/lists/tests/shl.mi:1.8 src/distrib/sets/lists/tests/shl.mi:1.9
--- src/distrib/sets/lists/tests/shl.mi:1.8	Sun Aug 11 22:29:03 2013
+++ src/distrib/sets/lists/tests/shl.mi	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-# $NetBSD: shl.mi,v 1.8 2013/08/11 22:29:03 joerg Exp $
+# $NetBSD: shl.mi,v 1.9 2014/08/25 20:40:52 joerg Exp $
 #
 ./usr/tests/lib/csu/h_initfini3_dso.so		tests-lib-tests		atf
 ./usr/tests/lib/csu/h_initfini3_dso.so.1	tests-lib-tests		atf
@@ -16,9 +16,11 @@
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso1/libh_helper_symver_dso.so.1	tests-libexec-tests	atf
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2/libh_helper_symver_dso.so	tests-libexec-tests	atf
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2/libh_helper_symver_dso.so.1	tests-libexec-tests	atf
-./usr/tests/libexec/ld.elf_so/libh_helper_dso1.so	tests-libexec-tests	atf
-./usr/tests/libexec/ld.elf_so/libh_helper_dso1.so.1	tests-libexec-tests	atf
-./usr/tests/libexec/ld.elf_so/libh_helper_dso2.so	tests-libexec-tests	atf
-./usr/tests/libexec/ld.elf_so/libh_helper_dso2.so.1	tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_dso1.so				tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_dso1.so.1				tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_dso2.so				tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_dso2.so.1				tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_ifunc_dso.so				tests-libexec-tests	atf
+./usr/tests/libexec/ld.elf_so/libh_helper_ifunc_dso.so.1			tests-libexec-tests	atf
 ./usr/tests/util/id/libfake.so.0		tests-obsolete		obsolete
 ./usr/tests/util/id/libfake.so.0.0		tests-obsolete		obsolete

Index: src/libexec/ld.elf_so/headers.c
diff -u src/libexec/ld.elf_so/headers.c:1.54 src/libexec/ld.elf_so/headers.c:1.55
--- src/libexec/ld.elf_so/headers.c:1.54	Fri Mar  7 01:27:14 2014
+++ src/libexec/ld.elf_so/headers.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: headers.c,v 1.54 2014/03/07 01:27:14 matt Exp $	 */
+/*	$NetBSD: headers.c,v 1.55 2014/08/25 20:40:52 joerg Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: headers.c,v 1.54 2014/03/07 01:27:14 matt Exp $");
+__RCSID("$NetBSD: headers.c,v 1.55 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -232,8 +232,7 @@ _rtld_digest_dynamic(const char *execnam
 
 #ifdef HAVE_INITFINI_ARRAY
 		case DT_INIT_ARRAY:
-			obj->init_array =
-			    (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
+			obj->init_array = (Elf_Addr *)obj->relocbase + dynp->d_un.d_ptr;
 			dbg(("headers: DT_INIT_ARRAY at %p",
 			    obj->init_array));
 			break;
@@ -252,7 +251,7 @@ _rtld_digest_dynamic(const char *execnam
 #ifdef HAVE_INITFINI_ARRAY
 		case DT_FINI_ARRAY:
 			obj->fini_array =
-			    (fptr_t *)(obj->relocbase + dynp->d_un.d_ptr);
+			    (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
 			dbg(("headers: DT_FINI_ARRAY at %p",
 			    obj->fini_array));
 			break;
@@ -345,21 +344,10 @@ _rtld_digest_dynamic(const char *execnam
 			obj->relalim = obj->pltrela;
 	}
 
-#if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
 	if (init != 0)
-		obj->init = (void (*)(void))
-		    _rtld_function_descriptor_alloc(obj, NULL, init);
+		obj->init = (Elf_Addr)obj->relocbase + init;
 	if (fini != 0)
-		obj->fini = (void (*)(void))
-		    _rtld_function_descriptor_alloc(obj, NULL, fini);
-#else
-	if (init != 0)
-		obj->init = (void (*)(void))
-		    (obj->relocbase + init);
-	if (fini != 0)
-		obj->fini = (void (*)(void))
-		    (obj->relocbase + fini);
-#endif
+		obj->fini = (Elf_Addr)obj->relocbase + fini;
 
 	if (dyn_rpath != NULL) {
 		_rtld_add_paths(execname, &obj->rpaths, obj->strtab +

Index: src/libexec/ld.elf_so/reloc.c
diff -u src/libexec/ld.elf_so/reloc.c:1.106 src/libexec/ld.elf_so/reloc.c:1.107
--- src/libexec/ld.elf_so/reloc.c:1.106	Fri Jan  6 10:38:56 2012
+++ src/libexec/ld.elf_so/reloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $	 */
+/*	$NetBSD: reloc.c,v 1.107 2014/08/25 20:40:52 joerg Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -39,7 +39,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: reloc.c,v 1.106 2012/01/06 10:38:56 skrll Exp $");
+__RCSID("$NetBSD: reloc.c,v 1.107 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -226,3 +226,16 @@ _rtld_relocate_objects(Obj_Entry *first,
 
 	return 0;
 }
+
+Elf_Addr
+_rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def)
+{
+	Elf_Addr target;
+
+	_rtld_shared_exit();
+	target = _rtld_call_function_addr(obj,
+	    (Elf_Addr)obj->relocbase + def->st_value);
+	_rtld_shared_enter();
+
+	return target;
+}

Index: src/libexec/ld.elf_so/rtld.c
diff -u src/libexec/ld.elf_so/rtld.c:1.173 src/libexec/ld.elf_so/rtld.c:1.174
--- src/libexec/ld.elf_so/rtld.c:1.173	Tue Mar 18 16:05:34 2014
+++ src/libexec/ld.elf_so/rtld.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.c,v 1.173 2014/03/18 16:05:34 joerg Exp $	 */
+/*	$NetBSD: rtld.c,v 1.174 2014/08/25 20:40:52 joerg Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.173 2014/03/18 16:05:34 joerg Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.174 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -136,25 +136,25 @@ static void _rtld_unref_dag(Obj_Entry *)
 static Obj_Entry *_rtld_obj_from_addr(const void *);
 
 static inline void
-_rtld_call_initfini_function(fptr_t func, sigset_t *mask)
+_rtld_call_initfini_function(const Obj_Entry *obj, Elf_Addr func, sigset_t *mask)
 {
 	_rtld_exclusive_exit(mask);
-	(*func)();
+	_rtld_call_function_void(obj, func);
 	_rtld_exclusive_enter(mask);
 }
 
 static void
 _rtld_call_fini_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
 {
-	if (obj->fini_arraysz == 0 && (obj->fini == NULL || obj->fini_called)) {
-		    	return;
-	}
-	if (obj->fini != NULL && !obj->fini_called) {
+	if (obj->fini_arraysz == 0 && (obj->fini == 0 || obj->fini_called))
+		return;
+
+	if (obj->fini != 0 && !obj->fini_called) {
 		dbg (("calling fini function %s at %p%s", obj->path,
 		    (void *)obj->fini,
 		    obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
 		obj->fini_called = 1;
-		_rtld_call_initfini_function(obj->fini, mask);
+		_rtld_call_initfini_function(obj, obj->fini, mask);
 	}
 #ifdef HAVE_INITFINI_ARRAY
 	/*
@@ -164,12 +164,12 @@ _rtld_call_fini_function(Obj_Entry *obj,
 	 * the loop.
 	 */
 	while (obj->fini_arraysz > 0 && _rtld_objgen == cur_objgen) {
-		fptr_t fini = *obj->fini_array++;
+		Elf_Addr fini = *obj->fini_array++;
 		obj->fini_arraysz--;
 		dbg (("calling fini array function %s at %p%s", obj->path,
 		    (void *)fini,
 		    obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
-		_rtld_call_initfini_function(fini, mask);
+		_rtld_call_initfini_function(obj, fini, mask);
 	}
 #endif /* HAVE_INITFINI_ARRAY */
 }
@@ -230,15 +230,15 @@ restart:
 static void
 _rtld_call_init_function(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen)
 {
-	if (obj->init_arraysz == 0 && (obj->init_called || obj->init == NULL)) {
+	if (obj->init_arraysz == 0 && (obj->init_called || obj->init == 0))
 		return;
-	}
-	if (!obj->init_called && obj->init != NULL) {
+
+	if (!obj->init_called && obj->init != 0) {
 		dbg (("calling init function %s at %p%s",
 		    obj->path, (void *)obj->init,
 		    obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
 		obj->init_called = 1;
-		_rtld_call_initfini_function(obj->init, mask);
+		_rtld_call_initfini_function(obj, obj->init, mask);
 	}
 
 #ifdef HAVE_INITFINI_ARRAY
@@ -249,12 +249,12 @@ _rtld_call_init_function(Obj_Entry *obj,
 	 * the loop.
 	 */
 	while (obj->init_arraysz > 0 && _rtld_objgen == cur_objgen) {
-		fptr_t init = *obj->init_array++;
+		Elf_Addr init = *obj->init_array++;
 		obj->init_arraysz--;
 		dbg (("calling init_array function %s at %p%s",
 		    obj->path, (void *)init,
 		    obj->z_initfirst ? " (DF_1_INITFIRST)" : ""));
-		_rtld_call_initfini_function(init, mask);
+		_rtld_call_initfini_function(obj, init, mask);
 	}
 #endif /* HAVE_INITFINI_ARRAY */
 }
@@ -1176,6 +1176,17 @@ do_dlsym(void *handle, const char *name,
 
 	if (def != NULL) {
 		void *p;
+
+		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+#ifdef __HAVE_FUNCTION_DESCRIPTORS
+			lookup_mutex_exit();
+			_rtld_shared_enter();
+#endif
+			p = (void *)_rtld_resolve_ifunc(defobj, def);
+			_rtld_shared_exit();
+			return p;
+		}
+
 #ifdef __HAVE_FUNCTION_DESCRIPTORS
 		if (ELF_ST_TYPE(def->st_info) == STT_FUNC) {
 			p = (void *)_rtld_function_descriptor_alloc(defobj,

Index: src/libexec/ld.elf_so/rtld.h
diff -u src/libexec/ld.elf_so/rtld.h:1.119 src/libexec/ld.elf_so/rtld.h:1.120
--- src/libexec/ld.elf_so/rtld.h:1.119	Sat Aug 23 18:05:33 2014
+++ src/libexec/ld.elf_so/rtld.h	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.h,v 1.119 2014/08/23 18:05:33 joerg Exp $	 */
+/*	$NetBSD: rtld.h,v 1.120 2014/08/25 20:40:52 joerg Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -193,8 +193,8 @@ typedef struct Struct_Obj_Entry {
 	Search_Path    *rpaths;		/* Search path specified in object */
 	Needed_Entry   *needed;		/* Shared objects needed by this (%) */
 
-	fptr_t		init;		/* Initialization function to call */
-	fptr_t		fini;		/* Termination function to call */
+	Elf_Addr	init;		/* Initialization function to call */
+	Elf_Addr	fini;		/* Termination function to call */
 
 	/*
 	 * BACKWARDS COMPAT Entry points for dlopen() and friends.
@@ -288,9 +288,9 @@ typedef struct Struct_Obj_Entry {
 	int		vertabnum;	/* Number of entries in vertab */
 
 	/* init_array/fini_array */
-	fptr_t		*init_array;	/* start of init array */
+	Elf_Addr	*init_array;	/* start of init array */
 	size_t		init_arraysz;	/* # of entries in it */
-	fptr_t		*fini_array;	/* start of fini array */
+	Elf_Addr	*fini_array;	/* start of fini array */
 	size_t		fini_arraysz;	/* # of entries in it */
 #ifdef __ARM_EABI__
 	void		*exidx_start;
@@ -404,6 +404,7 @@ int _rtld_relocate_nonplt_objects(Obj_En
 int _rtld_relocate_plt_lazy(const Obj_Entry *);
 int _rtld_relocate_plt_objects(const Obj_Entry *);
 void _rtld_setup_pltgot(const Obj_Entry *);
+Elf_Addr _rtld_resolve_ifunc(const Obj_Entry *, const Elf_Sym *);
 
 /* search.c */
 Obj_Entry *_rtld_load_library(const char *, const Obj_Entry *, int);
@@ -479,6 +480,20 @@ Obj_Entry *_rtld_obj_new(void);
 Elf_Addr _rtld_function_descriptor_alloc(const Obj_Entry *,
     const Elf_Sym *, Elf_Addr);
 const void *_rtld_function_descriptor_function(const void *);
+
+void _rtld_call_function_void(const Obj_Entry *, Elf_Addr);
+Elf_Addr _rtld_call_function_addr(const Obj_Entry *, Elf_Addr);
+#else
+static inline void
+_rtld_call_function_void(const Obj_Entry *obj, Elf_Addr addr)
+{
+	((void (*)(void))addr)();
+}
+static inline Elf_Addr
+_rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr addr)
+{
+	return ((Elf_Addr(*)(void))addr)();
+}
 #endif /* __HAVE_FUNCTION_DESCRIPTORS */
 
 #endif /* _RTLD_SOURCE */

Index: src/libexec/ld.elf_so/arch/aarch64/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.1 src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.2
--- src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.1	Sun Aug 10 05:47:37 2014
+++ src/libexec/ld.elf_so/arch/aarch64/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */
+/* $NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.1 2014/08/10 05:47:37 matt Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.2 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -222,7 +222,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 	if (*where != new_value)

Index: src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c
diff -u src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c:1.40 src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c:1.41
--- src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c:1.40	Thu Mar 31 15:30:31 2011
+++ src/libexec/ld.elf_so/arch/alpha/alpha_reloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: alpha_reloc.c,v 1.40 2011/03/31 15:30:31 skrll Exp $	*/
+/*	$NetBSD: alpha_reloc.c,v 1.41 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -62,7 +62,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: alpha_reloc.c,v 1.40 2011/03/31 15:30:31 skrll Exp $");
+__RCSID("$NetBSD: alpha_reloc.c,v 1.41 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -376,7 +376,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 

Index: src/libexec/ld.elf_so/arch/arm/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/arm/mdreloc.c:1.37 src/libexec/ld.elf_so/arch/arm/mdreloc.c:1.38
--- src/libexec/ld.elf_so/arch/arm/mdreloc.c:1.37	Fri Nov 18 16:10:03 2011
+++ src/libexec/ld.elf_so/arch/arm/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,8 +1,8 @@
-/*	$NetBSD: mdreloc.c,v 1.37 2011/11/18 16:10:03 joerg Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.38 2014/08/25 20:40:52 joerg Exp $	*/
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.37 2011/11/18 16:10:03 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.38 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -286,7 +286,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
 	/* Set the Thumb bit, if needed.  */
 	if (ELF_ST_TYPE(def->st_info) == STT_ARM_TFUNC)
 		new_value |= 1;

Index: src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c
diff -u src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c:1.42 src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c:1.43
--- src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c:1.42	Fri Jan  6 10:38:57 2012
+++ src/libexec/ld.elf_so/arch/hppa/hppa_reloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hppa_reloc.c,v 1.42 2012/01/06 10:38:57 skrll Exp $	*/
+/*	$NetBSD: hppa_reloc.c,v 1.43 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2004 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: hppa_reloc.c,v 1.42 2012/01/06 10:38:57 skrll Exp $");
+__RCSID("$NetBSD: hppa_reloc.c,v 1.43 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <stdlib.h>
@@ -656,9 +656,19 @@ _rtld_relocate_plt_object(const Obj_Entr
 		if (__predict_false(def == &_rtld_sym_zero))
 			return 0;
 
-		func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
-		    rela->r_addend);
-		func_sl = (Elf_Addr)(defobj->pltgot);
+		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+			if (tp == NULL)
+				return 0;
+			Elf_Addr ptr = _rtld_resolve_ifunc(defobj, def);
+			assert(RTLD_IS_PLABEL(ptr));
+			hppa_plabel *label = RTLD_GET_PLABEL(ptr);
+			func_pc = label->hppa_plabel_pc;
+			func_sl = label->hppa_plabel_sl;
+		} else {
+			func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
+			    rela->r_addend);
+			func_sl = (Elf_Addr)(defobj->pltgot);
+		}
 
 		rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
 		    defobj->strtab + def->st_name,
@@ -710,3 +720,29 @@ _rtld_relocate_plt_objects(const Obj_Ent
 	}
 	return 0;
 }
+
+void
+_rtld_call_function_void(const Obj_Entry *obj, Elf_Addr ptr)
+{
+	volatile hppa_plabel plabel;
+	void (*f)(void);
+
+	plabel.hppa_plabel_pc = (Elf_Addr)ptr;
+	plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
+	f = (void (*)(void))RTLD_MAKE_PLABEL(&plabel);
+
+	f();
+}
+
+Elf_Addr
+_rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr ptr)
+{
+	volatile hppa_plabel plabel;
+	Elf_Addr (*f)(void);
+
+	plabel.hppa_plabel_pc = (Elf_Addr)ptr;
+	plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
+	f = (Elf_Addr (*)(void))RTLD_MAKE_PLABEL(&plabel);
+
+	return f();
+}

Index: src/libexec/ld.elf_so/arch/i386/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/i386/mdreloc.c:1.35 src/libexec/ld.elf_so/arch/i386/mdreloc.c:1.36
--- src/libexec/ld.elf_so/arch/i386/mdreloc.c:1.35	Wed Nov  7 07:24:46 2012
+++ src/libexec/ld.elf_so/arch/i386/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,8 +1,8 @@
-/*	$NetBSD: mdreloc.c,v 1.35 2012/11/07 07:24:46 apb Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.36 2014/08/25 20:40:52 joerg Exp $	*/
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.35 2012/11/07 07:24:46 apb Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.36 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -230,6 +230,14 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		target = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		target = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
+
 	target = (Elf_Addr)(defobj->relocbase + def->st_value);
 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
 	    defobj->strtab + def->st_name, (void *)*where, 

Index: src/libexec/ld.elf_so/arch/m68k/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/m68k/mdreloc.c:1.29 src/libexec/ld.elf_so/arch/m68k/mdreloc.c:1.30
--- src/libexec/ld.elf_so/arch/m68k/mdreloc.c:1.29	Tue Nov 22 15:25:28 2011
+++ src/libexec/ld.elf_so/arch/m68k/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,13 +1,13 @@
-/*	$NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:52 joerg Exp $	*/
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.29 2011/11/22 15:25:28 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -223,8 +223,14 @@ _rtld_relocate_plt_object(const Obj_Entr
 		return 0;
 
 	assert(rela->r_addend == 0);
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
-	    rela->r_addend);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
+		    rela->r_addend);
+	}
 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 	if (*where != new_value)

Index: src/libexec/ld.elf_so/arch/mips/mips_reloc.c
diff -u src/libexec/ld.elf_so/arch/mips/mips_reloc.c:1.62 src/libexec/ld.elf_so/arch/mips/mips_reloc.c:1.63
--- src/libexec/ld.elf_so/arch/mips/mips_reloc.c:1.62	Fri Mar 25 18:07:05 2011
+++ src/libexec/ld.elf_so/arch/mips/mips_reloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mips_reloc.c,v 1.62 2011/03/25 18:07:05 joerg Exp $	*/
+/*	$NetBSD: mips_reloc.c,v 1.63 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*
  * Copyright 1997 Michael L. Hitch <[email protected]>
@@ -30,7 +30,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mips_reloc.c,v 1.62 2011/03/25 18:07:05 joerg Exp $");
+__RCSID("$NetBSD: mips_reloc.c,v 1.63 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -487,7 +487,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
 	rdbg(("bind now/fixup in %s --> new=%p",
 	    defobj->strtab + def->st_name, (void *)new_value));
 	got[obj->local_gotno + sym - obj->gotsym] = new_value;

Index: src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c
diff -u src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.52 src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.53
--- src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c:1.52	Mon Jul 28 17:28:13 2014
+++ src/libexec/ld.elf_so/arch/powerpc/ppc_reloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ppc_reloc.c,v 1.52 2014/07/28 17:28:13 matt Exp $	*/
+/*	$NetBSD: ppc_reloc.c,v 1.53 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*-
  * Copyright (C) 1998	Tsubai Masanari
@@ -30,7 +30,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: ppc_reloc.c,v 1.52 2014/07/28 17:28:13 matt Exp $");
+__RCSID("$NetBSD: ppc_reloc.c,v 1.53 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <stdarg.h>
@@ -366,7 +366,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	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 --> new=%p", 
 	    defobj->strtab + def->st_name, (void *)value));
 

Index: src/libexec/ld.elf_so/arch/sh3/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/sh3/mdreloc.c:1.30 src/libexec/ld.elf_so/arch/sh3/mdreloc.c:1.31
--- src/libexec/ld.elf_so/arch/sh3/mdreloc.c:1.30	Fri Mar 25 18:07:06 2011
+++ src/libexec/ld.elf_so/arch/sh3/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,13 +1,13 @@
-/*	$NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.31 2014/08/25 20:40:52 joerg Exp $	*/
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.31 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.30 2011/03/25 18:07:06 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.31 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -282,7 +282,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	}
 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 	if (*where != new_value)

Index: src/libexec/ld.elf_so/arch/sparc/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.47 src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.48
--- src/libexec/ld.elf_so/arch/sparc/mdreloc.c:1.47	Thu Mar 31 12:47:01 2011
+++ src/libexec/ld.elf_so/arch/sparc/mdreloc.c	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mdreloc.c,v 1.47 2011/03/31 12:47:01 nakayama Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.48 2014/08/25 20:40:52 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.47 2011/03/31 12:47:01 nakayama Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.48 2014/08/25 20:40:52 joerg Exp $");
 #endif /* not lint */
 
 #include <errno.h>
@@ -448,7 +448,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	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 --> new=%p", 
 	    defobj->strtab + def->st_name, (void *)value));
 

Index: src/libexec/ld.elf_so/arch/sparc64/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.56 src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.57
--- src/libexec/ld.elf_so/arch/sparc64/mdreloc.c:1.56	Wed Apr  2 14:11:25 2014
+++ src/libexec/ld.elf_so/arch/sparc64/mdreloc.c	Mon Aug 25 20:40:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mdreloc.c,v 1.56 2014/04/02 14:11:25 martin Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.57 2014/08/25 20:40:53 joerg Exp $	*/
 
 /*-
  * Copyright (c) 2000 Eduardo Horvath.
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.56 2014/04/02 14:11:25 martin Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.57 2014/08/25 20:40:53 joerg Exp $");
 #endif /* not lint */
 
 #include <errno.h>
@@ -602,7 +602,13 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	value = (Elf_Addr)(defobj->relocbase + def->st_value);
+	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));
 

Index: src/libexec/ld.elf_so/arch/vax/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/vax/mdreloc.c:1.29 src/libexec/ld.elf_so/arch/vax/mdreloc.c:1.30
--- src/libexec/ld.elf_so/arch/vax/mdreloc.c:1.29	Fri Mar 21 01:43:33 2014
+++ src/libexec/ld.elf_so/arch/vax/mdreloc.c	Mon Aug 25 20:40:53 2014
@@ -1,13 +1,13 @@
-/*	$NetBSD: mdreloc.c,v 1.29 2014/03/21 01:43:33 matt Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:53 joerg Exp $	*/
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.29 2014/03/21 01:43:33 matt Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:53 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.29 2014/03/21 01:43:33 matt Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.30 2014/08/25 20:40:53 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -166,8 +166,14 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
-	    rela->r_addend);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
+		    rela->r_addend);
+	}
 	rdbg(("bind now/fixup pltgot %p in %s --> old=%p new=%p", where,
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 	if (*where != new_value)

Index: src/libexec/ld.elf_so/arch/x86_64/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/x86_64/mdreloc.c:1.40 src/libexec/ld.elf_so/arch/x86_64/mdreloc.c:1.41
--- src/libexec/ld.elf_so/arch/x86_64/mdreloc.c:1.40	Fri Mar 25 18:07:07 2011
+++ src/libexec/ld.elf_so/arch/x86_64/mdreloc.c	Mon Aug 25 20:40:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mdreloc.c,v 1.40 2011/03/25 18:07:07 joerg Exp $	*/
+/*	$NetBSD: mdreloc.c,v 1.41 2014/08/25 20:40:53 joerg Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -68,7 +68,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.40 2011/03/25 18:07:07 joerg Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.41 2014/08/25 20:40:53 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -313,8 +313,15 @@ _rtld_relocate_plt_object(const Obj_Entr
 	if (__predict_false(def == &_rtld_sym_zero))
 		return 0;
 
-	new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
-	    rela->r_addend);
+	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+		if (tp == NULL)
+			return 0;
+		new_value = _rtld_resolve_ifunc(defobj, def);
+	} else {
+		new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
+		    rela->r_addend);
+	}
+
 	rdbg(("bind now/fixup in %s --> old=%p new=%p", 
 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
 	if (*where != new_value)

Index: src/sys/sys/cdefs_elf.h
diff -u src/sys/sys/cdefs_elf.h:1.44 src/sys/sys/cdefs_elf.h:1.45
--- src/sys/sys/cdefs_elf.h:1.44	Tue May 13 19:58:23 2014
+++ src/sys/sys/cdefs_elf.h	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: cdefs_elf.h,v 1.44 2014/05/13 19:58:23 christos Exp $	*/
+/*	$NetBSD: cdefs_elf.h,v 1.45 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*
  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
@@ -106,6 +106,18 @@
 
 #endif /* !__STDC__ */
 
+#if __arm__
+#define __ifunc(name, resolver) \
+	__asm(".globl	" _C_LABEL_STRING(#name) "\n" \
+	      ".type	" _C_LABEL_STRING(#name) ", %gnu_indirect_function\n" \
+	      ".set	" _C_LABEL_STRING(#name) ", " _C_LABEL_STRING(#resolver))
+#else
+#define __ifunc(name, resolver) \
+	__asm(".globl	" _C_LABEL_STRING(#name) "\n" \
+	      ".type	" _C_LABEL_STRING(#name) ", @gnu_indirect_function\n" \
+	      ".set	" _C_LABEL_STRING(#name) ", " _C_LABEL_STRING(#resolver))
+#endif
+
 #if __STDC__
 #define	__SECTIONSTRING(_sec, _str)					\
 	__asm(".pushsection " #_sec "\n"				\

Index: src/sys/sys/exec_elf.h
diff -u src/sys/sys/exec_elf.h:1.142 src/sys/sys/exec_elf.h:1.143
--- src/sys/sys/exec_elf.h:1.142	Tue Aug 19 07:26:45 2014
+++ src/sys/sys/exec_elf.h	Mon Aug 25 20:40:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec_elf.h,v 1.142 2014/08/19 07:26:45 matt Exp $	*/
+/*	$NetBSD: exec_elf.h,v 1.143 2014/08/25 20:40:52 joerg Exp $	*/
 
 /*-
  * Copyright (c) 1994 The NetBSD Foundation, Inc.
@@ -516,6 +516,7 @@ typedef struct {
 #define STT_NUM			7
 
 #define STT_LOOS		10	/* Operating system specific range */
+#define STT_GNU_IFUNC		10	/* GNU extension: indirect function */
 #define STT_HIOS		12
 #define STT_LOPROC		13	/* Processor-specific range */
 #define STT_HIPROC		15

Index: src/tests/libexec/ld.elf_so/Makefile
diff -u src/tests/libexec/ld.elf_so/Makefile:1.7 src/tests/libexec/ld.elf_so/Makefile:1.8
--- src/tests/libexec/ld.elf_so/Makefile:1.7	Sun Jul  3 15:28:25 2011
+++ src/tests/libexec/ld.elf_so/Makefile	Mon Aug 25 20:40:53 2014
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.7 2011/07/03 15:28:25 mrg Exp $
+# $NetBSD: Makefile,v 1.8 2014/08/25 20:40:53 joerg Exp $
 #
 
 NOMAN=		# defined
@@ -8,16 +8,19 @@ NOMAN=		# defined
 .if ${MKPIC} != "no"
 
 SUBDIR+=	helper_dso1 .WAIT helper_dso2 .WAIT \
+		helper_ifunc_dso \
 		helper_symver_dso0 .WAIT helper_symver_dso1 .WAIT \
 		helper_symver_dso2 .WAIT \
 		data
 
 TESTSDIR=	${TESTSBASE}/libexec/ld.elf_so
 
-TESTS_C+=	t_dlerror-cleared t_dlerror-false t_dlinfo t_dlvsym
+TESTS_C+=	t_dlerror-cleared t_dlerror-false t_dlinfo t_dlvsym t_ifunc
 
 LDADD.t_dlerror-false=	-Wl,-rpath,/var/nonexistent/lib
 LDADD.t_dlvsym=		-Wl,-rpath,${TESTSDIR}/h_helper_symver_dso2
+LDADD.t_ifunc=		-Wl,-rpath,${TESTSDIR} -lutil
+DPADD.t_ifunc=		${LIBUTIL}
 
 TESTS_SH+=		t_df_1_noopen t_dl_symver
 
@@ -29,6 +32,11 @@ PROGS+=			h_df_1_noopen2
 SRCS.h_df_1_noopen2=	h_df_1_noopen.c
 LDADD.h_df_1_noopen2=	-lpthread
 
+PROGS+=			h_ifunc
+SRCS.h_ifunc=		h_ifunc.c
+IFUNCDIR!=		cd ${.CURDIR}/helper_ifunc_dso && ${PRINTOBJDIR}
+LDADD.h_ifunc=		-Wl,-rpath,${TESTSDIR} -L${IFUNCDIR} -lh_helper_ifunc_dso
+
 PROGS+=			h_locking
 SRCS.h_locking=		h_locking.c
 LDADD.h_locking=	-lpthread -Wl,--export-dynamic -Wl,-rpath,${TESTSDIR}

Added files:

Index: src/tests/libexec/ld.elf_so/h_ifunc.c
diff -u /dev/null src/tests/libexec/ld.elf_so/h_ifunc.c:1.1
--- /dev/null	Mon Aug 25 20:40:53 2014
+++ src/tests/libexec/ld.elf_so/h_ifunc.c	Mon Aug 25 20:40:53 2014
@@ -0,0 +1,43 @@
+/*	$NetBSD: h_ifunc.c,v 1.1 2014/08/25 20:40:53 joerg Exp $	*/
+
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+extern int ifunc(void);
+
+int
+main(int argc, char **argv)
+{
+
+	if (argc != 2)
+		return 1;
+	return ifunc() != atoi(argv[1]);
+}
Index: src/tests/libexec/ld.elf_so/t_ifunc.c
diff -u /dev/null src/tests/libexec/ld.elf_so/t_ifunc.c:1.1
--- /dev/null	Mon Aug 25 20:40:53 2014
+++ src/tests/libexec/ld.elf_so/t_ifunc.c	Mon Aug 25 20:40:53 2014
@@ -0,0 +1,92 @@
+/*	$NetBSD: t_ifunc.c,v 1.1 2014/08/25 20:40:53 joerg Exp $	*/
+
+/*
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <atf-c.h>
+#include <dlfcn.h>
+#include <util.h>
+
+#include "../../h_macros.h"
+
+ATF_TC(rtld_ifunc);
+
+ATF_TC_HEAD(rtld_ifunc, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "ifunc functions are resolved");
+}
+
+ATF_TC_BODY(rtld_ifunc, tc)
+{
+	const char *envstr[] = {
+	    "0", "1"
+	};
+	int expected_result[] = {
+	    0xdeadbeef, 0xbeefdead
+	};
+	void *handle;
+	int (*sym)(void);
+	int result;
+	const char *error;
+	size_t i;
+
+	for (i = 0; i < __arraycount(envstr); ++i) {
+		setenv("USE_IFUNC2", envstr[i], 1);
+
+		handle = dlopen("libh_helper_ifunc_dso.so", RTLD_LAZY);
+		error = dlerror();
+		ATF_CHECK(error == NULL);
+		ATF_CHECK(handle != NULL);
+
+		sym = dlsym(handle, "ifunc");
+		error = dlerror();
+		ATF_CHECK(error == NULL);
+		ATF_CHECK(sym != NULL);
+
+		result = (*sym)();
+		ATF_CHECK(result == expected_result[i]);
+
+		dlclose(handle);
+		error = dlerror();
+		ATF_CHECK(error == NULL);
+
+		char *command;
+		easprintf(&command, "%s/h_ifunc %d",
+		    atf_tc_get_config_var(tc, "srcdir"), expected_result[i]);
+		if (system(command) != EXIT_SUCCESS)
+			atf_tc_fail("Test failed; see output for details");
+		free(command);
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, rtld_ifunc);
+	return 0;
+}

Index: src/tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile
diff -u /dev/null src/tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile:1.1
--- /dev/null	Mon Aug 25 20:40:53 2014
+++ src/tests/libexec/ld.elf_so/helper_ifunc_dso/Makefile	Mon Aug 25 20:40:53 2014
@@ -0,0 +1,19 @@
+# $NetBSD: Makefile,v 1.1 2014/08/25 20:40:53 joerg Exp $
+
+.include <bsd.own.mk>
+
+LIB=			h_helper_ifunc_dso
+SRCS=			h_helper_ifunc.c
+
+LIBDIR=		${TESTSBASE}/libexec/ld.elf_so
+SHLIBDIR=	${TESTSBASE}/libexec/ld.elf_so
+SHLIB_MAJOR=	1
+
+MKSTATICLIB=	no
+MKPROFILE=	no
+MKPICINSTALL=	no
+MKLINT=		no
+
+NOMAN=		# defined
+
+.include <bsd.lib.mk>
Index: src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c
diff -u /dev/null src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c:1.1
--- /dev/null	Mon Aug 25 20:40:53 2014
+++ src/tests/libexec/ld.elf_so/helper_ifunc_dso/h_helper_ifunc.c	Mon Aug 25 20:40:53 2014
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Joerg Sonnenberger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+static int
+ifunc1(void)
+{
+	return 0xdeadbeef;
+}
+
+static int
+ifunc2(void)
+{
+	return 0xbeefdead;
+}
+
+static __attribute__((used))
+int (*resolve_ifunc(void))(void)
+{
+	const char *e = getenv("USE_IFUNC2");
+	return e && strcmp(e, "1") == 0 ? ifunc2 : ifunc1;
+}
+
+__ifunc(ifunc, resolve_ifunc);

Reply via email to