static void load_relocLib(sSharedLib *l) { ElfAddr *got; sElfRel *rel; /* already relocated? */ if(l->relocated) return; /* first go through the dependencies; this may be required for the R_386_COPY-relocation */ for(sDep *dl = l->deps; dl != NULL; dl = dl->next) load_relocLib(dl->lib); if(load_hasDyn(l->dyn,DT_TEXTREL)) load_error("Unable to reloc library %s: requires a writable text segment\n",l->name); DBGDL("Relocating %s (loaded @ %p)\n",l->name,l->loadAddr ? l->loadAddr : l->textAddr); rel = (sElfRel*)load_getDyn(l->dyn,DT_REL); if(rel) load_relocDyn(l,rel,load_getDyn(l->dyn,DT_RELSZ),DT_REL); rel = (sElfRel*)load_getDyn(l->dyn,DT_RELA); if(rel) load_relocDyn(l,rel,load_getDyn(l->dyn,DT_RELASZ),DT_RELA); /* adjust addresses in PLT-jumps */ if(l->jmprel) { load_relocDyn(l,(void*)((uintptr_t)l->jmprel - l->loadAddr), load_getDyn(l->dyn,DT_PLTRELSZ),l->jmprelType); } /* store pointer to library and lookup-function into GOT */ got = (ElfAddr*)load_getDyn(l->dyn,DT_PLTGOT); DBGDL("GOT-Address of %s: %p\n",l->name,got); if(got) { got = (ElfAddr*)((uintptr_t)got + l->loadAddr); got[1] = (ElfAddr)l; got[2] = (ElfAddr)&lookup_resolveStart; } l->relocated = true; /* no longer needed */ close(l->fd); }
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; }
static void load_initLib(sSharedLib *l) { /* already initialized? */ if(l->initialized) return; /* first go through the dependencies */ for(sDep *dl = l->deps; dl != NULL; dl = dl->next) load_initLib(dl->lib); /* if its not the executable, call the init-function */ if(l->isDSO) { uintptr_t initAddr = (uintptr_t)load_getDyn(l->dyn,DT_INIT); if(initAddr) { DBGDL("Calling _init of %s...\n",l->name); void (*initFunc)(void) = (void (*)(void))(initAddr + l->loadAddr); initFunc(); } } l->initialized = true; }
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); } }