Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdio.h>
     28 #include <strings.h>
     29 #include <sys/types.h>
     30 #include <dlfcn.h>
     31 #include <libc_int.h>
     32 #include <_rtld.h>
     33 #include <_elf.h>
     34 #include <msg.h>
     35 #include <debug.h>
     36 
     37 #define	TLSBLOCKCNT	16	/* number of blocks of tmi_bits to allocate */
     38 				/* at a time. */
     39 typedef struct {
     40 	uint_t	*tmi_bits;
     41 	ulong_t	tmi_lowfree;
     42 	ulong_t	tmi_cnt;
     43 } Tlsmodid;
     44 
     45 static Tlsmodid	tmid = {0, 0, 0};
     46 
     47 static ulong_t
     48 tls_getmodid()
     49 {
     50 	ulong_t	ndx, cnt;
     51 
     52 	if (tmid.tmi_bits == 0) {
     53 		if ((tmid.tmi_bits =
     54 		    calloc(TLSBLOCKCNT, sizeof (uint_t))) == NULL)
     55 			return ((ulong_t)-1);
     56 		tmid.tmi_bits[0] = 1;
     57 		tmid.tmi_lowfree = 1;
     58 		tmid.tmi_cnt = TLSBLOCKCNT;
     59 		return (0);
     60 	}
     61 
     62 	for (cnt = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
     63 	    cnt < tmid.tmi_cnt; cnt++) {
     64 		uint_t	bits;
     65 
     66 		/*
     67 		 * If all bits are assigned - move on.
     68 		 */
     69 		if ((tmid.tmi_bits[cnt] ^ ~((uint_t)0)) == 0)
     70 			continue;
     71 
     72 		for (ndx = 0, bits = 1; bits; bits = bits << 1, ndx++) {
     73 			if ((tmid.tmi_bits[cnt] & bits) == 0) {
     74 				tmid.tmi_bits[cnt] |= bits;
     75 				ndx = (cnt * (sizeof (uint_t)) * 8) + ndx;
     76 				tmid.tmi_lowfree = ndx + 1;
     77 				return (ndx);
     78 			}
     79 		}
     80 	}
     81 
     82 	/*
     83 	 * All bits taken - must allocate a new block
     84 	 */
     85 	if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
     86 	    ((tmid.tmi_cnt * sizeof (uint_t)) +
     87 	    (TLSBLOCKCNT * sizeof (uint_t))))) == NULL)
     88 		return ((ulong_t)-1);
     89 
     90 	/*
     91 	 * Clear out the tail of the new allocation.
     92 	 */
     93 	bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
     94 	tmid.tmi_bits[tmid.tmi_cnt] = 1;
     95 	ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8;
     96 	tmid.tmi_lowfree = ndx + 1;
     97 	tmid.tmi_cnt += TLSBLOCKCNT;
     98 
     99 	return (ndx);
    100 }
    101 
    102 void
    103 tls_freemodid(ulong_t modid)
    104 {
    105 	ulong_t	i;
    106 	uint_t	j;
    107 
    108 	i = modid / (sizeof (uint_t) * 8);
    109 	/* LINTED */
    110 	j = modid % (sizeof (uint_t) * 8);
    111 	j = ~(1 << j);
    112 	tmid.tmi_bits[i] &= j;
    113 	if (modid < tmid.tmi_lowfree)
    114 		tmid.tmi_lowfree = modid;
    115 }
    116 
    117 void
    118 tls_modaddrem(Rt_map *lmp, uint_t flag)
    119 {
    120 	Lm_list		*lml = LIST(lmp);
    121 	TLS_modinfo	tmi;
    122 	Phdr		*tlsphdr;
    123 	void		(*fptr)(TLS_modinfo *);
    124 
    125 	if (flag & TM_FLG_MODADD) {
    126 		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
    127 	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
    128 		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
    129 	} else {
    130 		return;
    131 	}
    132 
    133 	tlsphdr = PTTLS(lmp);
    134 
    135 	bzero(&tmi, sizeof (tmi));
    136 	tmi.tm_modname = PATHNAME(lmp);
    137 	tmi.tm_modid = TLSMODID(lmp);
    138 	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
    139 
    140 	if (!(FLAGS(lmp) & FLG_RT_FIXED))
    141 		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
    142 		    ADDR(lmp));
    143 
    144 	tmi.tm_filesz = tlsphdr->p_filesz;
    145 	tmi.tm_memsz = tlsphdr->p_memsz;
    146 	tmi.tm_flags = 0;
    147 	tmi.tm_stattlsoffset = 0;
    148 
    149 	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
    150 	(*fptr)(&tmi);
    151 
    152 	/*
    153 	 * Tag that this link-map has registered its TLS, and, if this object
    154 	 * is being removed, free up the module id.
    155 	 */
    156 	FLAGS1(lmp) |= FL1_RT_TLSADD;
    157 
    158 	if (flag & TM_FLG_MODREM)
    159 		tls_freemodid(TLSMODID(lmp));
    160 }
    161 
    162 static ulong_t	tls_static_size = 0;	/* static TLS buffer size */
    163 static ulong_t	tls_static_resv = 512;	/* (extra) static TLS reservation */
    164 
    165 /*
    166  * Track any static TLS use, retain the TLS header, and assign a TLS module
    167  * identifier.
    168  */
    169 int
    170 tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
    171 {
    172 	ulong_t	memsz = S_ROUND(phdr->p_memsz, M_TLSSTATALIGN);
    173 	ulong_t	filesz = phdr->p_filesz;
    174 	ulong_t	resv = tls_static_resv;
    175 
    176 	/*
    177 	 * If this object explicitly references static TLS, then there are some
    178 	 * limitations.
    179 	 */
    180 	if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
    181 		/*
    182 		 * Static TLS is only available to objects on the primary
    183 		 * link-map list.
    184 		 */
    185 		if (((lml->lm_flags & LML_FLG_BASELM) == 0) ||
    186 		    ((rtld_flags2 & RT_FL2_NOPLM) != 0)) {
    187 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_STATBASE),
    188 			    NAME(lmp));
    189 			return (0);
    190 		}
    191 
    192 		/*
    193 		 * All TLS blocks that are processed before thread
    194 		 * initialization, are registered with libc.  This
    195 		 * initialization is carried out through a handshake with libc
    196 		 * prior to executing any user code (ie. before the first .init
    197 		 * sections are called).  As part of this initialization, a
    198 		 * small backup TLS reservation is added (tls_static_resv).
    199 		 * Only explicit static TLS references that can be satisfied by
    200 		 * this TLS backup reservation can be satisfied.
    201 		 */
    202 		if (rtld_flags2 & RT_FL2_PLMSETUP) {
    203 			/*
    204 			 * Initialized static TLS can not be satisfied from the
    205 			 * TLS backup reservation.
    206 			 */
    207 			if (filesz) {
    208 				eprintf(lml, ERR_FATAL,
    209 				    MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
    210 				return (0);
    211 			}
    212 
    213 			/*
    214 			 * Make sure the backup reservation is sufficient.
    215 			 */
    216 			if (memsz > tls_static_resv) {
    217 				eprintf(lml, ERR_FATAL,
    218 				    MSG_INTL(MSG_TLS_STATSIZE), NAME(lmp),
    219 				    EC_XWORD(memsz), EC_XWORD(tls_static_resv));
    220 				return (0);
    221 			}
    222 
    223 			tls_static_resv -= memsz;
    224 		}
    225 	}
    226 
    227 	/*
    228 	 * If we haven't yet initialized threads, or this static reservation can
    229 	 * be satisfied from the TLS backup reservation, determine the total
    230 	 * static TLS size, and assign this object a static TLS offset.
    231 	 */
    232 	if (((rtld_flags2 & RT_FL2_PLMSETUP) == 0) ||
    233 	    (FLAGS1(lmp) & FL1_RT_TLSSTAT)) {
    234 		tls_static_size += memsz;
    235 		TLSSTATOFF(lmp) = tls_static_size;
    236 	}
    237 
    238 	/*
    239 	 * Retain the PT_TLS header, obtain a new module identifier, and
    240 	 * indicate that this link-map list contains a new TLS object.
    241 	 */
    242 	PTTLS(lmp) = phdr;
    243 	TLSMODID(lmp) = tls_getmodid();
    244 
    245 	/*
    246 	 * Now that we have a TLS module id, generate any static TLS reservation
    247 	 * diagnostic.
    248 	 */
    249 	if (resv != tls_static_resv)
    250 		DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));
    251 
    252 	return (++lml->lm_tls);
    253 }
    254 
    255 int
    256 tls_statmod(Lm_list *lml, Rt_map *lmp)
    257 {
    258 	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
    259 	TLS_modinfo	**tlsmodlist, *tlsbuflist;
    260 	Phdr		*tlsphdr;
    261 	void		(*fptr)(TLS_modinfo **, ulong_t);
    262 
    263 	fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
    264 
    265 	/*
    266 	 * Allocate a buffer to report the TLS modules, the buffer consists of:
    267 	 *
    268 	 *	TLS_modinfo *	ptrs[tlsmodcnt + 1]
    269 	 *	TLS_modinfo	bufs[tlsmodcnt]
    270 	 *
    271 	 * The ptrs are initialized to the bufs - except the last one which
    272 	 * null terminates the array.
    273 	 *
    274 	 * Note, even if no TLS has yet been observed, we still supply a
    275 	 * TLS buffer with a single null entry.  This allows us to initialize
    276 	 * the backup TLS reservation.
    277 	 */
    278 	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
    279 	    (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == NULL)
    280 		return (0);
    281 
    282 	lml->lm_tls = 0;
    283 
    284 	/*
    285 	 * If we don't have any TLS modules - report that and return.
    286 	 */
    287 	if (tlsmodcnt == 0) {
    288 		if (fptr)
    289 			(*fptr)(tlsmodlist, tls_static_resv);
    290 		DBG_CALL(Dbg_tls_static_block(&lml_main, 0, 0,
    291 		    tls_static_resv));
    292 		return (1);
    293 	}
    294 
    295 	/*
    296 	 * Initialize the TLS buffer.
    297 	 */
    298 	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
    299 	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
    300 
    301 	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
    302 		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
    303 
    304 	/*
    305 	 * Account for the initial dtv ptr in the TLSSIZE calculation.
    306 	 */
    307 	tlsmodndx = 0;
    308 	for (lmp = lml->lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
    309 		if (THIS_IS_NOT_ELF(lmp) ||
    310 		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
    311 			continue;
    312 
    313 		tlsphdr = PTTLS(lmp);
    314 
    315 		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
    316 		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
    317 		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
    318 
    319 		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
    320 			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
    321 			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
    322 			    ADDR(lmp));
    323 		}
    324 		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
    325 		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
    326 		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
    327 		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
    328 		tlsmodndx++;
    329 	}
    330 
    331 	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
    332 	    tls_static_size, tls_static_resv));
    333 	(*fptr)(tlsmodlist, (tls_static_size + tls_static_resv));
    334 
    335 	/*
    336 	 * We're done with the list - clean it up.
    337 	 */
    338 	free(tlsmodlist);
    339 	return (1);
    340 }
    341