diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2019-04-12 15:15:27 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2019-04-12 15:15:27 +0000 |
| commit | df1b1afc355eb43abd04ea3d7764fabf21f85575 (patch) | |
| tree | e042da39c5977ef5a606fc87c7acf2427f1a6291 /libexec | |
| parent | 049e8c11b46f6a8796869a9b8f5fe29b1b2351d1 (diff) | |
Notes
Diffstat (limited to 'libexec')
| -rw-r--r-- | libexec/rtld-elf/rtld.c | 46 | ||||
| -rw-r--r-- | libexec/rtld-elf/rtld.h | 2 |
2 files changed, 42 insertions, 6 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 368fdbc8b5a6..b0fbff0f3c54 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -81,6 +81,7 @@ static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *, const Elf_Dyn *); static void digest_dynamic(Obj_Entry *, int); static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); +static void distribute_static_tls(Objlist *, RtldLockState *); static Obj_Entry *dlcheck(void *); static int dlclose_locked(void *, RtldLockState *); static Obj_Entry *dlopen_object(const char *name, int fd, Obj_Entry *refobj, @@ -1247,8 +1248,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, obj->textrel = true; if (dynp->d_un.d_val & DF_BIND_NOW) obj->bind_now = true; - /*if (dynp->d_un.d_val & DF_STATIC_TLS) - ;*/ + if (dynp->d_un.d_val & DF_STATIC_TLS) + obj->static_tls = true; break; #ifdef __mips__ case DT_MIPS_LOCAL_GOTNO: @@ -3309,8 +3310,16 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, if (globallist_next(old_obj_tail) != NULL) { /* We loaded something new. */ assert(globallist_next(old_obj_tail) == obj); - result = load_needed_objects(obj, - lo_flags & (RTLD_LO_DLOPEN | RTLD_LO_EARLY)); + result = 0; + if ((lo_flags & RTLD_LO_EARLY) == 0 && obj->static_tls && + !allocate_tls_offset(obj)) { + _rtld_error("%s: No space available " + "for static Thread Local Storage", obj->path); + result = -1; + } + if (result != -1) + result = load_needed_objects(obj, lo_flags & (RTLD_LO_DLOPEN | + RTLD_LO_EARLY)); init_dag(obj); ref_dag(obj); if (result != -1) @@ -3370,8 +3379,10 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, name); GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL); - if (!(lo_flags & RTLD_LO_EARLY)) { + if ((lo_flags & RTLD_LO_EARLY) == 0) { map_stacks_exec(lockstate); + if (obj != NULL) + distribute_static_tls(&initlist, lockstate); } if (initlist_objects_ifunc(&initlist, (mode & RTLD_MODEMASK) == RTLD_NOW, @@ -4851,8 +4862,10 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) addr = segbase - obj->tlsoffset; memset((void*) (addr + obj->tlsinitsize), 0, obj->tlssize - obj->tlsinitsize); - if (obj->tlsinit) + if (obj->tlsinit) { memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); + obj->static_tls_copied = true; + } dtv[obj->tlsindex + 1] = addr; } } @@ -5314,6 +5327,27 @@ map_stacks_exec(RtldLockState *lockstate) } } +static void +distribute_static_tls(Objlist *list, RtldLockState *lockstate) +{ + Objlist_Entry *elm; + Obj_Entry *obj; + void (*distrib)(size_t, void *, size_t, size_t); + + distrib = (void (*)(size_t, void *, size_t, size_t))(uintptr_t) + get_program_var_addr("__pthread_distribute_static_tls", lockstate); + if (distrib == NULL) + return; + STAILQ_FOREACH(elm, list, link) { + obj = elm->obj; + if (obj->marker || !obj->tls_done || obj->static_tls_copied) + continue; + distrib(obj->tlsoffset, obj->tlsinit, obj->tlsinitsize, + obj->tlssize); + obj->static_tls_copied = true; + } +} + void symlook_init(SymLook *dst, const char *name) { diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index e3b5d691a84c..1f99c9bba04c 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -253,6 +253,8 @@ typedef struct Struct_Obj_Entry { bool z_interpose : 1; /* Interpose all objects but main */ bool z_nodeflib : 1; /* Don't search default library path */ bool z_global : 1; /* Make the object global */ + bool static_tls : 1; /* Needs static TLS allocation */ + bool static_tls_copied : 1; /* Needs static TLS copying */ bool ref_nodel : 1; /* Refcount increased to prevent dlclose */ bool init_scanned: 1; /* Object is already on init list. */ bool on_fini_list: 1; /* Object is already on fini list. */ |
