Annotation of dietlibc/ldso.c, revision 1.1

1.1     ! leitner     1: #define errno fnord
        !             2: #include <unistd.h>
        !             3: #include <fcntl.h>
        !             4: #include <sys/mman.h>
        !             5: #include <elf.h>
        !             6: #include <stdlib.h>
        !             7: #include <stdint.h>
        !             8: #undef errno
        !             9: 
        !            10: #if (__WORDSIZE == 64)
        !            11: 
        !            12: #define phdr Elf64_Phdr
        !            13: #define ehdr Elf64_Ehdr
        !            14: #define shdr Elf64_Shdr
        !            15: #define sym Elf64_Sym
        !            16: #define dyn Elf64_Dyn
        !            17: 
        !            18: #else
        !            19: 
        !            20: #define phdr Elf32_Phdr
        !            21: #define ehdr Elf32_Ehdr
        !            22: #define shdr Elf32_Shdr
        !            23: #define sym Elf32_Sym
        !            24: #define dyn Elf32_Dyn
        !            25: 
        !            26: #endif
        !            27: 
        !            28: static int errno;
        !            29: __attribute__((visibility("hidden"))) int* __errno_location(void) { return &errno; }
        !            30: 
        !            31: static size_t _strlen(const char*s) {
        !            32:   size_t i;
        !            33:   for (i=0; s[i]; ++i);
        !            34:   return i;
        !            35: }
        !            36: static char* _stpcpy(char* dest,const char* src) {
        !            37:   size_t i;
        !            38:   for (i=0; src[i]; ++i)
        !            39:     dest[i]=src[i];
        !            40:   dest[i]=0;
        !            41:   return dest+i;
        !            42: }
        !            43: static char* _strchr(char* s,char c) {
        !            44:   size_t i;
        !            45:   for (i=0; s[i] && s[i]!=c; ++i) ;
        !            46:   if (s[i]==c) return s+i; else return NULL;
        !            47: }
        !            48: static int _strcmp(const void* str1,const void* str2) {
        !            49:   const unsigned char* a=str1;
        !            50:   const unsigned char* b=str2;
        !            51:   size_t i;
        !            52:   int r;
        !            53:   for (i=0; (r=(a[i]-b[i]))==0 && a[i]; ++i) ;
        !            54:   return r;
        !            55: }
        !            56: static int _memcmp(const void* dst,const void* src,size_t count) {
        !            57:   const unsigned char* a=dst;
        !            58:   const unsigned char* b=src;
        !            59:   size_t i;
        !            60:   int r;
        !            61:   for (i=0; i<count && (r=(a[i]-b[i]))==0; ++i) ;
        !            62:   return r;
        !            63: }
        !            64: static void* _memcpy(void* dst,const void* src,size_t len) {
        !            65:   char* a=dst;
        !            66:   const char* b=src;
        !            67:   size_t i;
        !            68:   for (i=0; i<len; ++i)
        !            69:     a[i]=b[i];
        !            70:   return dst;
        !            71: }
        !            72: static void _memset(void* dst,unsigned char c,size_t len) {
        !            73:   unsigned char* a=dst;
        !            74:   size_t i;
        !            75:   for (i=0; i<len; ++i) a[i]=c;
        !            76: }
        !            77: static ssize_t __write1(const char* s) {
        !            78:   write(1,s,_strlen(s));
        !            79: }
        !            80: static ssize_t __write2(const char* s) {
        !            81:   write(2,s,_strlen(s));
        !            82: }
        !            83: 
        !            84: ssize_t write(int fd,const void* buf,size_t len) __attribute__((visibility("hidden")));
        !            85: int open(const char* pathname,int flags, ...) __attribute__((visibility("hidden")));
        !            86: ssize_t read(int fd,void* buf,size_t len) __attribute__((visibility("hidden")));
        !            87: int close(int fd) __attribute__((visibility("hidden")));
        !            88: ssize_t pread64(int fd, void *buf, size_t count, off64_t offset) __attribute__((visibility("hidden")));;
        !            89: void *mmap(void *__addr, size_t __len, int __prot, int __flags, int __fd, off_t __offset) __attribute__((visibility("hidden")));
        !            90: int munmap(void *__addr, size_t __len) __attribute__((visibility("hidden")));
        !            91: int mprotect (void *__addr, size_t __len, int __prot) __attribute__((visibility("hidden")));
        !            92: void exit(int res) __attribute__((visibility("hidden")));
        !            93: 
        !            94: static struct page {
        !            95:   struct page* next;
        !            96:   size_t a;
        !            97:   char data[4096-sizeof(size_t)-sizeof(struct page*)];
        !            98: }* heap;
        !            99: 
        !           100: static void* _malloc(size_t l) {
        !           101:   struct page** p;
        !           102:   if (l>sizeof(heap->data)) return 0;
        !           103:   if (l%(sizeof(void*)*2)) {
        !           104:     l += sizeof(void*)*2;
        !           105:     l -= l%(sizeof(void*)*2);
        !           106:   }
        !           107:   for (p=&heap; *p && (*p)->a<l; p=&((*p)->next)) ;
        !           108:   if (!*p) {
        !           109:     void* tmp=mmap(0,4096,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
        !           110:     if (tmp==MAP_FAILED) return 0;
        !           111:     *p=tmp;
        !           112:     (*p)->a=sizeof(heap->data);
        !           113:   }
        !           114:   if (l <= (*p)->a) {
        !           115:     char* tmp=(*p)->data+sizeof((*p)->data)-(*p)->a;
        !           116:     (*p)->a-=l;
        !           117:     return tmp;
        !           118:   } else
        !           119:     return 0;  // can't happen
        !           120: }
        !           121: 
        !           122: static char path[100];
        !           123: static char* ldlp;
        !           124: 
        !           125: static struct dll {
        !           126:   struct dll* next;
        !           127:   ehdr* e;
        !           128:   shdr* s;
        !           129:   void* code,* data;
        !           130:   size_t codelen,datalen,codeplus;
        !           131:   char name[1];                // asciiz of library name
        !           132: } *dlls, dllroot;
        !           133: 
        !           134: static int map_sections(int fd,const ehdr* e,const phdr* p,struct dll* D) {
        !           135:   shdr* s;
        !           136:   size_t i;
        !           137:   uintptr_t codeplus=0;
        !           138: 
        !           139:   s=0;
        !           140:   for (i=0; i<e->e_phnum; ++i) {
        !           141:     if (p[i].p_type==PT_LOAD) {
        !           142:       size_t delta=p[i].p_offset%4096;
        !           143:       size_t maplen=p[i].p_filesz+delta;
        !           144:       size_t bssdiff=(p[i].p_filesz+delta)%4096;
        !           145:       char* c;
        !           146:       if ((p[i].p_flags&PF_W) && (p[i].p_flags&PF_X)) {
        !           147:        __write2("section is both executable and writable, aborting!\n");
        !           148:        return 1;
        !           149:       }
        !           150:       if (p[i].p_flags&PF_X) {
        !           151:        /* code segment */
        !           152:        size_t ofs,len,rolen=0,nolen=0,rolen2=0,vaddr=p[i].p_vaddr,baseofs=0;
        !           153:        /* the first segment will be the code segment, and it will have
        !           154:         * either a fixed address or 0 if it's a shared library. We
        !           155:         * insist that the mapping start at file offset 0, and we extend
        !           156:         * the mapping so it includes the section table */
        !           157:        ofs=p[i].p_offset;
        !           158:        len=p[i].p_filesz;
        !           159:        if (ofs) {
        !           160:          __write2("can't happen error: ofs!=0\n");
        !           161:          exit(1);
        !           162:          if (vaddr)
        !           163:            vaddr-=ofs;
        !           164:          else
        !           165:            baseofs=ofs;
        !           166:          rolen=ofs;
        !           167:          len+=ofs;
        !           168:          ofs=0;
        !           169:        }
        !           170:        if (ofs+len < e->e_shoff+e->e_shnum*e->e_shentsize) {
        !           171:          size_t needed=e->e_shoff+e->e_shnum*e->e_shentsize;
        !           172:          /* if this mapping does not include the section table is not
        !           173:           * included, extend the mapping to include it */
        !           174:          rolen2=e->e_shnum*e->e_shentsize;
        !           175:          if (rolen2>needed-len)
        !           176:            /* we were almost there, part of the section table was
        !           177:             * already mapped */
        !           178:            rolen2=needed-len;
        !           179:          else
        !           180:            nolen=needed-len-rolen2;
        !           181:          /*
        !           182:           * +------------------------+
        !           183:           * | rolen       e->        | if the mapping did not start at beginning of file, this is the beginning of file, PROT_READ
        !           184:           * +------------------------+
        !           185:           * | len         base->     | this is the actual mapping, base points here, PROT_READ|PROT_EXEC
        !           186:           * +------------------------+
        !           187:           * | nolen                  | stuff we don't really need and will mprotect PROT_NONE
        !           188:           * +------------------------+
        !           189:           * | rolen2      e+e->shoff | the section header table, PROT_READ
        !           190:           * +------------------------+
        !           191:           */
        !           192:        }
        !           193:        c=mmap((char*)vaddr,rolen+len+nolen+rolen2,
        !           194:                  ((p[i].p_flags&PF_R)?PROT_READ:0) |
        !           195:                  ((p[i].p_flags&PF_X)?PROT_EXEC:0),
        !           196:                  MAP_SHARED|(vaddr?MAP_FIXED:0),
        !           197:                  fd,0);
        !           198:        /* in case the can't happen branch ever happens */
        !           199:        D->e=(ehdr*)c;
        !           200:        D->code=c+rolen; D->codelen=len;
        !           201:        D->s=(shdr*)(c+e->e_shoff);
        !           202:        if (rolen>=4096)        /* if we extended the mapping in the front, remove exec permissions */
        !           203:          mprotect(c,rolen&~4095,PROT_READ);
        !           204:        if (!vaddr) codeplus=(uintptr_t)(c+rolen);
        !           205:        if (nolen) {
        !           206:          /* We mapped junk in the middle.
        !           207:           * If there are full pages in there, map them PROT_NONE */
        !           208:          char* start=c+rolen+len;
        !           209:          size_t len=nolen;
        !           210:          size_t diff=(-(uintptr_t)start & 4095);
        !           211:          if (diff < nolen) {
        !           212:            /* diff is the part at the beginning we need to skip because
        !           213:             * it's on a page we actually need to be executable.
        !           214:             * Now find out if we overshoot onto a page we want */
        !           215:            size_t removeatend=((uintptr_t)c+rolen+len)&4095;
        !           216:            mprotect(start+diff,len-diff-removeatend,PROT_NONE);
        !           217:          }
        !           218:        }
        !           219:        if (rolen2) {
        !           220:          /* Now we want to mprotect PROT_READ the section table.
        !           221:           * What makes this complex is that mprotect granularity is one
        !           222:           * page.  First figure out the region we are interested in. */
        !           223:          char* start=c+rolen+len+nolen;
        !           224:          size_t len=rolen2;
        !           225:          /* we want to mprotect from start to start+len */
        !           226:          int diff=((uintptr_t)start)&4095;
        !           227:          /* This is the offset of start from the page start.  We need
        !           228:           * to mprotect the whole page -- unless it also has code on
        !           229:           * it, in which case we need to leave it alone */
        !           230:          if (diff > nolen) {
        !           231:            size_t roundup=(-(uintptr_t)start)&4095;
        !           232:            /* we need to skip the first page. Let's see if there is
        !           233:             * anything left in that case */
        !           234:            start+=roundup;
        !           235:            if (rolen2>roundup)
        !           236:              len-=roundup;
        !           237:            else
        !           238:              len=0;
        !           239:          } else {
        !           240:            start-=diff;
        !           241:            len+=diff;
        !           242:          }
        !           243:          if (len) mprotect(start,len,PROT_READ);
        !           244:        }
        !           245:       } else if (p[i].p_flags&PF_W) {  /* data segment */
        !           246:        /* We have already mapped the code segment to base.
        !           247:         * For programs, the base mapping of the code and data segment
        !           248:         * is absolute and we just map there with MAP_FIXED.  For shared
        !           249:         * libraries however, the base mapping of the code segment is 0,
        !           250:         * and the vaddr of the data segment is not absolute but
        !           251:         * relative to the code segment */
        !           252: 
        !           253:        /* The data segment may not start on a page boundary.  Round
        !           254:         * start address if necessary. */
        !           255:        size_t addr,ofs,len,memsetstart=0,memsetend=0,additional=0;
        !           256:        addr=p[i].p_vaddr+codeplus;
        !           257:        ofs=p[i].p_offset;
        !           258:        len=p[i].p_filesz;
        !           259:        if ((memsetstart=(ofs%4096))) {
        !           260:          len+=memsetstart;
        !           261:          ofs-=memsetstart;
        !           262:          addr-=memsetstart;
        !           263:        }
        !           264: 
        !           265:        /* The data segment consists of actual data, but a part of it is
        !           266:         * data initialized to 0, the .bss section.  This section is not
        !           267:         * actually put in the file to save space, but the ELF loader
        !           268:         * (that's us) is expected to allocate that data at program
        !           269:         * start. */
        !           270:        memsetend=p[i].p_memsz-p[i].p_filesz;
        !           271:        if (memsetend) {
        !           272:          /* We have a .bss.  We need to handle two cases.  First: if
        !           273:           * the number of bytes is small enough to fit on the last page
        !           274:           * we already mapped for the data, all we need to do is memset
        !           275:           * it.  Otherwise we needto memset the rest of that page and
        !           276:           * map some additional pages after it. */
        !           277:          size_t bytes_on_last_page=(-len)&4095;
        !           278:          if (memsetend<bytes_on_last_page)
        !           279:            len+=memsetend;
        !           280:          else {
        !           281:            len+=bytes_on_last_page;
        !           282:            additional=memsetend-bytes_on_last_page;
        !           283:            memsetend=bytes_on_last_page;
        !           284:          }
        !           285:        }
        !           286: 
        !           287:        c=mmap((char*)addr,len,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,fd,ofs);
        !           288:        if (c==MAP_FAILED) {
        !           289:          __write2("mmap failed!\n");
        !           290:          return 1;
        !           291:        }
        !           292: 
        !           293:        if (memsetstart) _memset(c,0,memsetstart);
        !           294:        if (memsetend) _memset(c+len-memsetend,0,memsetend);
        !           295:        if (additional) {
        !           296:          char* tmp=mmap(c+len,additional,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);
        !           297:          if (tmp==MAP_FAILED) {
        !           298:            __write2("mmap failed!\n");
        !           299:            return 1;
        !           300:          }
        !           301:        }
        !           302:        D->data=c+memsetstart; D->datalen=len-memsetstart;
        !           303:        D->codeplus=codeplus;
        !           304:       }
        !           305:     }
        !           306:   }
        !           307: #if 0
        !           308:   /* map the section table separately */
        !           309:   {
        !           310:     size_t delta=e->e_shoff&4095;
        !           311:     s=mmap(0,delta+e->e_shnum*e->e_shentsize,PROT_READ,MAP_SHARED,fd,e->e_shoff-delta);
        !           312:     if (s==MAP_FAILED) {
        !           313:       __write2("mmap failed!\n");
        !           314:       return 1;
        !           315:     }
        !           316:     D->s=(shdr*)((char*)s + delta);
        !           317:   }
        !           318: #endif
        !           319:   return 0;
        !           320: }
        !           321: 
        !           322: 
        !           323: static int __loadlibrary(const char* fn) {
        !           324:   struct dll* D;
        !           325:   int fd;
        !           326:   char buf[1000];
        !           327:   ehdr* e;
        !           328:   phdr* p;
        !           329:   shdr* s;
        !           330:   size_t i;
        !           331:   char* code=0,* data=0;
        !           332:   char* base=0;
        !           333:   size_t codelen,datalen;
        !           334: #if 0
        !           335:   __write1("trying ");
        !           336:   __write1(fn);
        !           337:   __write1("\n");
        !           338: #endif
        !           339:   fd=open(fn,O_RDONLY);
        !           340:   if (fd==-1) return -1;
        !           341:   if (read(fd,buf,1000)<1000) {
        !           342: kaputt:
        !           343:     close(fd);
        !           344:     return -1;
        !           345:   }
        !           346:   if (_memcmp(buf,"\177ELF",4)) goto kaputt;
        !           347:   e=(ehdr*)buf;
        !           348: 
        !           349:   if (e->e_ident[4] != (sizeof(size_t)/4) ||   // wrong word size
        !           350:       e->e_type != ET_DYN ||                   // not shared object
        !           351:       e->e_machine !=                          // for different architecture
        !           352: #if defined(__x86_64__)
        !           353:        EM_X86_64
        !           354: #elif defined(__i386__)
        !           355:        EM_386
        !           356: #else
        !           357: #error architecture not recognized, please add
        !           358: #endif
        !           359:                                 ||
        !           360:       e->e_phentsize != sizeof(phdr) ||                // wrong program header entry size
        !           361:       e->e_phnum > 20 ||                       // too many program header entries
        !           362:       e->e_shentsize !=sizeof(shdr) ||         // wrong section header entry size
        !           363:       e->e_shnum > 100)                                // too many sections
        !           364:     goto kaputt;
        !           365: 
        !           366: 
        !           367:   if (e->e_phoff>=1000 || e->e_phentsize*e->e_phnum>1000-e->e_phoff) {
        !           368:     size_t wanted=e->e_phentsize*e->e_phnum;
        !           369:     p=alloca(wanted);
        !           370:     if (pread64(fd,p,wanted,e->e_phoff)!=wanted)
        !           371:       goto kaputt;
        !           372:   } else
        !           373:     p=(phdr*)(buf+e->e_phoff);
        !           374: 
        !           375:   struct dll dll;
        !           376:   if (map_sections(fd,e,p,&dll)) {
        !           377:     __write2("map_sections failed\n");
        !           378:     goto kaputt;
        !           379:   }
        !           380: 
        !           381:   close(fd);
        !           382: 
        !           383:   {
        !           384:     const char* tmp;
        !           385:     for (i=0; fn[i]; ++i)
        !           386:       if (fn[i]=='/') tmp=fn+i;
        !           387:     ++tmp;
        !           388:     D=_malloc(sizeof(struct dll)+_strlen(tmp));
        !           389:     _stpcpy(D->name,tmp);
        !           390:   }
        !           391:   D->next=0;
        !           392:   D->code=dll.code; D->codelen=dll.codelen;
        !           393:   D->data=dll.data; D->datalen=dll.datalen;
        !           394:   D->s=dll.s;
        !           395:   D->e=dll.e;
        !           396:   D->codeplus=dll.codeplus;
        !           397:   {
        !           398:     struct dll** x;
        !           399:     for (x=&dlls; *x; x=&(*x)->next) ;
        !           400:     *x=D;
        !           401:   }
        !           402:   return 0;
        !           403: }
        !           404: 
        !           405: static int loadlibrary(const char* fn) {
        !           406:   char lp[200];
        !           407:   int r;
        !           408:   char* c;
        !           409:   const char* shortname=fn;
        !           410:   struct dll* d;
        !           411: 
        !           412:   {
        !           413:     size_t i;
        !           414:     for (i=0; fn[i]; ++i)
        !           415:       if (fn[i]=='/') shortname=fn+i+1;
        !           416:   }
        !           417: 
        !           418:   if (_strlen(fn)>50) return -1;
        !           419:   for (d=dlls; d; d=d->next)
        !           420:     if (!_strcmp(d->name,shortname))
        !           421:       return 0;
        !           422: 
        !           423:   __write1("loadlibrary(\"");
        !           424:   __write1(fn);
        !           425:   __write1("\")\n");
        !           426:   if (fn[0]=='/') {
        !           427:     return __loadlibrary(fn);
        !           428:   }
        !           429: 
        !           430:   c=_stpcpy(lp,path);
        !           431:   *c++='/';
        !           432:   _stpcpy(c,fn);
        !           433:   r=__loadlibrary(lp);
        !           434:   if (r==0) return r;
        !           435:   if (ldlp) {
        !           436:     size_t i;
        !           437:     char* d;
        !           438:     c=ldlp;
        !           439:     for (i=0; ; ++i) {
        !           440: again:
        !           441:       if (c[i]==':' || c[i]==0) {
        !           442:        if (i<100) {
        !           443:          lp[i]='/';
        !           444:          _stpcpy(lp+i+1,fn);
        !           445:          r=__loadlibrary(lp);
        !           446:          if (r==0) return;
        !           447:        }
        !           448:        if (c[i]==0) break;
        !           449:        c+=i+1; i=0; goto again;
        !           450:       } else
        !           451:        if (i<100) lp[i]=c[i];
        !           452:     }
        !           453:   }
        !           454:   return r;
        !           455: }
        !           456: 
        !           457: static int loadlibs(ehdr* e,char* codemap,char* datamap,shdr* s) {
        !           458:   size_t i;
        !           459:   phdr* p=(phdr*)((char*)e+e->e_phoff);
        !           460:   phdr* code,* data;
        !           461:   dyn* d;
        !           462:   size_t dnum,dynstrlen;
        !           463:   char* dynstr;
        !           464: 
        !           465:   /* we know we have exactly one code and exactly one data segment,
        !           466:    * otherwise we wouldn't have gotten this far */
        !           467:   for (i=0; i<e->e_phnum; ++i) {
        !           468:     if (p[i].p_type==PT_LOAD)
        !           469:       if (p[i].p_flags&PF_X)
        !           470:        code=p+i;
        !           471:       else
        !           472:        data=p+i;
        !           473:   }
        !           474: 
        !           475:   d=0; dnum=0; dynstr=0; dynstrlen=0;
        !           476:   for (i=0; i<e->e_shnum; ++i) {
        !           477:     if (s[i].sh_type==SHT_DYNAMIC) {
        !           478:       /* dynamic section must be in data section */
        !           479:       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 ||
        !           480:          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)) {
        !           481:        __write2("invalid dynamic section offset/size\n");
        !           482:        return 1;
        !           483:       }
        !           484:       d=(dyn*)(datamap+s[i].sh_addr-data->p_vaddr);
        !           485:       dnum=s[i].sh_size/s[i].sh_entsize;
        !           486:     } else if (s[i].sh_type==SHT_STRTAB) {
        !           487:       /* not sure how to keep the strtabs apart */
        !           488:       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 ||
        !           489:          s[i].sh_addr < code->p_vaddr || s[i].sh_addr+s[i].sh_size > code->p_vaddr+code->p_memsz) continue;
        !           490:       dynstr=codemap+s[i].sh_addr-code->p_vaddr;
        !           491:       dynstrlen=s[i].sh_size;
        !           492:       if (!dynstrlen || dynstr[dynstrlen-1]) {
        !           493:        __write2("corrupt dynstr section\n");
        !           494:        return 1;
        !           495:       }
        !           496:     }
        !           497: //    printf("section %d type %d flags %x addr %p off %lx size %lx link %d info %d align %d entsize %d\n",
        !           498: //        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);
        !           499:   }
        !           500: 
        !           501:   /* we now have a dynamic section we can traverse */
        !           502:   for (i=0; i<dnum; ++i) {
        !           503:     if (d[i].d_tag==DT_NEEDED) {
        !           504: #if 0
        !           505:       __write1("needed library: ");
        !           506:       __write1(dynstr+d[i].d_un.d_val);
        !           507:       __write1("\n");
        !           508: #endif
        !           509:       if (loadlibrary(dynstr+d[i].d_un.d_val)) {
        !           510:        __write2("library ");
        !           511:        __write2(dynstr+d[i].d_un.d_val);
        !           512:        __write2(" not found!\n");
        !           513:        exit(2);
        !           514:       }
        !           515:     }
        !           516:   }
        !           517: 
        !           518:   return 0;
        !           519: }
        !           520: 
        !           521: static unsigned int elf_hash(const unsigned char *name) {
        !           522:   unsigned int h=0, g;
        !           523: 
        !           524:   while (*name) {
        !           525:     h = (h<<4) + *(name++);
        !           526:     if ((g = h&0xf0000000)) h ^= g>>24;
        !           527:     h ^= g;
        !           528:   }
        !           529:   return h;
        !           530: }
        !           531: 
        !           532: static uint_fast32_t gnu_hash(const unsigned char *s) {
        !           533:   unsigned char c;
        !           534:   uint_fast32_t h=5381;
        !           535:   for(c=*s;(c!='\0');c=*++s) {
        !           536: //    h=h*33+c;
        !           537:     h=((h<<5)+h)+c;
        !           538:   }
        !           539:   return (h&0xffffffff);
        !           540: }
        !           541: 
        !           542: static char* dlsym(const char* symbol) {
        !           543:   struct dll* x;
        !           544:   for (x=&dllroot; x; x=x->next) {
        !           545:     size_t i;
        !           546:     shdr* s=(shdr*)((char*)x->e + x->e->e_shoff);
        !           547:     dyn* d;
        !           548:     sym* sy;
        !           549:     const char* strtab;
        !           550:     size_t dnum;
        !           551:     int* hash=0;
        !           552:     for (i=0; i<x->e->e_shnum; ++i)
        !           553:       if (s[i].sh_type==SHT_DYNAMIC) {
        !           554:        d=(dyn*)(x->codeplus + s[i].sh_addr);
        !           555:        dnum=s[i].sh_size/s[i].sh_entsize;
        !           556:        break;
        !           557:       }
        !           558: 
        !           559:     for (i=0; i<dnum; ++i) {
        !           560:       if (d[i].d_tag == DT_HASH)
        !           561:        hash=(int*)((char*)x->codeplus + d[i].d_un.d_ptr);
        !           562:       else if (d[i].d_tag == DT_SYMTAB)
        !           563:        sy=(sym*)((char*)(x->codeplus+d[i].d_un.d_ptr));
        !           564:       else if (d[i].d_tag == DT_STRTAB)
        !           565:        strtab=(char*)(x->codeplus+d[i].d_un.d_ptr);
        !           566:     }
        !           567: 
        !           568:     /* hash[0] is the number of buckets. */
        !           569:     /* hash[1] is the hash chain length, not used here */
        !           570:     size_t bhash=elf_hash(symbol)%hash[0];
        !           571:     unsigned int* chain=hash+2+hash[0];
        !           572:     unsigned int index;
        !           573:     for (index=(hash+2)[bhash]; index; index=chain[index]) {
        !           574: #if 0
        !           575:       __write1(strtab+sy[index].st_name); __write1("\n");
        !           576: #endif
        !           577:       if (sy[index].st_value && sy[index].st_shndx!=SHN_UNDEF && !_strcmp(strtab+sy[index].st_name,symbol)) {
        !           578:        return (char*)x->codeplus+sy[index].st_value;
        !           579:       }
        !           580:     }
        !           581: #if 0
        !           582:     if (x->next) {
        !           583:       __write1(" ... next: ");
        !           584:       __write1(x->next->name);
        !           585:       __write1("\n");
        !           586:     }
        !           587: #endif
        !           588:   }
        !           589:   return 0;
        !           590: }
        !           591: 
        !           592: int main(int argc,char* argv[],char* envp[]) {
        !           593:   int fd;
        !           594:   size_t l;
        !           595:   char* m;
        !           596:   char buf[1000];
        !           597:   ehdr* e;
        !           598:   phdr* p;
        !           599:   phdr* code=0,* data=0;
        !           600:   shdr* s;
        !           601:   dyn* d;
        !           602:   size_t dnum;
        !           603:   char* dynstr;
        !           604:   size_t dynstrlen;
        !           605:   size_t i;
        !           606: 
        !           607: #if 0
        !           608:   {
        !           609:     fd=open("/proc/self/maps",O_RDONLY);
        !           610:     if (fd!=-1) {
        !           611:       size_t l;
        !           612:       do {
        !           613:        l=read(fd,buf,sizeof(buf));
        !           614:        write(1,buf,l);
        !           615:       } while (l==sizeof(buf));
        !           616:       close(fd);
        !           617:     }
        !           618:   }
        !           619: #endif
        !           620:   if (argc<2) {
        !           621:     __write2("usage: ld.so /path/to/binary\n");
        !           622:     return 0;
        !           623:   }
        !           624:   fd=open("/etc/diet.ld.conf",O_RDONLY);
        !           625:   if (fd!=-1) {
        !           626:     int r=read(fd,path,99);
        !           627:     if (r>0) path[r]=0;
        !           628:     while (r>0 && path[r-1]=='\n') path[--r]=0;
        !           629:     close(fd);
        !           630:   }
        !           631:   for (i=0; envp[i]; ++i) {
        !           632:     if (_memcmp(envp[i],"LD_LIBRARY_PATH=",16)==0)
        !           633:       ldlp=envp[i]+16;
        !           634:   }
        !           635:   fd=open(argv[1],O_RDONLY);
        !           636:   if (fd==-1) {
        !           637:     __write2("could not open \"");
        !           638:     __write2(argv[1]);
        !           639:     __write2("\".\n");
        !           640:     return 1;
        !           641:   }
        !           642:   l=read(fd,buf,1000);
        !           643:   if (l<sizeof(ehdr) || _memcmp(buf,"\177ELF",4)) {
        !           644: kaputt:
        !           645:     __write2("invalid ELF file \"");
        !           646:     close(fd);
        !           647:     return 1;
        !           648:   }
        !           649:   e=(ehdr*)buf;
        !           650: 
        !           651:   if (e->e_ident[4] != (sizeof(size_t)/4)) {
        !           652:     __write2("wrong word size!\n");
        !           653:     return 1;
        !           654:   }
        !           655: #if 0
        !           656:   if (e->e_ident[7] != ELFOSABI_LINUX) {
        !           657:     __write2("ABI not Linux!\n");
        !           658:     return 1;
        !           659:   }
        !           660: #endif
        !           661:   if (e->e_type != ET_EXEC) {
        !           662:     __write2("not an executable!\n");
        !           663:     return 1;
        !           664:   }
        !           665:   if (e->e_machine !=
        !           666: #if defined(__x86_64__)
        !           667:       EM_X86_64
        !           668: #elif defined(__i386__)
        !           669:       EM_386
        !           670: #else
        !           671: #error architecture not recognized, please add
        !           672: #endif
        !           673:      ) {
        !           674:     __write2("invalid architecture!\n");
        !           675:     return 1;
        !           676:   }
        !           677: 
        !           678:   if (e->e_phentsize != sizeof(phdr)) {
        !           679:     __write2("invalid phentsize!\n");
        !           680:     return 1;
        !           681:   }
        !           682:   if (e->e_phnum > 20) {
        !           683:     __write2("phnum too large!\n");
        !           684:     return 1;
        !           685:   }
        !           686:   if (e->e_shentsize != sizeof(shdr)) {
        !           687:     __write2("invalid shentsize!\n");
        !           688:     return 1;
        !           689:   }
        !           690:   if (e->e_shnum > 100) {
        !           691:     __write2("shnum too large!\n");
        !           692:     return 1;
        !           693:   }
        !           694: 
        !           695:   if (e->e_phoff>=l || e->e_phentsize*e->e_phnum>l-e->e_phoff) {
        !           696:     size_t wanted=e->e_phentsize*e->e_phnum;
        !           697:     p=alloca(wanted);
        !           698:     if (pread64(fd,p,wanted,e->e_phoff)!=wanted)
        !           699:       goto kaputt;
        !           700:   } else
        !           701:     p=(phdr*)(buf+e->e_phoff);
        !           702: 
        !           703:   dlls=&dllroot;
        !           704:   if (map_sections(fd,e,p,&dllroot)) {
        !           705:     __write2("map_sections failed!\n");
        !           706:     return 1;
        !           707:   }
        !           708:   close(fd);
        !           709: 
        !           710:   loadlibs(dllroot.e,dllroot.code,dllroot.data,dllroot.s);
        !           711: 
        !           712:   /* now load the prerequisites of the libraries we loaded */
        !           713:   {
        !           714:     struct dll* x;
        !           715:     for (x=dlls; x; x=x->next) {
        !           716:       loadlibs(x->e,x->code,x->data,x->s);
        !           717:     }
        !           718:   }
        !           719: 
        !           720:   {
        !           721:     char* x=dlsym("theint");
        !           722:     __write1("done");
        !           723:   }
        !           724: 
        !           725: #if 0
        !           726:   printf("jump to %p\n",e->e_entry);
        !           727:   for (i=0; i<16; ++i) {
        !           728:     printf("%02x ",((unsigned char*)e->e_entry)[i]);
        !           729:   }
        !           730: #endif
        !           731: 
        !           732:   return 0;
        !           733: }

LinuxTV legacy CVS <linuxtv.org/cvs>