From owner-svn-src-stable-9@FreeBSD.ORG Wed Jan 4 16:43:29 2012 Return-Path: Delivered-To: svn-src-stable-9@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C1F311065700; Wed, 4 Jan 2012 16:43:29 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id ADE208FC08; Wed, 4 Jan 2012 16:43:29 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q04GhTBi087262; Wed, 4 Jan 2012 16:43:29 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q04GhTvb087251; Wed, 4 Jan 2012 16:43:29 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201201041643.q04GhTvb087251@svn.freebsd.org> From: Konstantin Belousov Date: Wed, 4 Jan 2012 16:43:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r229503 - in stable/9/libexec/rtld-elf: . amd64 arm i386 ia64 mips powerpc powerpc64 sparc64 X-BeenThere: svn-src-stable-9@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 9-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Jan 2012 16:43:29 -0000 Author: kib Date: Wed Jan 4 16:43:29 2012 New Revision: 229503 URL: http://svn.freebsd.org/changeset/base/229503 Log: MFC r228435: Add support for STT_GNU_IFUNC and R_MACHINE_IRELATIVE GNU extensions to rtld on 386 and amd64. MFC r228503: Postpone the resolution for irelative/ifunc right before initializers are called, and drop bind lock around calls to dispatcher. Use initlist to iterate over the objects instead of the ->next, due to drop of the bind lock in iteration. For i386/reloc.c:reloc_iresolve(), fix calculation of the dispatch function address for dso, by taking into account possible non-zero relocbase. MFC r228635 (by nwhitehorn): Fix RTLD on PowerPC after r228435. Changing the order of init_pltgot() caused the icache to be invalidated at the wrong time, resulting in an icache full of nonsense in the PLT section. Modified: stable/9/libexec/rtld-elf/amd64/reloc.c stable/9/libexec/rtld-elf/arm/reloc.c stable/9/libexec/rtld-elf/i386/reloc.c stable/9/libexec/rtld-elf/ia64/reloc.c stable/9/libexec/rtld-elf/mips/reloc.c stable/9/libexec/rtld-elf/powerpc/reloc.c stable/9/libexec/rtld-elf/powerpc64/reloc.c stable/9/libexec/rtld-elf/rtld.c stable/9/libexec/rtld-elf/rtld.h stable/9/libexec/rtld-elf/sparc64/reloc.c Directory Properties: stable/9/libexec/rtld-elf/ (props changed) Modified: stable/9/libexec/rtld-elf/amd64/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/amd64/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/amd64/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -344,11 +344,22 @@ reloc_plt(Obj_Entry *obj) for (rela = obj->pltrela; rela < relalim; rela++) { Elf_Addr *where; - assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT); - - /* Relocate the GOT slot pointing into the PLT. */ - where = (Elf_Addr *)(obj->relocbase + rela->r_offset); - *where += (Elf_Addr)obj->relocbase; + switch(ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + /* Relocate the GOT slot pointing into the PLT. */ + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + *where += (Elf_Addr)obj->relocbase; + break; + + case R_X86_64_IRELATIVE: + obj->irelative = true; + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } } return 0; } @@ -368,19 +379,98 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS const Elf_Sym *def; const Obj_Entry *defobj; - assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT); - where = (Elf_Addr *)(obj->relocbase + rela->r_offset); - def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL, - lockstate); - if (def == NULL) - return -1; - target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); - reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL, + lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + obj->gnu_ifunc = true; + continue; + } + target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); + reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); + break; + + case R_X86_64_IRELATIVE: + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } } obj->jmpslots_done = true; return 0; } +int +reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (!obj->irelative) + return (0); + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where, target, *ptr; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + break; + + case R_X86_64_IRELATIVE: + ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + lock_release(rtld_bind_lock, lockstate); + target = ((Elf_Addr (*)(void))ptr)(); + wlock_acquire(rtld_bind_lock, lockstate); + *where = target; + break; + } + } + obj->irelative = false; + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (!obj->gnu_ifunc) + return (0); + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL, + lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) + continue; + lock_release(rtld_bind_lock, lockstate); + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); + wlock_acquire(rtld_bind_lock, lockstate); + reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); + break; + } + } + obj->gnu_ifunc = false; + return (0); +} + void allocate_initial_tls(Obj_Entry *objs) { Modified: stable/9/libexec/rtld-elf/arm/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/arm/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/arm/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -337,6 +337,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS return (0); } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, const Obj_Entry *obj, const Elf_Rel *rel) Modified: stable/9/libexec/rtld-elf/i386/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/i386/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/i386/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -298,13 +298,24 @@ reloc_plt(Obj_Entry *obj) rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); for (rel = obj->pltrel; rel < rellim; rel++) { - Elf_Addr *where; + Elf_Addr *where/*, val*/; - assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT); - - /* Relocate the GOT slot pointing into the PLT. */ - where = (Elf_Addr *)(obj->relocbase + rel->r_offset); - *where += (Elf_Addr)obj->relocbase; + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + /* Relocate the GOT slot pointing into the PLT. */ + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where += (Elf_Addr)obj->relocbase; + break; + + case R_386_IRELATIVE: + obj->irelative = true; + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + ELF_R_TYPE(rel->r_info)); + return (-1); + } } return 0; } @@ -324,19 +335,95 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS const Elf_Sym *def; const Obj_Entry *defobj; - assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT); - where = (Elf_Addr *)(obj->relocbase + rel->r_offset); - def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, - lockstate); - if (def == NULL) - return -1; - target = (Elf_Addr)(defobj->relocbase + def->st_value); - reloc_jmpslot(where, target, defobj, obj, rel); + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, + lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + obj->gnu_ifunc = true; + continue; + } + target = (Elf_Addr)(defobj->relocbase + def->st_value); + reloc_jmpslot(where, target, defobj, obj, rel); + break; + + case R_386_IRELATIVE: + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + ELF_R_TYPE(rel->r_info)); + return (-1); + } } + obj->jmpslots_done = true; return 0; } +int +reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + Elf_Addr *where, target; + + if (!obj->irelative) + return (0); + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_IRELATIVE: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + lock_release(rtld_bind_lock, lockstate); + target = ((Elf_Addr (*)(void))(obj->relocbase + *where))(); + wlock_acquire(rtld_bind_lock, lockstate); + *where = target; + break; + } + } + obj->irelative = false; + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + if (!obj->gnu_ifunc) + return (0); + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, + lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) + continue; + lock_release(rtld_bind_lock, lockstate); + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); + wlock_acquire(rtld_bind_lock, lockstate); + reloc_jmpslot(where, target, defobj, obj, rel); + break; + } + } + + obj->gnu_ifunc = false; + return (0); +} + void allocate_initial_tls(Obj_Entry *objs) { Modified: stable/9/libexec/rtld-elf/ia64/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/ia64/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/ia64/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -435,6 +435,22 @@ reloc_plt(Obj_Entry *obj) return 0; } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + /* Relocate the jump slots in an object. */ int reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) Modified: stable/9/libexec/rtld-elf/mips/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/mips/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/mips/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -498,6 +498,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS return (0); } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, const Obj_Entry *obj, const Elf_Rel *rel) Modified: stable/9/libexec/rtld-elf/powerpc/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/powerpc/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/powerpc/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -370,7 +370,7 @@ reloc_plt_object(Obj_Entry *obj, const E /* - * The icache will be sync'd in init_pltgot, which is called + * The icache will be sync'd in reloc_plt, which is called * after all the slots have been updated */ @@ -386,6 +386,7 @@ reloc_plt(Obj_Entry *obj) { const Elf_Rela *relalim; const Elf_Rela *rela; + int N = obj->pltrelasize / sizeof(Elf_Rela); if (obj->pltrelasize != 0) { @@ -400,6 +401,13 @@ reloc_plt(Obj_Entry *obj) } } + /* + * Sync the icache for the byte range represented by the + * trampoline routines and call slots. + */ + if (obj->pltgot != NULL) + __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); + return (0); } @@ -508,6 +516,21 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr return (target); } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} /* * Setup the plt glue routines. @@ -584,10 +607,9 @@ init_pltgot(Obj_Entry *obj) pltresolve[4] |= _ppc_la(obj); /* - * Sync the icache for the byte range represented by the - * trampoline routines and call slots. + * The icache will be sync'd in reloc_plt, which is called + * after all the slots have been updated */ - __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); } void Modified: stable/9/libexec/rtld-elf/powerpc64/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/powerpc64/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/powerpc64/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -459,6 +459,22 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr return (target); } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + void init_pltgot(Obj_Entry *obj) { Modified: stable/9/libexec/rtld-elf/rtld.c ============================================================================== --- stable/9/libexec/rtld-elf/rtld.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/rtld.c Wed Jan 4 16:43:29 2012 (r229503) @@ -116,6 +116,8 @@ static void objlist_push_tail(Objlist *, static void objlist_remove(Objlist *, Obj_Entry *); static void *path_enumerate(const char *, path_enum_proc, void *); static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, RtldLockState *); +static int resolve_objects_ifunc(Obj_Entry *first, bool bind_now, + RtldLockState *lockstate); static int rtld_dirname(const char *, char *); static int rtld_dirname_abs(const char *, char *); static void rtld_exit(void); @@ -513,6 +515,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, NULL) == -1) die(); + if (resolve_objects_ifunc(obj_main, + ld_bind_now != NULL && *ld_bind_now != '\0', NULL) == -1) + die(); + dbg("doing copy relocations"); if (do_copy_relocations(obj_main) == -1) die(); @@ -561,6 +567,17 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_ return (func_ptr_type) obj_main->entry; } +void * +rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def) +{ + void *ptr; + Elf_Addr target; + + ptr = (void *)make_function_pointer(def, obj); + target = ((Elf_Addr (*)(void))ptr)(); + return ((void *)target); +} + Elf_Addr _rtld_bind(Obj_Entry *obj, Elf_Size reloff) { @@ -584,8 +601,10 @@ _rtld_bind(Obj_Entry *obj, Elf_Size relo &lockstate); if (def == NULL) die(); - - target = (Elf_Addr)(defobj->relocbase + def->st_value); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); + else + target = (Elf_Addr)(defobj->relocbase + def->st_value); dbg("\"%s\" in \"%s\" ==> %p in \"%s\"", defobj->strtab + def->st_name, basename(obj->path), @@ -1944,6 +1963,10 @@ relocate_objects(Obj_Entry *first, bool } } + + /* Set the special PLT or GOT entries. */ + init_pltgot(obj); + /* Process the PLT relocations. */ if (reloc_plt(obj) == -1) return -1; @@ -1952,7 +1975,6 @@ relocate_objects(Obj_Entry *first, bool if (reloc_jmpslots(obj, lockstate) == -1) return -1; - /* * Set up the magic number and version in the Obj_Entry. These * were checked in the crt1.o from the original ElfKit, so we @@ -1960,12 +1982,55 @@ relocate_objects(Obj_Entry *first, bool */ obj->magic = RTLD_MAGIC; obj->version = RTLD_VERSION; - - /* Set the special PLT or GOT entries. */ - init_pltgot(obj); } - return 0; + return (0); +} + +/* + * The handling of R_MACHINE_IRELATIVE relocations and jumpslots + * referencing STT_GNU_IFUNC symbols is postponed till the other + * relocations are done. The indirect functions specified as + * ifunc are allowed to call other symbols, so we need to have + * objects relocated before asking for resolution from indirects. + * + * The R_MACHINE_IRELATIVE slots are resolved in greedy fashion, + * instead of the usual lazy handling of PLT slots. It is + * consistent with how GNU does it. + */ +static int +resolve_object_ifunc(Obj_Entry *obj, bool bind_now, RtldLockState *lockstate) +{ + if (obj->irelative && reloc_iresolve(obj, lockstate) == -1) + return (-1); + if ((obj->bind_now || bind_now) && obj->gnu_ifunc && + reloc_gnu_ifunc(obj, lockstate) == -1) + return (-1); + return (0); +} + +static int +resolve_objects_ifunc(Obj_Entry *first, bool bind_now, RtldLockState *lockstate) +{ + Obj_Entry *obj; + + for (obj = first; obj != NULL; obj = obj->next) { + if (resolve_object_ifunc(obj, bind_now, lockstate) == -1) + return (-1); + } + return (0); +} + +static int +initlist_objects_ifunc(Objlist *list, bool bind_now, RtldLockState *lockstate) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, list, link) { + if (resolve_object_ifunc(elm->obj, bind_now, lockstate) == -1) + return (-1); + } + return (0); } /* @@ -2170,6 +2235,16 @@ dlopen(const char *name, int mode) mode & (RTLD_MODEMASK | RTLD_GLOBAL))); } +static void +dlopen_cleanup(Obj_Entry *obj) +{ + + obj->dl_refcount--; + unref_dag(obj); + if (obj->refcount == 0) + unload_object(obj); +} + static Obj_Entry * dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode) { @@ -2208,10 +2283,7 @@ dlopen_object(const char *name, Obj_Entr goto trace; if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK) == RTLD_NOW, &obj_rtld, &lockstate)) == -1) { - obj->dl_refcount--; - unref_dag(obj); - if (obj->refcount == 0) - unload_object(obj); + dlopen_cleanup(obj); obj = NULL; } else { /* Make list of init functions to call. */ @@ -2245,6 +2317,14 @@ dlopen_object(const char *name, Obj_Entr map_stacks_exec(&lockstate); + if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW, + &lockstate) == -1) { + objlist_clear(&initlist); + dlopen_cleanup(obj); + lock_release(rtld_bind_lock, &lockstate); + return (NULL); + } + /* Call the init functions. */ objlist_call_init(&initlist, &lockstate); objlist_clear(&initlist); @@ -2376,9 +2456,11 @@ do_dlsym(void *handle, const char *name, * the relocated value of the symbol. */ if (ELF_ST_TYPE(def->st_info) == STT_FUNC) - return make_function_pointer(def, defobj); + return (make_function_pointer(def, defobj)); + else if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) + return (rtld_resolve_ifunc(defobj, def)); else - return defobj->relocbase + def->st_value; + return (defobj->relocbase + def->st_value); } _rtld_error("Undefined symbol \"%s\"", name); @@ -2822,6 +2904,8 @@ get_program_var_addr(const char *name, R if (ELF_ST_TYPE(req.sym_out->st_info) == STT_FUNC) return ((const void **)make_function_pointer(req.sym_out, req.defobj_out)); + else if (ELF_ST_TYPE(req.sym_out->st_info) == STT_GNU_IFUNC) + return ((const void **)rtld_resolve_ifunc(req.defobj_out, req.sym_out)); else return ((const void **)(req.defobj_out->relocbase + req.sym_out->st_value)); @@ -3088,6 +3172,7 @@ symlook_obj1(SymLook *req, const Obj_Ent case STT_FUNC: case STT_NOTYPE: case STT_OBJECT: + case STT_GNU_IFUNC: if (symp->st_value == 0) continue; /* fallthrough */ Modified: stable/9/libexec/rtld-elf/rtld.h ============================================================================== --- stable/9/libexec/rtld-elf/rtld.h Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/rtld.h Wed Jan 4 16:43:29 2012 (r229503) @@ -230,6 +230,8 @@ typedef struct Struct_Obj_Entry { bool on_fini_list: 1; /* Object is already on fini list. */ bool dag_inited : 1; /* Object has its DAG initialized. */ bool filtees_loaded : 1; /* Filtees loaded */ + bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */ + bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ @@ -317,6 +319,7 @@ void lockdflt_init(void); void obj_free(Obj_Entry *); Obj_Entry *obj_new(void); void _rtld_bind_start(void); +void *rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def); void symlook_init(SymLook *, const char *); int symlook_obj(SymLook *, const Obj_Entry *); void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); @@ -334,6 +337,8 @@ int do_copy_relocations(Obj_Entry *); int reloc_non_plt(Obj_Entry *, Obj_Entry *, struct Struct_RtldLockState *); int reloc_plt(Obj_Entry *); int reloc_jmpslots(Obj_Entry *, struct Struct_RtldLockState *); +int reloc_iresolve(Obj_Entry *, struct Struct_RtldLockState *); +int reloc_gnu_ifunc(Obj_Entry *, struct Struct_RtldLockState *); void allocate_initial_tls(Obj_Entry *); #endif /* } */ Modified: stable/9/libexec/rtld-elf/sparc64/reloc.c ============================================================================== --- stable/9/libexec/rtld-elf/sparc64/reloc.c Wed Jan 4 16:43:08 2012 (r229502) +++ stable/9/libexec/rtld-elf/sparc64/reloc.c Wed Jan 4 16:43:29 2012 (r229503) @@ -550,6 +550,22 @@ reloc_jmpslots(Obj_Entry *obj, RtldLockS return (0); } +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + Elf_Addr reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj, const Obj_Entry *refobj, const Elf_Rel *rel)