void load_init(int argc,char **argv) { uintptr_t addr; if(lookup_byName(NULL,"__libc_preinit",&addr)) { fPreinit preinit = (fPreinit)addr; preinit(0,argc,argv); } for(sSharedLib *l = libs; l != NULL; l = l->next) load_initLib(l); }
A_REGPARM(0) uintptr_t lookup_resolve(A_UNUSED SavedRegs regs,sSharedLib *lib,size_t off) { #endif sElfSym *foundSym; ulong info,offset; if(lib->jmprelType == DT_REL) { sElfRel *rel = (sElfRel*)((uintptr_t)lib->jmprel + off); info = rel->r_info; offset = rel->r_offset; } else { // TODO it's only the index on x86_64? sElfRela *rel = (sElfRela*)lib->jmprel + off; info = rel->r_info; offset = rel->r_offset; } sElfSym *sym = lib->dynsyms + ELF_R_SYM(info); uintptr_t value = 0,*addr; foundSym = lookup_byName(NULL,lib->dynstrtbl + sym->st_name,&value); if(foundSym == NULL) error("Unable to find symbol %s",lib->dynstrtbl + sym->st_name); addr = (uintptr_t*)(offset + lib->loadAddr); #if defined(CALLTRACE_PID) pid = getpid(); if(pid == CALLTRACE_PID) { if(depth < 100) { sSharedLib *calling = libs; for(sSharedLib *l = libs; l != NULL; l = l->next) { if(retAddr >= l->loadAddr && retAddr < l->loadAddr + l->textSize) { calling = l; break; } } debugf("%*s\\ %x(%s) -> %s (%x)\n",depth,"",retAddr - calling->loadAddr, calling->name,lib->dynstrtbl + sym->st_name,value); depth++; } } else *addr = value; #else DBGDL("Found: %s @ %p (off: %p) in %s (GOT: 0x%x)\n", lib->dynstrtbl + sym->st_name,value,value - lib->loadAddr,lib->name,off); *addr = value; #endif return value; }
uintptr_t load_setupProg(int binFd,A_UNUSED uintptr_t a,A_UNUSED uintptr_t b,A_UNUSED size_t c, int argc,char **argv) { #else uintptr_t load_setupProg(int binFd,int argc,char **argv) { #endif sSharedLib *prog; uintptr_t entryPoint; /* create entry for program */ prog = (sSharedLib*)malloc(sizeof(sSharedLib)); if(!prog) load_error("Not enough mem!"); prog->isDSO = false; prog->relocated = false; prog->initialized = false; prog->dynstrtbl = NULL; prog->dyn = NULL; prog->name = "-Main-"; prog->deps = NULL; appendto(&libs,prog); /* load program including shared libraries into linked list */ load_doLoad(binFd,prog); /* load segments into memory */ entryPoint = load_addSegments(); #if PRINT_LOADADDR for(sSharedLib *l = libs; l != NULL; l = l->next) { uintptr_t addr; lookup_byName(NULL,"_start",&addr); debugf("[%d] Loaded %s @ %p .. %p (text @ %p) with deps: ", getpid(),l->name,l->loadAddr,l->loadAddr + l->textSize,addr); for(sDep *dl = l->deps; dl != NULL; dl = dl->next) debugf("%s ",dl->lib->name); debugf("\n"); } #endif /* relocate everything we need so that the program can start */ load_reloc(); /* call global constructors */ load_init(argc,argv); return entryPoint; }
static void load_relocDyn(sSharedLib *l,void *entries,size_t size,uint type) { sElfRel *rel = (sElfRel*)((uintptr_t)entries + l->loadAddr); sElfRela *rela = (sElfRela*)((uintptr_t)entries + l->loadAddr); size_t count = type == DT_REL ? size / sizeof(sElfRel) : size / sizeof(sElfRela); for(size_t x = 0; x < count; x++) { ulong info,offset,addend; if(type == DT_REL) { info = rel[x].r_info; offset = rel[x].r_offset; addend = 0; } else { info = rela[x].r_info; offset = rela[x].r_offset; addend = rela[x].r_addend; } int rtype = ELF_R_TYPE(info); if(rtype == R_NONE) continue; size_t symIndex = ELF_R_SYM(info); sElfSym *sym = l->dynsyms + symIndex; const char *symname = l->dynstrtbl + sym->st_name; uintptr_t value = sym->st_value; uintptr_t *ptr = (uintptr_t*)(offset + l->loadAddr); if(rtype == R_JUMP_SLOT) { value = *ptr; if(*ptr == 0 || LD_BIND_NOW) { if(!lookup_byName(l,symname,&value)) { if(!lookup_byName(NULL,symname,&value)) load_error("Unable to find symbol '%s'\n",symname); } value -= l->loadAddr; } } /* if the symbol-value is 0, it seems that we have to lookup the symbol now and * store that value instead. TODO I'm not sure if thats correct */ else if(rtype != R_RELATIVE && (rtype == R_COPY || value == 0)) { if(!lookup_byName(l,symname,&value)) load_error("Unable to find symbol '%s'\n",symname); // we'll add that again value -= l->loadAddr; } switch(rtype) { case R_COPY: memcpy((void*)offset,(void*)(value + l->loadAddr),sym->st_size); /* set the GOT-Entry in the library of the symbol to the address we've copied * the value to. TODO I'm not sure if that's the intended way... */ load_adjustCopyGotEntry(symname,offset); break; default: if(!perform_reloc(l,rtype,offset,ptr,value,addend)) { load_error("In library %s: Unknown relocation: off=%p info=%p type=%d addend=%x\n", l->name,offset,info,ELF_R_TYPE(info),addend); } break; } DBGDL("Rel (%s) off=%p reloc=%p value=%p symbol=%s\n", load_getRelName(rtype),offset,*ptr,value,symname); } }