dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / sgs / rtld / common / tls.c
blobe36c03c02d5d06aa65596516f930bb493dc36d6e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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>
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;
45 static Tlsmodid tmid = {0, 0, 0};
47 static ulong_t
48 tls_getmodid()
50 ulong_t ndx, cnt;
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);
62 for (cnt = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
63 cnt < tmid.tmi_cnt; cnt++) {
64 uint_t bits;
67 * If all bits are assigned - move on.
69 if ((tmid.tmi_bits[cnt] ^ ~((uint_t)0)) == 0)
70 continue;
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);
83 * All bits taken - must allocate a new block
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);
91 * Clear out the tail of the new allocation.
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;
99 return (ndx);
102 void
103 tls_freemodid(ulong_t modid)
105 ulong_t i;
106 uint_t j;
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;
117 void
118 tls_modaddrem(Rt_map *lmp, uint_t flag)
120 Lm_list *lml = LIST(lmp);
121 TLS_modinfo tmi;
122 Phdr *tlsphdr;
123 void (*fptr)(TLS_modinfo *);
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;
133 tlsphdr = PTTLS(lmp);
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);
140 if (!(FLAGS(lmp) & FLG_RT_FIXED))
141 tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
142 ADDR(lmp));
144 tmi.tm_filesz = tlsphdr->p_filesz;
145 tmi.tm_memsz = tlsphdr->p_memsz;
146 tmi.tm_flags = 0;
147 tmi.tm_stattlsoffset = 0;
149 DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
150 (*fptr)(&tmi);
153 * Tag that this link-map has registered its TLS, and, if this object
154 * is being removed, free up the module id.
156 FLAGS1(lmp) |= FL1_RT_TLSADD;
158 if (flag & TM_FLG_MODREM)
159 tls_freemodid(TLSMODID(lmp));
162 static ulong_t tls_static_size = 0; /* static TLS buffer size */
163 static ulong_t tls_static_resv = 512; /* (extra) static TLS reservation */
166 * Track any static TLS use, retain the TLS header, and assign a TLS module
167 * identifier.
170 tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
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;
177 * If this object explicitly references static TLS, then there are some
178 * limitations.
180 if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
182 * Static TLS is only available to objects on the primary
183 * link-map list.
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);
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.
202 if (rtld_flags2 & RT_FL2_PLMSETUP) {
204 * Initialized static TLS can not be satisfied from the
205 * TLS backup reservation.
207 if (filesz) {
208 eprintf(lml, ERR_FATAL,
209 MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
210 return (0);
214 * Make sure the backup reservation is sufficient.
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);
223 tls_static_resv -= memsz;
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.
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;
239 * Retain the PT_TLS header, obtain a new module identifier, and
240 * indicate that this link-map list contains a new TLS object.
242 PTTLS(lmp) = phdr;
243 TLSMODID(lmp) = tls_getmodid();
246 * Now that we have a TLS module id, generate any static TLS reservation
247 * diagnostic.
249 if (resv != tls_static_resv)
250 DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));
252 return (++lml->lm_tls);
256 tls_statmod(Lm_list *lml, Rt_map *lmp)
258 uint_t tlsmodndx, tlsmodcnt = lml->lm_tls;
259 TLS_modinfo **tlsmodlist, *tlsbuflist;
260 Phdr *tlsphdr;
261 void (*fptr)(TLS_modinfo **, ulong_t);
263 fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
266 * Allocate a buffer to report the TLS modules, the buffer consists of:
268 * TLS_modinfo * ptrs[tlsmodcnt + 1]
269 * TLS_modinfo bufs[tlsmodcnt]
271 * The ptrs are initialized to the bufs - except the last one which
272 * null terminates the array.
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.
278 if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
279 (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == NULL)
280 return (0);
282 lml->lm_tls = 0;
285 * If we don't have any TLS modules - report that and return.
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);
296 * Initialize the TLS buffer.
298 tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
299 ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
301 for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
302 tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
305 * Account for the initial dtv ptr in the TLSSIZE calculation.
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;
313 tlsphdr = PTTLS(lmp);
315 tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
316 tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
317 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
319 if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
320 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
321 ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
322 ADDR(lmp));
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++;
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));
336 * We're done with the list - clean it up.
338 free(tlsmodlist);
339 return (1);