diff --git a/lib/clang/libllvm/Makefile b/lib/clang/libllvm/Makefile index 6c81a315cfb..9579a00bcd3 100644 --- a/lib/clang/libllvm/Makefile +++ b/lib/clang/libllvm/Makefile @@ -820,7 +820,7 @@ SRCS_MIN+= Support/regerror.c SRCS_MIN+= Support/regexec.c SRCS_MIN+= Support/regfree.c SRCS_MIN+= Support/regstrlcpy.c -SRCS_LLD+= Support/xxhash.cpp +SRCS_MIN+= Support/xxhash.cpp SRCS_MIN+= TableGen/Error.cpp SRCS_MIN+= TableGen/JSONBackend.cpp SRCS_MIN+= TableGen/Main.cpp diff --git a/lib/clang/libllvmminimal/Makefile b/lib/clang/libllvmminimal/Makefile index 248b8e38fc2..8f46d9c922b 100644 --- a/lib/clang/libllvmminimal/Makefile +++ b/lib/clang/libllvmminimal/Makefile @@ -19,6 +19,7 @@ SRCS+= Support/Error.cpp SRCS+= Support/ErrorHandling.cpp SRCS+= Support/FoldingSet.cpp SRCS+= Support/FormattedStream.cpp +SRCS+= Support/FormatVariadic.cpp SRCS+= Support/Hashing.cpp SRCS+= Support/Host.cpp SRCS+= Support/IntEqClasses.cpp diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index cd6f70b7d00..f527e0b105d 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -154,89 +155,118 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) /* - * Relocate a non-PLT object with addend. + * Relocate a non-PLT object. */ static int reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) { - Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); - const Elf_Sym *def; - const Obj_Entry *defobj; - Elf_Addr tmp; + const Elf_Sym *def = NULL; + const Obj_Entry *defobj; + Elf_Addr *where, symval = 0; + /* + * First, resolve symbol for relocations which + * reference symbols. + */ switch (ELF_R_TYPE(rela->r_info)) { - case R_PPC_NONE: - break; - - case R_PPC64_UADDR64: /* doubleword64 S + A */ - case R_PPC64_ADDR64: - case R_PPC_GLOB_DAT: + case R_PPC64_UADDR64: /* doubleword64 S + A */ + case R_PPC64_ADDR64: + case R_PPC_GLOB_DAT: + case R_PPC64_DTPMOD64: + case R_PPC64_TPREL64: + case R_PPC64_DTPREL64: def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, cache, lockstate); if (def == NULL) { return (-1); } - - tmp = (Elf_Addr)(defobj->relocbase + def->st_value + - rela->r_addend); - - /* Don't issue write if unnecessary; avoid COW page fault */ - if (*where != tmp) { - *where = tmp; - } - break; - - case R_PPC_RELATIVE: /* doubleword64 B + A */ - tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); - - /* As above, don't issue write unnecessarily */ - if (*where != tmp) { - *where = tmp; - } - break; - - case R_PPC_COPY: /* - * These are deferred until all other relocations - * have been done. All we do here is make sure - * that the COPY relocation is not in a shared - * library. They are allowed only in executable - * files. + * If symbol is IFUNC, only perform relocation + * when caller allowed it by passing + * SYMLOOK_IFUNC flag. Skip the relocations + * otherwise. + * + * Also error out in case IFUNC relocations + * are specified for TLS, which cannot be + * usefully interpreted. */ - if (!obj->mainprog) { - _rtld_error("%s: Unexpected R_COPY " - " relocation in shared library", - obj->path); - return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + dbg("IFUNC IFUNC IFUNC IFUNC"); + switch (ELF_R_TYPE(rela->r_info)) { + case R_PPC64_UADDR64: + case R_PPC64_ADDR64: + case R_PPC_GLOB_DAT: + if ((flags & SYMLOOK_IFUNC) == 0) { + obj->non_plt_gnu_ifunc = true; + return (0); + } + symval = (Elf_Addr)rtld_resolve_ifunc( + defobj, def); + break; + default: + _rtld_error("%s: IFUNC for TLS reloc", + obj->path); + return (-1); + } + } else { + if ((flags & SYMLOOK_IFUNC) != 0) + return (0); + symval = (Elf_Addr)defobj->relocbase + + def->st_value; } break; - - case R_PPC_JMP_SLOT: + case R_PPC64_IRELATIVE: /* - * These will be handled by the plt/jmpslot routines + * Yes, non-PLT IRELATIVE is a thing! + * This can happen when ifuncs are defined in the executable, + * or are not called from multiple units. + * + * ifunc resolver functions in this case are NOT allowed + * to call outside their compilation unit, since we only defer + * them until the end of the current object, not the end of the + * runtime linking process. So it's perfectly normal for them + * to be called before libc is even loaded! + * + * The main use of this form of ifunc is to switch out optimized + * assembly functions based on cpu feature flags. */ + dbg("~~~~~~~~~~~~~~R_PPC64_IRELATIVE~~~~~~~~~~~~~~"); + /* Always process IRELATIVE. */ + if ((flags & SYMLOOK_IFUNC) == 0) { + dbg("SETTING NON PLT GNU IFUNC"); + obj->non_plt_gnu_ifunc = true; + return(0); + } break; + } + default: + if ((flags & SYMLOOK_IFUNC) != 0) + return (0); + } - case R_PPC64_DTPMOD64: - def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - flags, cache, lockstate); - - if (def == NULL) - return (-1); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); +// if (defobj != NULL && def != NULL) +// dbg("WHERE %p BASE %p OFFS %lx SYM %s", where, obj->relocbase, rela->r_offset, (const char*)(defobj->strtab + def->st_name)); + switch (ELF_R_TYPE(rela->r_info)) { + case R_PPC_NONE: + break; + case R_PPC64_UADDR64: + case R_PPC64_ADDR64: + case R_PPC_GLOB_DAT: + /* Don't issue write if unnecessary; avoid COW page fault */ + if (*where != symval + rela->r_addend) { + *where = symval + rela->r_addend; + } + break; + case R_PPC64_DTPMOD64: + dbg("DTPMOD64 %p %d ", where, defobj->tlsindex); *where = (Elf_Addr) defobj->tlsindex; - break; - case R_PPC64_TPREL64: - def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - flags, cache, lockstate); - - if (def == NULL) - return (-1); - + dbg("TPREL64"); /* * We lazily allocate offsets for static TLS as we * see the first relocation that references the @@ -257,21 +287,80 @@ reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, *(Elf_Addr **)where = *where * sizeof(Elf_Addr) + (Elf_Addr *)(def->st_value + rela->r_addend + defobj->tlsoffset - TLS_TP_OFFSET); + break; + case R_PPC64_DTPREL64: + dbg("DTPREL64 %p OLDVAL %lx", where, *where); + *where += (Elf_Addr)(def->st_value + rela->r_addend + - TLS_DTV_OFFSET); + dbg("DTPREL64 NEW %lx", *where); + break; + case R_PPC_RELATIVE: /* doubleword64 B + A */ + symval = (Elf_Addr)(obj->relocbase + rela->r_addend); + /* As above, don't issue write unnecessarily */ + if (*where != symval) { + *where = symval; + } break; - case R_PPC64_DTPREL64: - def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, - flags, cache, lockstate); + case R_PPC64_IRELATIVE: /* doubleword64 indirect */ +#if !defined(__CALL_ELF) || __CALL_ELF == 1 + _rtld_error("ELFv1 IRELATIVE is not implemented!"); + return (-1); +#else +dbg("IRELATIVE FOUND IRELATIVE FOUND IRELATIVE FOUND"); +/* + if ((flags & SYMLOOK_IFUNC) == 0) { + dbg("SETTING NON PLT GNU IFUNC"); + obj->non_plt_gnu_ifunc = true; + return(0); + } +*/ + /* obj->irelative = true; + break; */ + /* + * OpenPOWER ELFv2 ifuncs use direct manipulation instead + * of being PLT relocations. + */ + dbg("IRELATIVE IRELATIVE IRELATIVE found"); + Elf_Addr ptr; + ptr = (Elf_Addr)(obj->relocbase + rela->r_addend); +dbg("1"); + lock_release(rtld_bind_lock, lockstate); +dbg("2"); +dbg("PTR address %p", &ptr); + symval = call_ifunc_resolver(ptr); +dbg("3"); + wlock_acquire(rtld_bind_lock, lockstate); +dbg("4"); + *where = symval; +dbg("We survived"); +#endif + break; - if (def == NULL) + case R_PPC_COPY: + /* + * These are deferred until all other relocations + * have been done. All we do here is make sure + * that the COPY relocation is not in a shared + * library. They are allowed only in executable + * files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_COPY " + " relocation in shared library", + obj->path); return (-1); + } + break; - *where += (Elf_Addr)(def->st_value + rela->r_addend - - TLS_DTV_OFFSET); - + case R_PPC_JMP_SLOT: + /* + * These will be handled by the plt/jmpslot routines + */ break; + default: _rtld_error("%s: Unsupported relocation type %ld" " in non-PLT relocations\n", obj->path, @@ -295,10 +384,6 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, SymCache *cache; int r = -1; - if ((flags & SYMLOOK_IFUNC) != 0) - /* XXX not implemented */ - return (0); - /* * The dynamic loader may be called from a thread, we have * limited amounts of stack available so we cannot use alloca(). @@ -352,9 +437,10 @@ reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) long reloff; reloff = rela - obj->pltrela; - +/* dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, reloff, obj->glink); +*/ #if !defined(_CALL_ELF) || _CALL_ELF == 1 /* Glink code is 3 instructions after the first 32k, 2 before */ @@ -375,9 +461,10 @@ reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) int reloc_plt(Obj_Entry *obj) { + dbg("reloc_plt()"); const Elf_Rela *relalim; const Elf_Rela *rela; - +/* FIXME ADD IFUNC RELOCS*/ if (obj->pltrelasize != 0) { relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); @@ -393,7 +480,6 @@ reloc_plt(Obj_Entry *obj) return (0); } - /* * LD_BIND_NOW was set - force relocation for all jump slots */ @@ -445,8 +531,10 @@ reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) */ Elf_Addr reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, - const Obj_Entry *obj __unused, const Elf_Rel *rel __unused) + const Obj_Entry *obj __unused, const Elf_Rel *rel) { + assert(ELF_R_TYPE(rel->r_info) == R_PPC_JMP_SLOT);// || + //ELF_R_TYPE(rel->r_info) == R_PPC64_IRELATIVE); /* * At the PLT entry pointed at by `wherep', construct @@ -493,6 +581,8 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, } out: #else + /* Not used on ELFv2. */ + (void)(defobj); dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, (void *)target); @@ -504,21 +594,85 @@ reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, } int -reloc_iresolve(Obj_Entry *obj __unused, - struct Struct_RtldLockState *lockstate __unused) +reloc_iresolve(Obj_Entry *obj, + struct Struct_RtldLockState *lockstate) { - +dbg("reloc_iresolve(%p, %p) IRESOLVE IRESOLVE IRESOLVE IRESOLVE IRESOLVE!", obj, lockstate); +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + (void)(obj); + (void)(lockstate); /* XXX not implemented */ return (0); +#else + const Elf_Rela *relalim; + const Elf_Rela *rela; + Elf_Addr *where, target, *ptr; + + if (!obj->irelative) + return (0); +dbg("DOING IT!"); + relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { +dbg("CHECK"); + if (ELF_R_TYPE(rela->r_info) == R_PPC64_IRELATIVE) { +dbg("FOUND!"); + ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); +dbg("PTR %p WHERE %p", ptr, where); + lock_release(rtld_bind_lock, lockstate); + target = call_ifunc_resolver(ptr); +dbg("POSTCALL"); + wlock_acquire(rtld_bind_lock, lockstate); + *where = target; + } + } +dbg("DID IT!"); + obj->irelative = false; + return (0); +#endif } int reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused, struct Struct_RtldLockState *lockstate __unused) { - +dbg("GNU IFUNC RELOC RELOC RELOC!"); +return (0); +#if !defined(_CALL_ELF) || _CALL_ELF == 1 /* XXX not implemented */ return (0); +#else + +dbg("GNU"); + + const Elf_Rela *relalim; + const Elf_Rela *rela; + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + if (!obj->gnu_ifunc) + return (0); + relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) { + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, 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); + } + } + obj->gnu_ifunc = false; + return (0); +#endif } void @@ -541,10 +695,68 @@ init_pltgot(Obj_Entry *obj) #endif } +u_long cpu_features; +u_long cpu_features2; + +void +powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info) +{ + cpu_features = -1UL; + cpu_features2 = -1UL; + if (aux_info[AT_HWCAP] != NULL) + cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val; + if (aux_info[AT_HWCAP2] != NULL) + cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val; +} + void ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) { + int mib[2]; + size_t len, size; + uint64_t temp; + /* + * If the cpu features were not passed in auxv, we need to process + * them manually. + */ + + if (cpu_features == -1UL) { + size = sizeof(temp); + len = 2; + if (sysctlnametomib("hw.cpu_features", mib, &len)) + goto error; + + if (sysctl(mib, len, &temp, &size, NULL, 0)) + goto error; + cpu_features = (uint32_t)(temp); + } + + if (cpu_features2 == -1UL) { + size = sizeof(temp); + len = 2; + if (sysctlnametomib("hw.cpu_features2", mib, &len)) + goto error; + + if (sysctl(mib, len, &temp, &size, NULL, 0)) + goto error; + cpu_features2 = (uint32_t)(temp); + } + + dbg("cpu_features %lx", cpu_features); + dbg("cpu_features2 %lx", cpu_features2); + + Elf_Auxinfo *aux; + for (aux = &aux_info[0]; aux->a_type != AT_NULL; aux++) { + dbg("AUX value of %ld", aux->a_type); + } + + + return; + +error: + _rtld_error("Unable to determine cpu info!"); + rtld_die(); } void diff --git a/libexec/rtld-elf/powerpc64/rtld_machdep.h b/libexec/rtld-elf/powerpc64/rtld_machdep.h index f95f7f3f374..40a2328aba0 100644 --- a/libexec/rtld-elf/powerpc64/rtld_machdep.h +++ b/libexec/rtld-elf/powerpc64/rtld_machdep.h @@ -53,8 +53,13 @@ void reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase); #define call_init_pointer(obj, target) \ (((InitArrFunc)(target))(main_argc, main_argv, environ)) +extern u_long cpu_features; /* r3 */ +extern u_long cpu_features2; /* r4 */ +/* r5-r10: ifunc resolver parameters reserved for future assignment. */ #define call_ifunc_resolver(ptr) \ - (((Elf_Addr (*)(void))ptr)()) + (((Elf_Addr (*)(uint32_t, uint32_t, uint64_t, uint64_t, uint64_t, \ + uint64_t, uint64_t, uint64_t))ptr)((uint32_t)cpu_features, \ + (uint32_t)cpu_features2, 0, 0, 0, 0, 0, 0)) /* * TLS @@ -83,6 +88,7 @@ extern void *__tls_get_addr(tls_index* ti); #define RTLD_DEFAULT_STACK_PF_EXEC PF_X #define RTLD_DEFAULT_STACK_EXEC PROT_EXEC -#define md_abi_variant_hook(x) +extern void powerpc64_abi_variant_hook(Elf_Auxinfo **); +#define md_abi_variant_hook(x) powerpc64_abi_variant_hook(x) #endif diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 80c78d9f21c..a6e8b1d863a 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -415,6 +415,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) main_argc = argc; main_argv = argv; +debug=1; + trust = !issetugid(); md_abi_variant_hook(aux_info); @@ -753,6 +755,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (initlist_objects_ifunc(&initlist, ld_bind_now != NULL && *ld_bind_now != '\0', SYMLOOK_EARLY, &lockstate) == -1) rtld_die(); +dbg("ifunc resolve done"); if (obj_main->crt_no_init) preinit_main(); @@ -781,9 +784,13 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) return (func_ptr_type) obj_main->entry; } +/* + * Resolve an STT_GNU_IFUNC symbol by calling the resolver function. + */ void * rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def) { + dbg("rtld_resolve_ifunc()"); void *ptr; Elf_Addr target; @@ -2700,16 +2707,18 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate) LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)elm->obj->init, 0, 0, elm->obj->path); call_initfini_pointer(elm->obj, elm->obj->init); + dbg("init call finished."); } init_addr = (Elf_Addr *)elm->obj->init_array; if (init_addr != NULL) { for (index = 0; index < elm->obj->init_array_num; index++) { if (init_addr[index] != 0 && init_addr[index] != 1) { - dbg("calling init function for %s at %p", elm->obj->path, + dbg("calling init[] function for %s at %p", elm->obj->path, (void *)init_addr[index]); LD_UTRACE(UTRACE_INIT_CALL, elm->obj, (void *)init_addr[index], 0, 0, elm->obj->path); call_init_pointer(elm->obj, init_addr[index]); + dbg("init[] call finished."); } } } @@ -4770,6 +4779,8 @@ get_tls_block_ptr(void *tcb, size_t tcbsize) void * allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) { + dbg("ALLOCATE MODULE SZ %ld", tcbsize); + Obj_Entry *obj; char *tls_block; Elf_Addr *dtv, **tcb; diff --git a/sys/powerpc/include/cpu.h b/sys/powerpc/include/cpu.h index 31b747cd0c3..6a2add1b6fd 100644 --- a/sys/powerpc/include/cpu.h +++ b/sys/powerpc/include/cpu.h @@ -53,8 +53,10 @@ * sysctl. */ +#ifdef _KERNEL extern u_long cpu_features; extern u_long cpu_features2; +#endif /* _KERNEL */ #define PPC_FEATURE_32 0x80000000 /* Always true */ #define PPC_FEATURE_64 0x40000000 /* Defined on a 64-bit CPU */ diff --git a/sys/powerpc/include/ifunc.h b/sys/powerpc/include/ifunc.h index af785a0a726..a7f2e0bf616 100644 --- a/sys/powerpc/include/ifunc.h +++ b/sys/powerpc/include/ifunc.h @@ -39,12 +39,13 @@ #define DEFINE_UIFUNC(qual, ret_type, name, args, resolver_qual) \ resolver_qual ret_type (*name##_resolver(uint32_t, uint32_t, \ - uint32_t, uint32_t))args __used; \ + register_t, register_t, register_t, register_t, register_t, \ + register_t))args __used; \ qual ret_type name args __attribute__((ifunc(#name "_resolver"))); \ resolver_qual ret_type (*name##_resolver( \ - uint32_t cpu_feature __unused, \ - uint32_t cpu_feature2 __unused, \ - uint32_t cpu_stdext_feature __unused, \ - uint32_t cpu_stdext_feature2 __unused))args - + uint32_t cpu_features __unused, \ + uint32_t cpu_features2 __unused, \ + register_t _arg3 __unused, register_t _arg4 __unused, \ + register_t _arg5 __unused, register_t _arg6 __unused, \ + register_t _arg7 __unused, register_t _arg8 __unused))args #endif diff --git a/sys/powerpc/powerpc/elf64_machdep.c b/sys/powerpc/powerpc/elf64_machdep.c index 2815fcfcd38..0fcd931d348 100644 --- a/sys/powerpc/powerpc/elf64_machdep.c +++ b/sys/powerpc/powerpc/elf64_machdep.c @@ -127,6 +127,9 @@ struct sysentvec elf64_freebsd_sysvec_v2 = { .sv_shared_page_len = PAGE_SIZE, .sv_schedtail = NULL, .sv_thread_detach = NULL, + .sv_trap = NULL, + .sv_hwcap = &cpu_features, + .sv_hwcap2 = &cpu_features2, }; INIT_SYSENTVEC(elf64_sysvec_v2, &elf64_freebsd_sysvec_v2);