Diff for /dietlibc/ldso.c between versions 1.1 and 1.2

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);

Removed from v.1.1  
changed lines
  Added in v.1.2


LinuxTV legacy CVS <linuxtv.org/cvs>