Date: Sat, 17 Dec 2011 09:09:24 -0600 From: Nathan Whitehorn <nwhitehorn@freebsd.org> To: Konstantin Belousov <kib@FreeBSD.org> Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org, powerpc@freebsd.org Subject: Re: svn commit: r228435 - in head/libexec/rtld-elf: . amd64 arm i386 ia64 mips powerpc powerpc64 sparc64 Message-ID: <4EECB0A4.504@freebsd.org> In-Reply-To: <201112121103.pBCB3FuT097580@svn.freebsd.org> References: <201112121103.pBCB3FuT097580@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
This broke PowerPC really, really badly. Basically every dynamically-linked executable dies with an illegal instruction trap. -Nathan On 12/12/11 05:03, Konstantin Belousov wrote: > Author: kib > Date: Mon Dec 12 11:03:14 2011 > New Revision: 228435 > URL: http://svn.freebsd.org/changeset/base/228435 > > Log: > Add support for STT_GNU_IFUNC and R_MACHINE_IRELATIVE GNU extensions to > rtld on 386 and amd64. This adds runtime bits neccessary for the use > of the dispatch functions from the dynamically-linked executables and > shared libraries. > > To allow use of external references from the dispatch function, resolution > of the R_MACHINE_IRESOLVE relocations in PLT is postponed until GOT entries > for PLT are prepared, and normal resolution of the GOT entries is finished. > Similar to how it is done by GNU, IRELATIVE relocations are resolved in > advance, instead of normal lazy handling for PLT. > > Move the init_pltgot() call before the relocations for the object are > processed. > > MFC after: 3 weeks > > Modified: > head/libexec/rtld-elf/amd64/reloc.c > head/libexec/rtld-elf/arm/reloc.c > head/libexec/rtld-elf/i386/reloc.c > head/libexec/rtld-elf/ia64/reloc.c > head/libexec/rtld-elf/mips/reloc.c > head/libexec/rtld-elf/powerpc/reloc.c > head/libexec/rtld-elf/powerpc64/reloc.c > head/libexec/rtld-elf/rtld.c > head/libexec/rtld-elf/rtld.h > head/libexec/rtld-elf/sparc64/reloc.c > > Modified: head/libexec/rtld-elf/amd64/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/amd64/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/amd64/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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,91 @@ 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; > + > + 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); > + target = ((Elf_Addr (*)(void))ptr)(); > + *where = target; > + break; > + } > + } > + 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; > + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); > + 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: head/libexec/rtld-elf/arm/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/arm/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/arm/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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: head/libexec/rtld-elf/i386/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/i386/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/i386/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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,88 @@ 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; > + > + 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); > + target = ((Elf_Addr (*)(void))(*where))(); > + *where = target; > + break; > + } > + } > + 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; > + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); > + reloc_jmpslot(where, target, defobj, obj, rel); > + break; > + } > + } > + > + obj->gnu_ifunc = false; > + return (0); > +} > + > void > allocate_initial_tls(Obj_Entry *objs) > { > > Modified: head/libexec/rtld-elf/ia64/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/ia64/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/ia64/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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: head/libexec/rtld-elf/mips/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/mips/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/mips/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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: head/libexec/rtld-elf/powerpc/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/powerpc/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/powerpc/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -504,6 +504,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. > > Modified: head/libexec/rtld-elf/powerpc64/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/powerpc64/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/powerpc64/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -456,6 +456,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: head/libexec/rtld-elf/rtld.c > ============================================================================== > --- head/libexec/rtld-elf/rtld.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/rtld.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -561,6 +561,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 +595,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 +1957,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 +1969,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,11 +1976,26 @@ relocate_objects(Obj_Entry *first, bool > */ > obj->magic = RTLD_MAGIC; > obj->version = RTLD_VERSION; > - > - /* Set the special PLT or GOT entries. */ > - init_pltgot(obj); > } > > + /* > + * 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. > + */ > + for (obj = first; obj != NULL; obj = obj->next) { > + 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; > } > > @@ -2376,9 +2407,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 +2855,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 +3123,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: head/libexec/rtld-elf/rtld.h > ============================================================================== > --- head/libexec/rtld-elf/rtld.h Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/rtld.h Mon Dec 12 11:03:14 2011 (r228435) > @@ -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: head/libexec/rtld-elf/sparc64/reloc.c > ============================================================================== > --- head/libexec/rtld-elf/sparc64/reloc.c Mon Dec 12 10:10:49 2011 (r228434) > +++ head/libexec/rtld-elf/sparc64/reloc.c Mon Dec 12 11:03:14 2011 (r228435) > @@ -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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4EECB0A4.504>