00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "converse.h"
00043
00044
00045
00046 #if CMI_SWAPGLOBALS
00047
00048 #include "cklists.h"
00049 #include <string.h>
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <errno.h>
00053 #include <sys/types.h>
00054 #if CMK_HAS_REGEX_H
00055 #include <regex.h>
00056 #endif
00057 #include <vector>
00058 #include <algorithm>
00059 #include "converse.h"
00060 #include "pup.h"
00061 #include "memory-isomalloc.h"
00062
00063 #include <elf.h>
00064
00065 #define DEBUG_GOT_MANAGER 0
00066
00067 #define UNPROTECT_GOT 1
00068
00069 #if UNPROTECT_GOT && CMK_HAS_MPROTECT
00070 #include <sys/mman.h>
00071 #if CMK_HAS_GETPAGESIZE
00072 #include <unistd.h>
00073 #endif
00074 #endif
00075
00076 #ifdef __INTEL_COMPILER
00077 #define ALIGN_GOT(x) (long)((~15)&((x)+15))
00078 #else
00079 #define ALIGN_GOT(x) ALIGN8(x)
00080 #endif
00081
00082 CpvDeclare(int, CmiPICMethod);
00083
00084 #if CMK_AMD64
00085 typedef Elf64_Addr ELFXX_TYPE_Addr;
00086 typedef Elf64_Dyn ELFXX_TYPE_Dyn;
00087 typedef Elf64_Rela ELFXX_TYPE_Rel;
00088 typedef Elf64_Sym ELFXX_TYPE_Sym;
00089 #define ELFXX_R_TYPE ELF64_R_TYPE
00090 #define ELFXX_R_SYM ELF64_R_SYM
00091 #define ELFXX_ST_TYPE ELF64_ST_TYPE
00092 #define CMK_DT_REL DT_RELA
00093 #define CMK_DT_RELSZ DT_RELASZ
00094 #define is_elf_global(x) ((x) == R_X86_64_GLOB_DAT)
00095 #else
00096 typedef Elf32_Addr ELFXX_TYPE_Addr;
00097 typedef Elf32_Dyn ELFXX_TYPE_Dyn;
00098 typedef Elf32_Rel ELFXX_TYPE_Rel;
00099 typedef Elf32_Sym ELFXX_TYPE_Sym;
00100 #define ELFXX_R_TYPE ELF32_R_TYPE
00101 #define ELFXX_R_SYM ELF32_R_SYM
00102 #define ELFXX_ST_TYPE ELF32_ST_TYPE
00103 #define CMK_DT_REL DT_REL
00104 #define CMK_DT_RELSZ DT_RELSZ
00105 #define is_elf_global(x) ((x) == R_386_GLOB_DAT)
00106 #endif
00107
00108 extern ELFXX_TYPE_Dyn _DYNAMIC[];
00109
00110
00116 std::vector<char *> _blacklist;
00117 static bool loaded = false;
00118 extern int quietModeRequested;
00119
00120 static void readBlacklist()
00121 {
00122 if (loaded) return;
00123 const char *fname = "blacklist";
00124 FILE *bl = fopen(fname, "r");
00125 if (bl == NULL){
00126 if (!quietModeRequested && CmiMyPe() == 0) {
00127 CmiPrintf("WARNING: Running swapglobals without blacklist, globals from libraries might be unnecessarily swapped.\n");
00128 }
00129 loaded = true;
00130 return;
00131 }
00132 printf("Loading blacklist from file \"%s\" ... \n", fname);
00133 while (!feof(bl)){
00134 char name[512];
00135 if (fscanf(bl, "%511s\n", name) != 1) {
00136 CmiAbort("Swapglobals> reading blacklist file failed!");
00137 }
00138 _blacklist.push_back(strdup(name));
00139 }
00140 fclose(bl);
00141 loaded = true;
00142 }
00143
00144
00145
00146
00147
00151 class CtgGlobalList
00152 {
00153 size_t datalen;
00154 struct CtgRec {
00155 ELFXX_TYPE_Addr *got;
00156 size_t off;
00157 CtgRec() {got=NULL;}
00158 CtgRec(ELFXX_TYPE_Addr *got_,int off_) :got(got_), off(off_) {}
00159 };
00160 std::vector<CtgRec> rec;
00161 public:
00167 CtgGlobalList();
00168
00170 inline size_t getSize(void) const {return datalen;}
00171
00174 void read(void *datav) const;
00175
00177 inline void install(void *datav) const {
00178 intptr_t data = (intptr_t)datav;
00179 int nRec = rec.size();
00180 for (int i=0;i<nRec;i++)
00181 *(rec[i].got)=(ELFXX_TYPE_Addr)(data+rec[i].off);
00182 }
00183
00184 private:
00185
00186
00187
00188 int isUserSymbol(const char *name);
00189 };
00190
00191 int match(const char *string, const char *pattern) {
00192 #if CMK_HAS_REGEX_H
00193 int status;
00194
00195 regex_t re;
00196 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
00197 CmiAbort("error compiling regex");
00198 }
00199 status = regexec(&re, string, (size_t) 0, NULL, 0);
00200 regfree(&re);
00201 if (status == 0) {
00202 return 1;
00203 } else if (status == REG_NOMATCH) {
00204 return 0;
00205 }
00206 perror("error in match\n");
00207 return 0;
00208 #else
00209 CmiPrinf("Warning: elfgot.C::match() is not implemented!\n");
00210 return 0;
00211 #endif
00212 }
00213
00214 int CtgGlobalList::isUserSymbol(const char *name) {
00215
00216 if((strncmp("_", name, 1) == 0) || (strncmp("Cpv_", name, 4) == 0)
00217 || (strncmp("Csv_", name, 4) == 0) || (strncmp("Ctv_", name, 4) == 0)
00218 || (strncmp("Bnv_", name, 4) == 0) || (strncmp("Bpv_", name, 4) == 0)
00219 || (strncmp("ckout", name, 5) == 0) || (strncmp("stdout", name, 6) == 0)
00220 || (strncmp("ckerr", name, 5) == 0)
00221 || (strncmp("environ", name, 7) == 0)
00222 || (strncmp("pthread", name, 7) == 0)
00223 || (strncmp("stderr", name, 6) == 0) || (strncmp("stdin", name, 5) == 0)) {
00224 #ifdef CMK_GFORTRAN
00225 if (match(name, "__.*_MOD_.*")) return 1;
00226 #endif
00227 return 0;
00228 }
00229
00233 for(unsigned int i=0;i<_blacklist.size();i++){
00234 if(strlen(name) == strlen(_blacklist[i]) && strncmp(name,_blacklist[i],strlen(name)) == 0){
00235 return 0;
00236 }
00237 }
00238
00239 return 1;
00240 }
00241
00242 void CtgGlobalList::read(void *datav) const {
00243 char *data=(char *)datav;
00244 int nRec = rec.size();
00245 size_t size;
00246 for (int i=0;i<nRec-1;i++) {
00247 size = rec[i+1].off-rec[i].off;
00248 memcpy(data+rec[i].off, (void *)*rec[i].got, size);
00249 }
00250
00251 if (nRec > 0) {
00252 size = datalen-rec[nRec-1].off;
00253 memcpy(data+rec[nRec-1].off, (void *)(uintptr_t)*rec[nRec-1].got, size);
00254 }
00255 }
00256
00262 CtgGlobalList::CtgGlobalList() {
00263 datalen=0;
00264
00265 int count;
00266 size_t relt_size = 0;
00267 int type, symindx;
00268 char *sym_name;
00269 ELFXX_TYPE_Rel *relt=NULL;
00270 ELFXX_TYPE_Sym *symt=NULL;
00271 char *str_tab=NULL;
00272
00273
00274 for(count = 0; _DYNAMIC[count].d_tag != 0; ++count) {
00275 switch(_DYNAMIC[count].d_tag) {
00276 case CMK_DT_REL:
00277 relt = (ELFXX_TYPE_Rel *) _DYNAMIC[count].d_un.d_ptr;
00278 break;
00279 case CMK_DT_RELSZ:
00280 relt_size = _DYNAMIC[count].d_un.d_val/ sizeof(ELFXX_TYPE_Rel);
00281 break;
00282 case DT_SYMTAB:
00283 symt = (ELFXX_TYPE_Sym *) _DYNAMIC[count].d_un.d_ptr;
00284 break;
00285 case DT_STRTAB:
00286 str_tab = (char *)_DYNAMIC[count].d_un.d_ptr;
00287 break;
00288 }
00289 }
00290
00291 int padding = 0;
00292
00293 #if UNPROTECT_GOT && CMK_HAS_MPROTECT
00294 const size_t pagesize = CmiGetPageSize();
00295 #endif
00296
00297
00298 for(count = 0; count < relt_size; count ++) {
00299 type = ELFXX_R_TYPE(relt[count].r_info);
00300 symindx = ELFXX_R_SYM(relt[count].r_info);
00301
00302 if(!is_elf_global(type))
00303 continue;
00304
00305 sym_name = str_tab + symt[symindx].st_name;
00306
00307 #if DEBUG_GOT_MANAGER
00308 printf("relt[%d]= %s: %d bytes, %p sym, R_==%d\n", count, sym_name,
00309 symt[symindx].st_size, (void *)symt[symindx].st_value, type);
00310 #endif
00311
00312 if(ELFXX_ST_TYPE(symt[symindx].st_info) != STT_OBJECT &&
00313 ELFXX_ST_TYPE(symt[symindx].st_info) != STT_NOTYPE
00314 #if 0
00315 #ifdef __INTEL_COMPILER
00316 && ELFXX_ST_TYPE(symt[symindx].st_info) != STT_FUNC
00317 #endif
00318 #endif
00319 )
00320 continue;
00321
00322 if(strcmp(sym_name, "_DYNAMIC") == 0 ||
00323 strcmp(sym_name, "__gmon_start__") == 0 ||
00324 strcmp(sym_name, "_GLOBAL_OFFSET_TABLE_") == 0)
00325 continue;
00326
00327 if (!isUserSymbol(sym_name))
00328 continue;
00329
00330
00331 size_t size = symt[symindx].st_size;
00332 size_t gSize = ALIGN_GOT(size);
00333 padding += gSize - size;
00334 ELFXX_TYPE_Addr *gGot=(ELFXX_TYPE_Addr *)(uintptr_t)relt[count].r_offset;
00335
00336 #if DEBUG_GOT_MANAGER
00337 printf(" -> %s is a user global, of size %d, at %p\n",
00338 sym_name, size, (void *)*gGot);
00339 #endif
00340 if ((void *)(uintptr_t)*gGot != (void *)(uintptr_t)symt[symindx].st_value)
00341 CmiAbort("CtgGlobalList: symbol table and GOT address mismatch!\n");
00342
00343 #if UNPROTECT_GOT && CMK_HAS_MPROTECT
00344 static void *last = NULL;
00345 void *pg = (void*)(uintptr_t)(((size_t)gGot) & ~(pagesize-1));
00346 if (pg != last) {
00347 mprotect(pg, pagesize, PROT_READ | PROT_WRITE);
00348 last = pg;
00349 }
00350 #endif
00351
00352 rec.emplace_back(gGot, datalen);
00353 datalen+=gSize;
00354 }
00355
00356 #if DEBUG_GOT_MANAGER
00357 printf("relt has %d entries, %d of which are user globals\n\n",
00358 relt_size, rec.size());
00359 printf("Globals take %d bytes (padding bytes: %d)\n", datalen, padding);
00360 #endif
00361 }
00362
00363
00364 CpvStaticDeclare(CtgGlobals,_curCtg);
00365
00366 struct CtgGlobalStruct {
00367 public:
00368
00369 bool installed;
00370
00371
00372 void *data_seg;
00373 size_t seg_size;
00374
00375 void allocate(size_t size, CthThread tid) {
00376 seg_size=size;
00377
00378 if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
00379 data_seg=CmiIsomallocMallocForThread(tid, seg_size);
00380 else
00381 data_seg=malloc(seg_size);
00382 }
00383
00384 CtgGlobalStruct(void) {
00385 installed=false;
00386 data_seg=0;
00387 }
00388 ~CtgGlobalStruct() {
00389 if (data_seg) {
00390 if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
00391 {
00392 #if !CMK_USE_MEMPOOL_ISOMALLOC
00393 CmiIsomallocBlockListFree(data_seg);
00394 #endif
00395 }
00396 else
00397 free(data_seg);
00398 data_seg = NULL;
00399 }
00400 }
00401
00402 void pup(PUP::er &p);
00403 };
00404
00405 void CtgGlobalStruct::pup(PUP::er &p) {
00406 p | seg_size;
00407
00408 if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
00409 #if CMK_USE_MEMPOOL_ISOMALLOC
00410 pup_bytes(&p, &data_seg, sizeof(void*));
00411 #else
00412 CmiIsomallocPup(&p, &data_seg);
00413 #endif
00414 else {
00415 if (p.isUnpacking()) allocate(seg_size, NULL);
00416 p((char *)data_seg, seg_size);
00417 }
00418 }
00419
00421 static CtgGlobalList *_ctgList=NULL;
00423 static CtgGlobalStruct *_ctgListGlobals=NULL;
00424
00426 void CtgInit(void) {
00427 CpvInitialize(int, CmiPICMethod);
00428 CpvAccess(CmiPICMethod) = CMI_PIC_ELFGOT;
00429 CpvInitialize(CtgGlobals,_curCtg);
00430
00431 if (!_ctgList)
00432 {
00433
00434
00435
00436 readBlacklist();
00437 CtgGlobalList *l=new CtgGlobalList;
00438 CtgGlobalStruct *g=new CtgGlobalStruct;
00439 if (!quietModeRequested && CmiMyPe() == 0) {
00440 CmiPrintf("Charm++> -swapglobals enabled for automatic privatization of global variables.\n"
00441 "WARNING> -swapglobals does not handle static variables.\n");
00442 }
00443
00444 g->allocate(l->getSize(), NULL);
00445 l->read(g->data_seg);
00446 l->install(g->data_seg);
00447 _ctgList=l;
00448 _ctgListGlobals=g;
00449 }
00450
00451 CpvAccess(_curCtg)=_ctgListGlobals;
00452 }
00453
00455 CtgGlobals CtgCreate(CthThread tid) {
00456 CtgGlobalStruct *g=new CtgGlobalStruct;
00457 g->allocate(_ctgList->getSize(), tid);
00458 _ctgList->read(g->data_seg);
00459 return g;
00460 }
00462 CtgGlobals CtgPup(pup_er pv, CtgGlobals g) {
00463 PUP::er *p=(PUP::er *)pv;
00464 if (p->isUnpacking()) g=new CtgGlobalStruct;
00465 if (g->installed)
00466 CmiAbort("CtgPup called on currently installed globals!\n");
00467 g->pup(*p);
00468 if (g->seg_size!=_ctgList->getSize())
00469 CmiAbort("CtgPup: global variable size changed during migration!\n");
00470 return g;
00471 }
00472
00474 void CtgInstall(CtgGlobals g) {
00475 CtgGlobals *cur=&CpvAccess(_curCtg);
00476 CtgGlobals oldG=*cur;
00477 if (g==NULL) g=_ctgListGlobals;
00478 if (g == oldG) return;
00479 *cur=g;
00480 oldG->installed=false;
00481 _ctgList->install(g->data_seg);
00482 g->installed=true;
00483 }
00484
00486 void CtgFree(CtgGlobals g) {
00487 if (g->installed) CmiAbort("CtgFree called on currently installed globals!\n");
00488 delete g;
00489 }
00490
00491 CtgGlobals CtgCurrentGlobals(void){
00492 return CpvAccess(_curCtg);
00493 }
00494
00495 #else // CMI_SWAPGLOBALS
00496
00497 #include "global-nop.C"
00498
00499 #endif