00001
00002 #include <stdio.h>
00003
00004 #include "converse.h"
00005 #include "cmitls.h"
00006
00007 #include <string.h>
00008 #include <stdlib.h>
00009 #if CMK_HAS_MALLOC_H
00010 #include <malloc.h>
00011 #endif
00012
00013 #include "memory-isomalloc.h"
00014
00015 #if CMK_HAS_TLS_VARIABLES
00016
00017 extern int quietModeRequested;
00018
00019
00020
00021
00022
00023 #ifndef _GNU_SOURCE
00024 # define _GNU_SOURCE
00025 #endif
00026 #ifndef __USE_GNU
00027 # define __USE_GNU
00028 #endif
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 extern "C" {
00041 void* getTLS();
00042 void setTLS(void*);
00043 void* swapTLS(void*);
00044 }
00045
00046 #if CMK_TLS_SWITCHING_X86_64
00047 # define CMK_TLS_X86_MOV "movq"
00048 # ifdef __APPLE__
00049 # define CMK_TLS_X86_REG "gs"
00050 # else
00051 # define CMK_TLS_X86_REG "fs"
00052 # endif
00053 #elif CMK_TLS_SWITCHING_X86
00054 # define CMK_TLS_X86_MOV "movl"
00055 # define CMK_TLS_X86_REG "gs"
00056 #else
00057 # define CMK_TLS_SWITCHING_UNAVAILABLE
00058 #endif
00059
00060 void* getTLS()
00061 {
00062 #ifdef CMK_TLS_X86_MOV
00063 void* ptr;
00064 asm volatile (CMK_TLS_X86_MOV " %%" CMK_TLS_X86_REG ":0x0, %0\n"
00065 : "=&r"(ptr));
00066 return ptr;
00067 #else
00068 return nullptr;
00069 #endif
00070 }
00071
00072 void setTLS(void* newptr)
00073 {
00074 #ifdef CMK_TLS_X86_MOV
00075 asm volatile (CMK_TLS_X86_MOV " %0, %%" CMK_TLS_X86_REG ":0x0\n\t"
00076 :
00077 : "r"(newptr));
00078 #endif
00079 }
00080
00081 void* swapTLS(void* newptr)
00082 {
00083 void* oldptr = getTLS();
00084 setTLS(newptr);
00085 return oldptr;
00086 }
00087
00088
00089
00090
00091 #if CMK_HAS_DL_ITERATE_PHDR
00092
00093 # include <link.h>
00094
00095 static inline void CmiTLSStatsInit(void)
00096 {
00097 }
00098
00099 static int count_tls_sizes(struct dl_phdr_info* info, size_t size, void* data)
00100 {
00101 size_t i;
00102 tlsseg_t* t = (tlsseg_t*)data;
00103
00104 for (i = 0; i < info->dlpi_phnum; i++)
00105 {
00106 const ElfW(Phdr) * hdr = &info->dlpi_phdr[i];
00107 if (hdr->p_type == PT_TLS)
00108 {
00109 t->size += hdr->p_memsz;
00110 if (t->align < hdr->p_align)
00111 t->align = hdr->p_align;
00112 }
00113 }
00114
00115 return 0;
00116 }
00117
00118 static void populateTLSSegStats(tlsseg_t * t)
00119 {
00120 t->size = 0;
00121 t->align = 0;
00122 dl_iterate_phdr(count_tls_sizes, t);
00123 }
00124
00125 #elif defined __APPLE__
00126
00127
00128
00129 # include <mach-o/dyld.h>
00130 # include <mach-o/nlist.h>
00131
00132 #if __LP64__
00133 typedef struct mach_header_64 macho_header;
00134 # define MACHO_HEADER_MAGIC MH_MAGIC_64
00135 # define LC_SEGMENT_COMMAND LC_SEGMENT_64
00136 typedef struct segment_command_64 macho_segment_command;
00137 typedef struct section_64 macho_section;
00138 typedef struct nlist_64 macho_nlist;
00139 #else
00140 typedef struct mach_header macho_header;
00141 # define MACHO_HEADER_MAGIC MH_MAGIC
00142 # define LC_SEGMENT_COMMAND LC_SEGMENT
00143 typedef struct segment_command macho_segment_command;
00144 typedef struct section macho_section;
00145 typedef struct nlist macho_nlist;
00146 #endif
00147
00148 static size_t GetTLVSizeFromMachOHeader()
00149 {
00150 size_t totalsize = 0;
00151
00152 for (uint32_t c = 0; c < _dyld_image_count(); ++c)
00153 {
00154 const struct mach_header * const mh_orig = _dyld_get_image_header(c);
00155 if (mh_orig == nullptr)
00156 continue;
00157
00158 CmiEnforce(mh_orig->magic == MACHO_HEADER_MAGIC);
00159 const auto mh = (const macho_header *)mh_orig;
00160 const auto mh_addr = (const char *)mh;
00161
00162 const uint8_t * start = nullptr;
00163 unsigned long size = 0;
00164 intptr_t slide = 0;
00165 bool slideComputed = false;
00166
00167 uint64_t text_vmaddr = 0, linkedit_vmaddr = 0, linkedit_fileoff = 0;
00168
00169 const uint32_t cmd_count = mh->ncmds;
00170 const auto cmds = (const struct load_command *)(mh_addr + sizeof(macho_header));
00171 const struct load_command * cmd = cmds;
00172 for (uint32_t i = 0; i < cmd_count; ++i)
00173 {
00174 const auto lc_type = cmd->cmd & ~LC_REQ_DYLD;
00175 if (lc_type == LC_SEGMENT_COMMAND)
00176 {
00177 const auto seg = (const macho_segment_command *)cmd;
00178
00179 if (!slideComputed && seg->filesize != 0)
00180 {
00181 slide = (uintptr_t)mh - seg->vmaddr;
00182 slideComputed = true;
00183 }
00184
00185 if (strcmp(seg->segname, SEG_TEXT) == 0)
00186 text_vmaddr = seg->vmaddr;
00187 else if (strcmp(seg->segname, SEG_LINKEDIT) == 0)
00188 {
00189 linkedit_vmaddr = seg->vmaddr;
00190 linkedit_fileoff = seg->fileoff;
00191 }
00192
00193
00194
00195 const auto sectionsStart = (const macho_section *)((const char *)seg + sizeof(macho_segment_command));
00196 const auto sectionsEnd = sectionsStart + seg->nsects;
00197 for (auto sect = sectionsStart; sect < sectionsEnd; ++sect)
00198 {
00199 const auto section_type = sect->flags & SECTION_TYPE;
00200 if (section_type == S_THREAD_LOCAL_ZEROFILL || section_type == S_THREAD_LOCAL_REGULAR)
00201 {
00202 if (start == nullptr)
00203 {
00204
00205 start = (const uint8_t *)(sect->addr + slide);
00206 size = sect->size;
00207 }
00208 else
00209 {
00210
00211 const auto newEnd = (const uint8_t *)(sect->addr + slide + sect->size);
00212 size = newEnd - start;
00213 }
00214 }
00215 }
00216 }
00217 else if (lc_type == LC_SYMTAB && text_vmaddr)
00218 {
00219
00220
00221 const auto symcmd = (const struct symtab_command *)cmd;
00222 auto strtab = (const char *)(linkedit_vmaddr + (symcmd->stroff - linkedit_fileoff) + slide);
00223 auto symtab = (const macho_nlist *)(linkedit_vmaddr + (symcmd->symoff - linkedit_fileoff) + slide);
00224
00225 for (const macho_nlist * nl = symtab, * const nl_end = symtab + symcmd->nsyms; nl < nl_end; ++nl)
00226 {
00227 if ((nl->n_type & (N_TYPE & N_SECT)) != N_SECT)
00228 continue;
00229
00230 static const char emutls_prefix[] = "___emutls_v.";
00231 const char * const symname = strtab + nl->n_un.n_strx;
00232 if (strncmp(symname, emutls_prefix, sizeof(emutls_prefix)-1) == 0)
00233 {
00234 const auto addr = (const size_t *)(nl->n_value + slide);
00235 const size_t symsize = *addr;
00236 totalsize += symsize;
00237 }
00238 }
00239 }
00240
00241 cmd = (const struct load_command *)(((const char *)cmd) + cmd->cmdsize);
00242 }
00243
00244 totalsize += size;
00245 }
00246
00247 return totalsize;
00248 }
00249
00250 static size_t CmiTLSSize;
00251
00252 static inline void CmiTLSStatsInit(void)
00253 {
00254
00255 CmiTLSSize = GetTLVSizeFromMachOHeader();
00256 }
00257
00258 static void populateTLSSegStats(tlsseg_t * t)
00259 {
00260
00261 t->size = CmiTLSSize;
00262
00263 t->align = 16;
00264 }
00265
00266 #elif CMK_HAS_ELF_H && CMK_DLL_USE_DLOPEN && CMK_HAS_RTLD_DEFAULT
00267
00268 # include <dlfcn.h>
00269 # define CMK_TLS_NO_SHARED
00270
00271 static void* CmiTLSExecutableStart;
00272
00273 static inline Addr getCodeSegAddr()
00274 {
00275 return (Addr) CmiTLSExecutableStart;
00276 }
00277
00278 static inline Ehdr* getELFHeader()
00279 {
00280 return (Ehdr*) getCodeSegAddr();
00281 }
00282
00283 static inline Phdr* getProgramHeader(Ehdr* ehdr)
00284 {
00285 return (Phdr*)((char *)ehdr + ehdr->e_phoff);
00286 }
00287
00288 Phdr* getTLSPhdrEntry()
00289 {
00290 int phnum, i;
00291 Ehdr* elfHeader;
00292 Phdr* progHeader;
00293
00294 elfHeader = getELFHeader();
00295 if (elfHeader == NULL)
00296 return NULL;
00297
00298 phnum = elfHeader->e_phnum;
00299 progHeader = getProgramHeader(elfHeader);
00300 for (i = 0; i < phnum; i++)
00301 {
00302 if (progHeader[i].p_type == PT_TLS)
00303 {
00304 #if CMK_ERROR_CHECKING
00305
00306
00307 int align = progHeader[i].p_align;
00308 CmiAssert(align > 0 && (align & (align-1)) == 0);
00309
00310 CmiAssert(progHeader[i].p_memsz >= progHeader[i].p_filesz);
00311 #endif
00312 return &progHeader[i];
00313 }
00314 }
00315 return NULL;
00316 }
00317
00318 static void CmiTLSStatsInit()
00319 {
00320
00321
00322 void** pCmiExecutableStart = (void**)dlsym(RTLD_DEFAULT, "CmiExecutableStart");
00323 if (pCmiExecutableStart != NULL)
00324 CmiTLSExecutableStart = *pCmiExecutableStart;
00325 else
00326 CmiPrintf("Charm++> Error: \"CmiExecutableStart\" symbol not found. -tlsglobals disabled.\n");
00327 }
00328
00329 static void populateTLSSegStats(tlsseg_t * t)
00330 {
00331 Phdr* phdr = getTLSPhdrEntry();
00332 if (phdr != NULL)
00333 {
00334 t->align = phdr->p_align;
00335 t->size = phdr->p_memsz;
00336 }
00337 else
00338 {
00339 t->size = 0;
00340 t->align = 0;
00341 }
00342 }
00343
00344 #else
00345
00346 static inline void CmiTLSStatsInit()
00347 {
00348 }
00349
00350 static void populateTLSSegStats(tlsseg_t * t)
00351 {
00352 t->size = 0;
00353 }
00354
00355 #endif
00356
00357
00358
00359
00360 void CmiTLSInit()
00361 {
00362 #ifdef CMK_TLS_SWITCHING_UNAVAILABLE
00363 CmiAbort("TLS globals are not supported.");
00364 #else
00365 if (CmiMyRank() == 0)
00366 {
00367 if (!quietModeRequested && CmiMyPe() == 0)
00368 {
00369 CmiPrintf("Charm++> -tlsglobals enabled for privatization of thread-local variables.\n");
00370 #ifdef CMK_TLS_NO_SHARED
00371 CmiPrintf("Charm++> Warning: Unable to examine TLS segments of shared objects.\n");
00372 #endif
00373 }
00374
00375 CmiTLSStatsInit();
00376 }
00377 #endif
00378 }
00379
00380 void allocNewTLSSeg(tlsseg_t* t, CthThread th)
00381 {
00382 populateTLSSegStats(t);
00383
00384 if (t->size > 0)
00385 {
00386 t->size = CMIALIGN(t->size, t->align);
00387 t->memseg = (Addr)CmiIsomallocMallocAlignForThread(th, t->align, t->size);
00388 memcpy((void*)t->memseg, (char *)getTLS() - t->size, t->size);
00389 t->memseg = (Addr)( ((char *)(t->memseg)) + t->size );
00390
00391 }
00392 else
00393 {
00394
00395 t->memseg = (Addr)getTLS();
00396 }
00397 }
00398
00399 void switchTLS(tlsseg_t* cur, tlsseg_t* next)
00400 {
00401 cur->memseg = (Addr)swapTLS((void*)next->memseg);
00402 }
00403
00404 void currentTLS(tlsseg_t* cur)
00405 {
00406 cur->memseg = (Addr)getTLS();
00407 }
00408
00409 #endif