Changeset View
Changeset View
Standalone View
Standalone View
libexec/rtld-elf/rtld.c
Show First 20 Lines • Show All 4,686 Lines • ▼ Show 20 Lines | if (__predict_true(dtv[0] == tls_dtv_generation && | ||||
return ((void *)(dtv[index + 1] + offset)); | return ((void *)(dtv[index + 1] + offset)); | ||||
return (tls_get_addr_slow(dtvp, index, offset)); | return (tls_get_addr_slow(dtvp, index, offset)); | ||||
} | } | ||||
#if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \ | #if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \ | ||||
defined(__powerpc__) || defined(__riscv) | defined(__powerpc__) || defined(__riscv) | ||||
/* | /* | ||||
* Return pointer to allocated TLS block | |||||
*/ | |||||
static void * | |||||
get_tls_block_ptr(void *tcb, size_t tcbsize) | |||||
{ | |||||
size_t extra_size, post_size, pre_size, tls_block_size; | |||||
size_t tls_init_align; | |||||
tls_init_align = MAX(obj_main->tlsalign, 1); | |||||
/* Compute fragments sizes. */ | |||||
extra_size = tcbsize - TLS_TCB_SIZE; | |||||
post_size = calculate_tls_post_size(tls_init_align); | |||||
kib: Perhaps add another MD macro for this expression. It could be also used in allocate_tls() and… | |||||
tls_block_size = tcbsize + post_size; | |||||
pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size; | |||||
return ((char *)tcb - pre_size - extra_size); | |||||
} | |||||
/* | |||||
* Allocate Static TLS using the Variant I method. | * Allocate Static TLS using the Variant I method. | ||||
* | |||||
* For details on the layout, see lib/libc/gen/tls.c. | |||||
* | |||||
* NB: rtld's tls_static_space variable includes TLS_TCB_SIZE and post_size as | |||||
* it is based on tls_last_offset, and TLS offsets here are really TCB | |||||
* offsets, whereas libc's tls_static_space is just the executable's static | |||||
* TLS segment. | |||||
*/ | */ | ||||
void * | void * | ||||
allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) | allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) | ||||
{ | { | ||||
Obj_Entry *obj; | Obj_Entry *obj; | ||||
char *tcb; | char *tls_block; | ||||
Elf_Addr **tls; | Elf_Addr *dtv, **tcb; | ||||
Elf_Addr *dtv; | |||||
Elf_Addr addr; | Elf_Addr addr; | ||||
int i; | int i; | ||||
size_t extra_size, maxalign, post_size, pre_size, tls_block_size; | |||||
size_t tls_init_align; | |||||
if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) | if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) | ||||
return (oldtcb); | return (oldtcb); | ||||
assert(tcbsize >= TLS_TCB_SIZE); | assert(tcbsize >= TLS_TCB_SIZE); | ||||
tcb = xcalloc(1, tls_static_space - TLS_TCB_SIZE + tcbsize); | maxalign = MAX(tcbalign, tls_static_max_align); | ||||
tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); | tls_init_align = MAX(obj_main->tlsalign, 1); | ||||
/* Compute fragmets sizes. */ | |||||
extra_size = tcbsize - TLS_TCB_SIZE; | |||||
post_size = calculate_tls_post_size(tls_init_align); | |||||
tls_block_size = tcbsize + post_size; | |||||
pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size; | |||||
tls_block_size += pre_size + tls_static_space - TLS_TCB_SIZE - post_size; | |||||
/* Allocate whole TLS block */ | |||||
tls_block = malloc_aligned(tls_block_size, maxalign); | |||||
tcb = (Elf_Addr **)(tls_block + pre_size + extra_size); | |||||
if (oldtcb != NULL) { | if (oldtcb != NULL) { | ||||
memcpy(tls, oldtcb, tls_static_space); | memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), | ||||
free(oldtcb); | tls_static_space); | ||||
free_aligned(get_tls_block_ptr(oldtcb, tcbsize)); | |||||
/* Adjust the DTV. */ | /* Adjust the DTV. */ | ||||
dtv = tls[0]; | dtv = tcb[0]; | ||||
for (i = 0; i < dtv[1]; i++) { | for (i = 0; i < dtv[1]; i++) { | ||||
if (dtv[i+2] >= (Elf_Addr)oldtcb && | if (dtv[i+2] >= (Elf_Addr)oldtcb && | ||||
dtv[i+2] < (Elf_Addr)oldtcb + tls_static_space) { | dtv[i+2] < (Elf_Addr)oldtcb + tls_static_space) { | ||||
dtv[i+2] = dtv[i+2] - (Elf_Addr)oldtcb + (Elf_Addr)tls; | dtv[i+2] = dtv[i+2] - (Elf_Addr)oldtcb + (Elf_Addr)tcb; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
dtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr)); | dtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr)); | ||||
tls[0] = dtv; | tcb[0] = dtv; | ||||
dtv[0] = tls_dtv_generation; | dtv[0] = tls_dtv_generation; | ||||
dtv[1] = tls_max_index; | dtv[1] = tls_max_index; | ||||
for (obj = globallist_curr(objs); obj != NULL; | for (obj = globallist_curr(objs); obj != NULL; | ||||
obj = globallist_next(obj)) { | obj = globallist_next(obj)) { | ||||
if (obj->tlsoffset > 0) { | if (obj->tlsoffset > 0) { | ||||
addr = (Elf_Addr)tls + obj->tlsoffset; | addr = (Elf_Addr)tcb + obj->tlsoffset; | ||||
if (obj->tlsinitsize > 0) | if (obj->tlsinitsize > 0) | ||||
memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); | memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); | ||||
if (obj->tlssize > obj->tlsinitsize) | if (obj->tlssize > obj->tlsinitsize) | ||||
memset((void*) (addr + obj->tlsinitsize), 0, | memset((void*) (addr + obj->tlsinitsize), 0, | ||||
obj->tlssize - obj->tlsinitsize); | obj->tlssize - obj->tlsinitsize); | ||||
dtv[obj->tlsindex + 1] = addr; | dtv[obj->tlsindex + 1] = addr; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return (tcb); | return (tcb); | ||||
} | } | ||||
void | void | ||||
free_tls(void *tcb, size_t tcbsize, size_t tcbalign) | free_tls(void *tcb, size_t tcbsize, size_t tcbalign) | ||||
{ | { | ||||
Elf_Addr *dtv; | Elf_Addr *dtv; | ||||
Elf_Addr tlsstart, tlsend; | Elf_Addr tlsstart, tlsend; | ||||
int dtvsize, i; | size_t post_size; | ||||
size_t dtvsize, i, tls_init_align; | |||||
assert(tcbsize >= TLS_TCB_SIZE); | assert(tcbsize >= TLS_TCB_SIZE); | ||||
tls_init_align = MAX(obj_main->tlsalign, 1); | |||||
tlsstart = (Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE; | /* Compute fragments sizes. */ | ||||
tlsend = tlsstart + tls_static_space; | post_size = calculate_tls_post_size(tls_init_align); | ||||
dtv = *(Elf_Addr **)tlsstart; | tlsstart = (Elf_Addr)tcb + TLS_TCB_SIZE + post_size; | ||||
tlsend = (Elf_Addr)tcb + tls_static_space; | |||||
dtv = *(Elf_Addr **)tcb; | |||||
dtvsize = dtv[1]; | dtvsize = dtv[1]; | ||||
for (i = 0; i < dtvsize; i++) { | for (i = 0; i < dtvsize; i++) { | ||||
if (dtv[i+2] && (dtv[i+2] < tlsstart || dtv[i+2] >= tlsend)) { | if (dtv[i+2] && (dtv[i+2] < tlsstart || dtv[i+2] >= tlsend)) { | ||||
free((void*)dtv[i+2]); | free((void*)dtv[i+2]); | ||||
} | } | ||||
} | } | ||||
free(dtv); | free(dtv); | ||||
free(tcb); | free_aligned(get_tls_block_ptr(tcb, tcbsize)); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) | #if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) | ||||
/* | /* | ||||
* Allocate Static TLS using the Variant II method. | * Allocate Static TLS using the Variant II method. | ||||
▲ Show 20 Lines • Show All 746 Lines • Show Last 20 Lines |
Perhaps add another MD macro for this expression. It could be also used in allocate_tls() and free_tls().