FreeBSD/libexec/rtld-elf/rtld.c
/*
 * Allocate Static TLS using the Variant II method.
 */
Allocate Static TLS using the Variant II method.
Allocate Static TLS using the Variant II method .
void *
allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign)
{
    Obj_Entry *obj;
    size_t size, ralign;
    char *tls;
    Elf_Addr *dtv, *olddtv;
    Elf_Addr segbase, oldsegbase, addr;
    int i;
    ralign = tcbalign;
    if (tls_static_max_align > ralign)
	    ralign = tls_static_max_align;
    size = round(tls_static_space, ralign) + round(tcbsize, ralign);
    assert(tcbsize >= 2*sizeof(Elf_Addr));
    tls = malloc_aligned(size, ralign);
    dtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr));
    segbase = (Elf_Addr)(tls + round(tls_static_space, ralign));
    ((Elf_Addr*)segbase)[0] = segbase;
    ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
    dtv[0] = tls_dtv_generation;
    dtv[1] = tls_max_index;
    if (oldtls) {
	oldsegbase = (Elf_Addr) oldtls;
	memcpy((void *)(segbase - tls_static_space),
	       (const void *)(oldsegbase - tls_static_space),
	       tls_static_space);
	olddtv = ((Elf_Addr**)oldsegbase)[1];
	for (i = 0; i < olddtv[1]; i++) {
	    if (olddtv[i+2] < oldsegbase - size || olddtv[i+2] > oldsegbase) {
		dtv[i+2] = olddtv[i+2];
		olddtv[i+2] = 0;
	    }
	}
	free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
    } else {
	for (obj = objs; obj != NULL; obj = TAILQ_NEXT(obj, next)) {
		if (obj->marker || obj->tlsoffset == 0)
			continue;
		addr = segbase - obj->tlsoffset;
		memset((void*) (addr + obj->tlsinitsize),
		       0, obj->tlssize - obj->tlsinitsize);
		if (obj->tlsinit)
		    memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize);
		dtv[obj->tlsindex + 1] = addr;
	}
    }
    return (void*) segbase;
}
void * allocate_tls ( Obj_Entry * objs , void * oldtls , size_t tcbsize , size_t tcbalign ) { Obj_Entry * obj ; size_t size , ralign ; char * tls ; Elf_Addr * dtv , * olddtv ; Elf_Addr segbase , oldsegbase , addr ; int i ; ralign = tcbalign ; if ( tls_static_max_align > ralign ) ralign = tls_static_max_align ; size = round ( tls_static_space , ralign ) + round ( tcbsize , ralign ) ; assert ( tcbsize >= 2 * sizeof ( Elf_Addr ) ) ; tls = malloc_aligned ( size , ralign ) ; dtv = xcalloc ( tls_max_index + 2 , sizeof ( Elf_Addr ) ) ; segbase = ( Elf_Addr ) ( tls + round ( tls_static_space , ralign ) ) ; ( ( Elf_Addr * ) segbase ) [ 0 ] = segbase ; ( ( Elf_Addr * ) segbase ) [ 1 ] = ( Elf_Addr ) dtv ; dtv [ 0 ] = tls_dtv_generation ; dtv [ 1 ] = tls_max_index ; if ( oldtls ) { oldsegbase = ( Elf_Addr ) oldtls ; memcpy ( ( void * ) ( segbase - tls_static_space ) , ( const void * ) ( oldsegbase - tls_static_space ) , tls_static_space ) ; olddtv = ( ( Elf_Addr * * ) oldsegbase ) [ 1 ] ; for ( i = 0 ; i < olddtv [ 1 ] ; i ++ ) { if ( olddtv [ i + 2 ] < oldsegbase - size || olddtv [ i + 2 ] > oldsegbase ) { dtv [ i + 2 ] = olddtv [ i + 2 ] ; olddtv [ i + 2 ] = 0 ; } } free_tls ( oldtls , 2 * sizeof ( Elf_Addr ) , sizeof ( Elf_Addr ) ) ; } else { for ( obj = objs ; obj != NULL ; obj = TAILQ_NEXT ( obj , next ) ) { if ( obj -> marker || obj -> tlsoffset == 0 ) continue ; addr = segbase - obj -> tlsoffset ; memset ( ( void * ) ( addr + obj -> tlsinitsize ) , 0 , obj -> tlssize - obj -> tlsinitsize ) ; if ( obj -> tlsinit ) memcpy ( ( void * ) addr , obj -> tlsinit , obj -> tlsinitsize ) ; dtv [ obj -> tlsindex + 1 ] = addr ; } } return ( void * ) segbase ; }
Allocate Static TLS using the Variant II method.
Allocate Static TLS using the Variant II method .
/*
	 * Copy the static TLS block over whole.
	 */ /*
	 * If any dynamic TLS blocks have been created tls_get_addr(),
	 * move them over.
	 */ /*
	 * We assume that this block was the one we created with
	 * allocate_initial_tls().
	 */