#include #include #include "linuxsys.h" #include "linux.h" enum { /* file types */ ElfTNone = 0, ElfTReloc = 1, ElfTExec = 2, ElfTShared = 3, ElfTCore = 4, ElfTMax = 5, /* machine architectures */ ElfMNone = 0, ElfM32 = 1, ElfMSparc = 2, ElfM386 = 3, ElfM68 = 4, ElfM88 = 5, ElfM860 = 7, ElfMMips = 8, ElfMMax = 9, /* program segment types */ ElfPNull = 0, ElfPLoad = 1, ElfPDynamic = 2, ElfPInterp = 3, ElfPNote = 4, ElfPShlib = 5, ElfPPhdr = 6, ElfPMax = 7, }; typedef struct Elfhdr Elfhdr; typedef struct Proghdr Proghdr; struct Elfhdr { uchar ident[16]; ushort type; ushort machine; ulong version; ulong entry; ulong phoff; ulong shoff; ulong flags; ushort ehsize; ushort phentsize; ushort phnum; ushort shentsize; ushort shnum; ushort shstrndx; }; struct Proghdr { ulong type; ulong offset; ulong vaddr; ulong paddr; ulong filesz; ulong memsz; ulong flags; ulong align; }; int loadelf(char *file, ElfEx *ex) { static int zfd = -1; int fd; int i, l; int mapprot; int mapflags; ulong mapbase; ulong loadaddr; Elfhdr hdr; Proghdr *phdr; char *interpreter; fd = -1; interpreter = nil; phdr = nil; if(zfd < 0){ if((zfd = open("/dev/zero", OREAD)) < 0) goto errout; } if((fd = open(file, OREAD)) < 0) goto errout; if(readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)){ werrstr("cant read elf header: %r"); goto errout; } if(memcmp(hdr.ident, "\x7fELF", 4)!=0){ werrstr("no elf magic"); goto errout; } l = hdr.phnum * hdr.phentsize; phdr = malloc(l); seek(fd, hdr.phoff, 0); if(readn(fd, phdr, l) != l){ werrstr("cant read program headers"); goto errout; } loadaddr = 0; mapbase = 0; mapflags = MAP_PRIVATE; if(hdr.type != ElfTShared) mapflags |= MAP_FIXED; for(i=0; itype == ElfPInterp){ if(interpreter){ werrstr("multiple interpeter sections"); goto errout; } l = p->filesz; interpreter = malloc(l+1); seek(fd, p->offset, 0); if(readn(fd, interpreter, l)!=l){ werrstr("cant read interpreter section"); goto errout; } interpreter[l] = '\0'; } if(p->type == ElfPLoad){ ulong a; int diff; mapprot = PROT_READ; if(hdr.entry >= p->vaddr && hdr.entry < p->vaddr + p->memsz) mapprot |= PROT_EXEC; diff = p->vaddr - TRUNC_PAGE(p->vaddr); a = (ulong)mmap( (void*)(mapbase + p->vaddr - diff), (p->filesz + diff), mapprot, mapflags, fd, p->offset - diff); if(a == (ulong)-1){ werrstr("mmap failed: %r"); goto errout; } if(loadaddr == 0) loadaddr = a; if(hdr.type == ElfTShared && mapbase == 0){ mapbase = (a - p->vaddr); mapflags |= MAP_FIXED; } if(p->memsz > ROUND_PAGE(p->filesz + diff)){ a = (ulong)mmap( (void*)ROUND_PAGE(a + p->filesz + diff), p->memsz - ROUND_PAGE(p->filesz + diff), mapprot, mapflags, zfd, 0); if(a == (ulong)-1){ werrstr("mmap failed: %r"); goto errout; } } } } ex->base = loadaddr; ex->entry = hdr.entry + ((hdr.type == ElfTShared) ? loadaddr : 0); ex->phdr = loadaddr + hdr.phoff; ex->phent = hdr.phentsize; ex->phnum = hdr.phnum; if(interpreter){ ElfEx interpex; if(loadelf(interpreter, &interpex) < 0){ werrstr("cant load interpreter: %r"); goto errout; } free(interpreter); ex->ientry = interpex.entry; ex->ibase = interpex.base; } else { ex->ientry = ex->entry; ex->ibase = ex->base; } close(fd); free(phdr); return 0; errout: if(interpreter) free(interpreter); if(fd >= 0) close(fd); if(phdr) free(phdr); return -1; }