xref: /titanic_51/usr/src/cmd/sgs/rtld/common/tls.c (revision 3e992d44958b161ac51c4643fb42f686bd072ab2)
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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 
29 #include <stdio.h>
30 #include <strings.h>
31 #include <sys/types.h>
32 #include <dlfcn.h>
33 #include <libc_int.h>
34 #include <_rtld.h>
35 #include <_elf.h>
36 #include <msg.h>
37 #include <debug.h>
38 
39 static ulong_t	tls_static_size = 0;	/* static TLS buffer size */
40 
41 #define	TLSBLOCKCNT	16	/* number of blocks of tmi_bits to allocate */
42 				/* at a time. */
43 typedef struct {
44 	uint_t	*tmi_bits;
45 	ulong_t	tmi_lowfree;
46 	ulong_t	tmi_cnt;
47 } Tlsmodid;
48 
49 static Tlsmodid	tmid = {0, 0, 0};
50 
51 ulong_t
52 tls_getmodid()
53 {
54 	ulong_t		ndx;
55 	ulong_t		i;
56 
57 	if (tmid.tmi_bits == 0) {
58 		if ((tmid.tmi_bits = calloc(TLSBLOCKCNT, sizeof (uint_t))) == 0)
59 			return ((ulong_t)-1);
60 		tmid.tmi_bits[0] = 1;
61 		tmid.tmi_lowfree = 1;
62 		tmid.tmi_cnt = TLSBLOCKCNT;
63 		return (0);
64 	}
65 
66 	for (i = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
67 	    i < tmid.tmi_cnt; i++) {
68 		uint_t	j;
69 		/*
70 		 * If all bits are assigned - move on.
71 		 */
72 		if ((tmid.tmi_bits[i] ^ ~((uint_t)0)) == 0)
73 			continue;
74 		for (ndx = 0, j = 1; j; j = j << 1, ndx++) {
75 			if ((tmid.tmi_bits[i] & j) == 0) {
76 				tmid.tmi_bits[i] |= j;
77 				ndx = (i * (sizeof (uint_t)) * 8) + ndx;
78 				tmid.tmi_lowfree = ndx + 1;
79 				return (ndx);
80 			}
81 		}
82 	}
83 
84 	/*
85 	 * All bits taken - must allocate a new block
86 	 */
87 	if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
88 	    ((tmid.tmi_cnt * sizeof (uint_t)) +
89 	    (TLSBLOCKCNT * sizeof (uint_t))))) == 0)
90 		return ((ulong_t)-1);
91 
92 	/*
93 	 * Clear out the tail of the new allocation.
94 	 */
95 	bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
96 	tmid.tmi_bits[tmid.tmi_cnt] = 1;
97 	ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8;
98 	tmid.tmi_lowfree = ndx + 1;
99 	tmid.tmi_cnt += TLSBLOCKCNT;
100 
101 	return (ndx);
102 }
103 
104 void
105 tls_freemodid(ulong_t modid)
106 {
107 	ulong_t	i;
108 	uint_t	j;
109 
110 	i = modid / (sizeof (uint_t) * 8);
111 	/* LINTED */
112 	j = modid % (sizeof (uint_t) * 8);
113 	j = ~(1 << j);
114 	tmid.tmi_bits[i] &= j;
115 	if (modid < tmid.tmi_lowfree)
116 		tmid.tmi_lowfree = modid;
117 }
118 
119 void
120 tls_modaddrem(Rt_map *lmp, uint_t flag)
121 {
122 	Lm_list		*lml = LIST(lmp);
123 	TLS_modinfo	tmi;
124 	Phdr		*tlsphdr;
125 	void		(*fptr)(TLS_modinfo *);
126 
127 	if (flag & TM_FLG_MODADD) {
128 		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
129 	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
130 		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
131 	} else {
132 		return;
133 	}
134 
135 	tlsphdr = PTTLS(lmp);
136 
137 	bzero(&tmi, sizeof (tmi));
138 	tmi.tm_modname = PATHNAME(lmp);
139 	tmi.tm_modid = TLSMODID(lmp);
140 	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
141 
142 	if (!(FLAGS(lmp) & FLG_RT_FIXED))
143 		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
144 			ADDR(lmp));
145 
146 	tmi.tm_filesz = tlsphdr->p_filesz;
147 	tmi.tm_memsz = tlsphdr->p_memsz;
148 	tmi.tm_flags = 0;
149 	tmi.tm_stattlsoffset = 0;
150 
151 	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
152 	(*fptr)(&tmi);
153 
154 	/*
155 	 * Tag that this link-map has registered its TLS, and free up the
156 	 * moduleid
157 	 */
158 	FLAGS1(lmp) |= FL1_RT_TLSADD;
159 
160 	if (flag & TM_FLG_MODREM)
161 		tls_freemodid(TLSMODID(lmp));
162 }
163 
164 void
165 tls_assign_soffset(Rt_map *lmp)
166 {
167 	/*
168 	 * Only objects on the primary link-map list are associated
169 	 * with the STATIC tls block.
170 	 */
171 	if (LIST(lmp)->lm_flags & LML_FLG_BASELM) {
172 		tls_static_size += S_ROUND(PTTLS(lmp)->p_memsz, M_TLSSTATALIGN);
173 		TLSSTATOFF(lmp) = tls_static_size;
174 	}
175 
176 	/*
177 	 * Everyone get's a dynamic TLS modid.
178 	 */
179 	TLSMODID(lmp) = tls_getmodid();
180 }
181 
182 int
183 tls_statmod(Lm_list *lml, Rt_map *lmp)
184 {
185 	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
186 	TLS_modinfo	**tlsmodlist, *tlsbuflist;
187 	Phdr		*tlsphdr;
188 	void		(*fptr)(TLS_modinfo **, ulong_t);
189 
190 	fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
191 
192 	/*
193 	 * If we don't have any TLS modules - report that and return.
194 	 */
195 	if (tlsmodcnt == 0) {
196 		if (fptr)
197 			(*fptr)(0, 0);
198 		return (1);
199 	}
200 	lml->lm_tls = 0;
201 
202 	/*
203 	 * Allocate a buffer to report the TLS modules, the buffer consists of:
204 	 *
205 	 *	TLS_modinfo *	ptrs[tlsmodcnt + 1]
206 	 *	TLS_modinfo	bufs[tlsmodcnt]
207 	 *
208 	 * The ptrs are initialized to the bufs - except the last
209 	 * one which null terminates the array.
210 	 */
211 	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
212 	    (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == 0)
213 		return (0);
214 
215 	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
216 	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
217 
218 	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
219 		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
220 
221 	/*
222 	 * Account for the initial dtv ptr in the TLSSIZE calculation.
223 	 */
224 	tlsmodndx = 0;
225 	for (lmp = lml->lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) {
226 		if ((FCT(lmp) != &elf_fct) ||
227 		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
228 			continue;
229 
230 		tlsphdr = PTTLS(lmp);
231 
232 		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
233 		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
234 		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
235 
236 		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
237 			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
238 			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
239 			    ADDR(lmp));
240 		}
241 		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
242 		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
243 		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
244 		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
245 		tlsmodndx++;
246 	}
247 
248 	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
249 	    tls_static_size));
250 	(*fptr)(tlsmodlist, tls_static_size);
251 
252 	/*
253 	 * We're done with the list - clean it up.
254 	 */
255 	free(tlsmodlist);
256 	return (1);
257 }
258