version 1.1, 2014/03/24 08:28:25
|
version 1.2, 2014/03/29 11:10:52
|
Line 14
|
Line 14
|
#define shdr Elf64_Shdr |
#define shdr Elf64_Shdr |
#define sym Elf64_Sym |
#define sym Elf64_Sym |
#define dyn Elf64_Dyn |
#define dyn Elf64_Dyn |
|
#define rela Elf64_Rela |
|
#define R_SYM ELF64_R_SYM |
|
#define R_TYPE ELF64_R_TYPE |
|
|
#else |
#else |
|
|
Line 22
|
Line 25
|
#define shdr Elf32_Shdr |
#define shdr Elf32_Shdr |
#define sym Elf32_Sym |
#define sym Elf32_Sym |
#define dyn Elf32_Dyn |
#define dyn Elf32_Dyn |
|
#define rela Elf32_Rela |
|
#define R_SYM ELF32_R_SYM |
|
#define R_TYPE ELF32_R_TYPE |
|
|
#endif |
#endif |
|
|
static int errno; |
static int errno; |
__attribute__((visibility("hidden"))) int* __errno_location(void) { return &errno; } |
__attribute__((visibility("hidden"))) int* __errno_location(void) { return &errno; } |
|
|
static size_t _strlen(const char*s) { |
static size_t _strlen(const char* s) { |
size_t i; |
size_t i; |
for (i=0; s[i]; ++i); |
for (i=0; s[i]; ++i); |
return i; |
return i; |
Line 125 static char* ldlp;
|
Line 131 static char* ldlp;
|
static struct dll { |
static struct dll { |
struct dll* next; |
struct dll* next; |
ehdr* e; |
ehdr* e; |
shdr* s; |
|
void* code,* data; |
void* code,* data; |
size_t codelen,datalen,codeplus; |
size_t codelen,datalen,codeplus; |
char name[1]; // asciiz of library name |
char name[1]; // asciiz of library name |
} *dlls, dllroot; |
} *dlls, dllroot; |
|
|
static int map_sections(int fd,const ehdr* e,const phdr* p,struct dll* D) { |
static int map_sections(int fd,const ehdr* e,const phdr* p,struct dll* D) { |
shdr* s; |
|
size_t i; |
size_t i; |
uintptr_t codeplus=0; |
uintptr_t codeplus=0; |
|
|
s=0; |
|
for (i=0; i<e->e_phnum; ++i) { |
for (i=0; i<e->e_phnum; ++i) { |
if (p[i].p_type==PT_LOAD) { |
if (p[i].p_type==PT_LOAD) { |
size_t delta=p[i].p_offset%4096; |
size_t delta=p[i].p_offset%4096; |
Line 198 static int map_sections(int fd,const ehd
|
Line 201 static int map_sections(int fd,const ehd
|
/* in case the can't happen branch ever happens */ |
/* in case the can't happen branch ever happens */ |
D->e=(ehdr*)c; |
D->e=(ehdr*)c; |
D->code=c+rolen; D->codelen=len; |
D->code=c+rolen; D->codelen=len; |
D->s=(shdr*)(c+e->e_shoff); |
// D->s=(shdr*)(c+e->e_shoff); |
if (rolen>=4096) /* if we extended the mapping in the front, remove exec permissions */ |
if (rolen>=4096) /* if we extended the mapping in the front, remove exec permissions */ |
mprotect(c,rolen&~4095,PROT_READ); |
mprotect(c,rolen&~4095,PROT_READ); |
if (!vaddr) codeplus=(uintptr_t)(c+rolen); |
if (!vaddr) codeplus=(uintptr_t)(c+rolen); |
Line 304 static int map_sections(int fd,const ehd
|
Line 307 static int map_sections(int fd,const ehd
|
} |
} |
} |
} |
} |
} |
#if 0 |
|
/* map the section table separately */ |
|
{ |
|
size_t delta=e->e_shoff&4095; |
|
s=mmap(0,delta+e->e_shnum*e->e_shentsize,PROT_READ,MAP_SHARED,fd,e->e_shoff-delta); |
|
if (s==MAP_FAILED) { |
|
__write2("mmap failed!\n"); |
|
return 1; |
|
} |
|
D->s=(shdr*)((char*)s + delta); |
|
} |
|
#endif |
|
return 0; |
return 0; |
} |
} |
|
|
Line 391 kaputt:
|
Line 382 kaputt:
|
D->next=0; |
D->next=0; |
D->code=dll.code; D->codelen=dll.codelen; |
D->code=dll.code; D->codelen=dll.codelen; |
D->data=dll.data; D->datalen=dll.datalen; |
D->data=dll.data; D->datalen=dll.datalen; |
D->s=dll.s; |
// D->s=dll.s; |
D->e=dll.e; |
D->e=dll.e; |
D->codeplus=dll.codeplus; |
D->codeplus=dll.codeplus; |
{ |
{ |
Line 454 again:
|
Line 445 again:
|
return r; |
return r; |
} |
} |
|
|
static int loadlibs(ehdr* e,char* codemap,char* datamap,shdr* s) { |
static int loadlibs(struct dll* D) { |
size_t i; |
size_t i; |
phdr* p=(phdr*)((char*)e+e->e_phoff); |
phdr* p=(phdr*)((char*)D->e+D->e->e_phoff); |
phdr* code,* data; |
|
dyn* d; |
dyn* d; |
size_t dnum,dynstrlen; |
size_t dnum,dynstrlen; |
char* dynstr; |
char* dynstr; |
|
|
/* we know we have exactly one code and exactly one data segment, |
/* we know we have exactly one code and exactly one data segment, |
* otherwise we wouldn't have gotten this far */ |
* otherwise we wouldn't have gotten this far */ |
for (i=0; i<e->e_phnum; ++i) { |
for (i=0; i<D->e->e_phnum; ++i) |
if (p[i].p_type==PT_LOAD) |
if (p[i].p_type==PT_DYNAMIC) { |
if (p[i].p_flags&PF_X) |
d=(dyn*)((char*)p[i].p_vaddr+D->codeplus); |
code=p+i; |
dnum=p[i].p_memsz/sizeof(dyn); |
else |
|
data=p+i; |
|
} |
|
|
|
d=0; dnum=0; dynstr=0; dynstrlen=0; |
|
for (i=0; i<e->e_shnum; ++i) { |
|
if (s[i].sh_type==SHT_DYNAMIC) { |
|
/* dynamic section must be in data section */ |
|
if (s[i].sh_offset < data->p_offset || s[i].sh_offset+s[i].sh_size<s[i].sh_offset || s[i].sh_offset+s[i].sh_size > data->p_offset+data->p_memsz || |
|
s[i].sh_addr < data->p_vaddr || s[i].sh_addr+s[i].sh_size > data->p_vaddr+data->p_memsz || s[i].sh_entsize!=sizeof(dyn)) { |
|
__write2("invalid dynamic section offset/size\n"); |
|
return 1; |
|
} |
|
d=(dyn*)(datamap+s[i].sh_addr-data->p_vaddr); |
|
dnum=s[i].sh_size/s[i].sh_entsize; |
|
} else if (s[i].sh_type==SHT_STRTAB) { |
|
/* not sure how to keep the strtabs apart */ |
|
if (s[i].sh_offset < code->p_offset || s[i].sh_offset+s[i].sh_size<s[i].sh_offset || s[i].sh_offset+s[i].sh_size > code->p_offset+code->p_memsz || |
|
s[i].sh_addr < code->p_vaddr || s[i].sh_addr+s[i].sh_size > code->p_vaddr+code->p_memsz) continue; |
|
dynstr=codemap+s[i].sh_addr-code->p_vaddr; |
|
dynstrlen=s[i].sh_size; |
|
if (!dynstrlen || dynstr[dynstrlen-1]) { |
|
__write2("corrupt dynstr section\n"); |
|
return 1; |
|
} |
|
} |
} |
// printf("section %d type %d flags %x addr %p off %lx size %lx link %d info %d align %d entsize %d\n", |
for (i=0; i<dnum; ++i) |
// s[i].sh_name,s[i].sh_type,s[i].sh_flags,s[i].sh_offset,s[i].sh_size,s[i].sh_link,s[i].sh_info,s[i].sh_addralign,s[i].sh_entsize); |
if (d[i].d_tag==DT_STRTAB) |
} |
dynstr=(char*)d[i].d_un.d_ptr+D->codeplus; |
|
|
/* we now have a dynamic section we can traverse */ |
/* we now have a dynamic section we can traverse */ |
for (i=0; i<dnum; ++i) { |
for (i=0; i<dnum; ++i) { |
if (d[i].d_tag==DT_NEEDED) { |
if (d[i].d_tag==DT_NEEDED) { |
#if 0 |
|
__write1("needed library: "); |
|
__write1(dynstr+d[i].d_un.d_val); |
|
__write1("\n"); |
|
#endif |
|
if (loadlibrary(dynstr+d[i].d_un.d_val)) { |
if (loadlibrary(dynstr+d[i].d_un.d_val)) { |
__write2("library "); |
__write2("library "); |
__write2(dynstr+d[i].d_un.d_val); |
__write2(dynstr+d[i].d_un.d_val); |
Line 539 static uint_fast32_t gnu_hash(const unsi
|
Line 499 static uint_fast32_t gnu_hash(const unsi
|
return (h&0xffffffff); |
return (h&0xffffffff); |
} |
} |
|
|
static char* dlsym(const char* symbol) { |
static char* dlsym_int(const char* symbol,struct dll* x) { |
struct dll* x; |
for (; x; x=x->next) { |
for (x=&dllroot; x; x=x->next) { |
|
size_t i; |
size_t i; |
shdr* s=(shdr*)((char*)x->e + x->e->e_shoff); |
|
dyn* d; |
dyn* d; |
sym* sy; |
sym* sy; |
|
phdr* p=(phdr*)(x->e->e_phoff+(char*)x->e); |
const char* strtab; |
const char* strtab; |
size_t dnum; |
size_t dnum; |
int* hash=0; |
int* hash=0; |
for (i=0; i<x->e->e_shnum; ++i) |
for (i=0; i<x->e->e_phnum; ++i) |
if (s[i].sh_type==SHT_DYNAMIC) { |
if (p[i].p_type==PT_DYNAMIC) { |
d=(dyn*)(x->codeplus + s[i].sh_addr); |
d=(dyn*)(x->codeplus + p[i].p_vaddr); |
dnum=s[i].sh_size/s[i].sh_entsize; |
dnum=p[i].p_memsz/sizeof(dyn); |
break; |
break; |
} |
} |
|
|
Line 589 static char* dlsym(const char* symbol) {
|
Line 548 static char* dlsym(const char* symbol) {
|
return 0; |
return 0; |
} |
} |
|
|
|
static void* dlsym(const char* s) { |
|
return dlsym_int(s,&dllroot); |
|
} |
|
|
|
static void* _dlsym(const char* s) { |
|
const void* x=dlsym(s); |
|
if (!x) { |
|
__write2("ld.so: lookup of symbol \""); |
|
__write2(s); |
|
__write2("\" failed.\n"); |
|
// exit(1); |
|
} |
|
return x; |
|
} |
|
|
|
static void resolve(struct dll* D) { |
|
size_t i; |
|
phdr* p=(phdr*)((char*)D->e+D->e->e_phoff); |
|
dyn* d=0; |
|
size_t dnum,dynstrlen,rnum=0; |
|
char* dynstr=0, *pltgot=0, *pltrel=0; |
|
rela* r=0; |
|
sym* symtab=0; |
|
|
|
/* we know we have exactly one code and exactly one data segment, |
|
* otherwise we wouldn't have gotten this far */ |
|
for (i=0; i<D->e->e_phnum; ++i) |
|
if (p[i].p_type==PT_DYNAMIC) { |
|
d=(dyn*)((char*)p[i].p_vaddr+D->codeplus); |
|
dnum=p[i].p_memsz/sizeof(dyn); |
|
break; |
|
} |
|
for (i=0; i<dnum; ++i) |
|
if (d[i].d_tag==DT_STRTAB) |
|
dynstr=(char*)d[i].d_un.d_ptr+D->codeplus; |
|
else if (d[i].d_tag==DT_RELA) |
|
r=(rela*)((char*)d[i].d_un.d_ptr+D->codeplus); |
|
else if (d[i].d_tag==DT_RELASZ) |
|
rnum=d[i].d_un.d_val/sizeof(rela); |
|
else if (d[i].d_tag==DT_SYMTAB) |
|
symtab=(sym*)((char*)d[i].d_un.d_ptr+D->codeplus); |
|
else if (d[i].d_tag==0) |
|
break; |
|
|
|
for (i=0; i<rnum; ++i) { |
|
size_t* x=(size_t*)((char*)(r[i].r_offset+D->codeplus)); |
|
size_t sym=R_SYM(r[i].r_info); |
|
switch (R_TYPE(r[i].r_info)) { |
|
#if defined(__x86_64__) |
|
case R_X86_64_64: |
|
*x=D->codeplus+symtab[sym].st_value; |
|
break; |
|
case R_X86_64_COPY: |
|
_memcpy(x,dlsym_int(symtab[sym].st_name+dynstr,D->next),symtab[sym].st_size); |
|
break; |
|
case R_X86_64_GLOB_DAT: |
|
case R_X86_64_JUMP_SLOT: |
|
*x=(uintptr_t)_dlsym(symtab[sym].st_name+dynstr); |
|
break; |
|
case R_X86_64_RELATIVE: |
|
*x=r[i].r_addend+D->codeplus; |
|
break; |
|
case R_X86_64_32: |
|
*(uint32_t*)x=*(uint32_t*)_dlsym(symtab[sym].st_name+dynstr)+r[i].r_addend; |
|
break; |
|
default: |
|
__write2("unknown relocation type!\n"); |
|
exit(1); |
|
break; |
|
#else |
|
#error fixme: add relocation types for your platform |
|
#endif |
|
} |
|
} |
|
|
|
return; |
|
} |
|
|
int main(int argc,char* argv[],char* envp[]) { |
int main(int argc,char* argv[],char* envp[]) { |
int fd; |
int fd; |
size_t l; |
size_t l; |
Line 707 kaputt:
|
Line 744 kaputt:
|
} |
} |
close(fd); |
close(fd); |
|
|
loadlibs(dllroot.e,dllroot.code,dllroot.data,dllroot.s); |
loadlibs(&dllroot); |
|
|
/* now load the prerequisites of the libraries we loaded */ |
/* now load the prerequisites of the libraries we loaded */ |
{ |
{ |
struct dll* x; |
struct dll* x; |
for (x=dlls; x; x=x->next) { |
for (x=dlls; x; x=x->next) { |
loadlibs(x->e,x->code,x->data,x->s); |
loadlibs(x); |
} |
} |
} |
} |
|
|
|
resolve(&dllroot); |
|
|
|
{ |
|
int (*_init)(int argc,char* argv[],char* envp[])=(void*)e->e_entry; |
|
return _init(argc,argv,envp); |
|
} |
|
#if 0 |
{ |
{ |
char* x=dlsym("theint"); |
char* x=dlsym("theint"); |
__write1("done"); |
__write1("done\n"); |
} |
} |
|
#endif |
|
|
#if 0 |
#if 0 |
printf("jump to %p\n",e->e_entry); |
printf("jump to %p\n",e->e_entry); |