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 ((rtld_flags2 & RT_FL2_PLMSETUP) == 0)) { 173 tls_static_size += S_ROUND(PTTLS(lmp)->p_memsz, M_TLSSTATALIGN); 174 TLSSTATOFF(lmp) = tls_static_size; 175 } 176 177 /* 178 * Everyone get's a dynamic TLS modid. 179 */ 180 TLSMODID(lmp) = tls_getmodid(); 181 } 182 183 int 184 tls_statmod(Lm_list *lml, Rt_map *lmp) 185 { 186 uint_t tlsmodndx, tlsmodcnt = lml->lm_tls; 187 TLS_modinfo **tlsmodlist, *tlsbuflist; 188 Phdr *tlsphdr; 189 void (*fptr)(TLS_modinfo **, ulong_t); 190 191 fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func; 192 193 /* 194 * If we don't have any TLS modules - report that and return. 195 */ 196 if (tlsmodcnt == 0) { 197 if (fptr) 198 (*fptr)(0, 0); 199 return (1); 200 } 201 lml->lm_tls = 0; 202 203 /* 204 * Allocate a buffer to report the TLS modules, the buffer consists of: 205 * 206 * TLS_modinfo * ptrs[tlsmodcnt + 1] 207 * TLS_modinfo bufs[tlsmodcnt] 208 * 209 * The ptrs are initialized to the bufs - except the last 210 * one which null terminates the array. 211 */ 212 if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) + 213 (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == 0) 214 return (0); 215 216 tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist + 217 ((tlsmodcnt + 1) * sizeof (TLS_modinfo *))); 218 219 for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++) 220 tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx]; 221 222 /* 223 * Account for the initial dtv ptr in the TLSSIZE calculation. 224 */ 225 tlsmodndx = 0; 226 for (lmp = lml->lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) { 227 if ((FCT(lmp) != &elf_fct) || 228 (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0)) 229 continue; 230 231 tlsphdr = PTTLS(lmp); 232 233 tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp); 234 tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp); 235 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr); 236 237 if (!(FLAGS(lmp) & FLG_RT_FIXED)) { 238 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *) 239 ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock + 240 ADDR(lmp)); 241 } 242 tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz; 243 tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz; 244 tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS; 245 tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp); 246 tlsmodndx++; 247 } 248 249 DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist, 250 tls_static_size)); 251 (*fptr)(tlsmodlist, tls_static_size); 252 253 /* 254 * We're done with the list - clean it up. 255 */ 256 free(tlsmodlist); 257 return (1); 258 } 259