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