diff options
Diffstat (limited to 'src/libmach/executable.c')
-rw-r--r-- | src/libmach/executable.c | 203 |
1 files changed, 195 insertions, 8 deletions
diff --git a/src/libmach/executable.c b/src/libmach/executable.c index e90334438..3db3e7da4 100644 --- a/src/libmach/executable.c +++ b/src/libmach/executable.c @@ -66,6 +66,7 @@ static int adotout(int, Fhdr*, ExecHdr*); static int elfdotout(int, Fhdr*, ExecHdr*); static int machdotout(int, Fhdr*, ExecHdr*); static int armdotout(int, Fhdr*, ExecHdr*); +static int pedotout(int, Fhdr*, ExecHdr*); static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32); static void setdata(Fhdr*, uvlong, int32, vlong, int32); static void settext(Fhdr*, uvlong, uvlong, int32, vlong); @@ -312,6 +313,15 @@ ExecTable exectab[] = sizeof(Exec), beswal, common }, + { 0x4d5a9000, /* see dosstub[] in pe.c */ + "windows PE executable", + nil, + FWINPE, + 0, + &mi386, + sizeof(Exec), /* TODO */ + nil, + pedotout }, { 0 }, }; @@ -502,6 +512,8 @@ commonllp64(int unused, Fhdr *fp, ExecHdr *hp) int32 pgsize; uvlong entry; + USED(unused); + hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal); if(!(hp->e.exechdr.magic & HDR_MAGIC)) return 0; @@ -542,6 +554,10 @@ commonllp64(int unused, Fhdr *fp, ExecHdr *hp) static int mipsboot(int fd, Fhdr *fp, ExecHdr *hp) { + USED(fd); + USED(fp); + USED(hp); + abort(); #ifdef unused USED(fd); @@ -573,6 +589,10 @@ abort(); static int mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) { + USED(fd); + USED(fp); + USED(hp); + abort(); #ifdef unused USED(fd); @@ -604,6 +624,10 @@ abort(); static int sparcboot(int fd, Fhdr *fp, ExecHdr *hp) { + USED(fd); + USED(fp); + USED(hp); + abort(); #ifdef unused USED(fd); @@ -624,6 +648,10 @@ abort(); static int nextboot(int fd, Fhdr *fp, ExecHdr *hp) { + USED(fd); + USED(fp); + USED(hp); + abort(); #ifdef unused USED(fd); @@ -645,12 +673,11 @@ abort(); static int elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) { - uvlong (*swav)(uvlong); uint32 (*swal)(uint32); ushort (*swab)(ushort); Ehdr64 *ep; - Phdr64 *ph; + Phdr64 *ph, *pph; Shdr64 *sh; int i, it, id, is, phsz, shsz; @@ -770,7 +797,8 @@ elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) } settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset); - setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz); + pph = ph + id; + setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz); if(is != -1) setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz); else if(sh != 0){ @@ -784,7 +812,7 @@ elf64dotout(int fd, Fhdr *fp, ExecHdr *hp) buf = malloc(sh[ep->shstrndx].size); if (buf == 0) goto done; - memset(buf, 0, sizeof buf); + memset(buf, 0, sh[ep->shstrndx].size); seek(fd, sh[ep->shstrndx].offset, 0); i = read(fd, buf, sh[ep->shstrndx].size); USED(i); // shut up ubuntu gcc @@ -962,7 +990,7 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp) buf = malloc(sh[ep->shstrndx].size); if (buf == 0) goto done; - memset(buf, 0, sizeof buf); + memset(buf, 0, sh[ep->shstrndx].size); seek(fd, sh[ep->shstrndx].offset, 0); i = read(fd, buf, sh[ep->shstrndx].size); USED(i); // shut up ubuntu gcc @@ -1022,7 +1050,6 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) mp->sizeofcmds = swal(mp->sizeofcmds); mp->flags = swal(mp->flags); mp->reserved = swal(mp->reserved); - hdrsize = 0; switch(mp->magic) { case 0xFEEDFACE: // 32-bit mach @@ -1077,7 +1104,9 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) datava = 0; symtab = 0; pclntab = 0; - textsize = datasize = bsssize = 0; + textsize = 0; + datasize = 0; + bsssize = 0; for (i = 0; i < mp->ncmds; i++) { MachCmd *c; @@ -1232,6 +1261,165 @@ armdotout(int fd, Fhdr *fp, ExecHdr *hp) return 1; } +/* + * Structures needed to parse PE image. + */ +typedef struct { + uint16 Machine; + uint16 NumberOfSections; + uint32 TimeDateStamp; + uint32 PointerToSymbolTable; + uint32 NumberOfSymbols; + uint16 SizeOfOptionalHeader; + uint16 Characteristics; +} IMAGE_FILE_HEADER; + +typedef struct { + uint8 Name[8]; + uint32 VirtualSize; + uint32 VirtualAddress; + uint32 SizeOfRawData; + uint32 PointerToRawData; + uint32 PointerToRelocations; + uint32 PointerToLineNumbers; + uint16 NumberOfRelocations; + uint16 NumberOfLineNumbers; + uint32 Characteristics; +} IMAGE_SECTION_HEADER; + +typedef struct { + uint32 VirtualAddress; + uint32 Size; +} IMAGE_DATA_DIRECTORY; + +typedef struct { + uint16 Magic; + uint8 MajorLinkerVersion; + uint8 MinorLinkerVersion; + uint32 SizeOfCode; + uint32 SizeOfInitializedData; + uint32 SizeOfUninitializedData; + uint32 AddressOfEntryPoint; + uint32 BaseOfCode; + uint32 BaseOfData; + uint32 ImageBase; + uint32 SectionAlignment; + uint32 FileAlignment; + uint16 MajorOperatingSystemVersion; + uint16 MinorOperatingSystemVersion; + uint16 MajorImageVersion; + uint16 MinorImageVersion; + uint16 MajorSubsystemVersion; + uint16 MinorSubsystemVersion; + uint32 Win32VersionValue; + uint32 SizeOfImage; + uint32 SizeOfHeaders; + uint32 CheckSum; + uint16 Subsystem; + uint16 DllCharacteristics; + uint32 SizeOfStackReserve; + uint32 SizeOfStackCommit; + uint32 SizeOfHeapReserve; + uint32 SizeOfHeapCommit; + uint32 LoaderFlags; + uint32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} IMAGE_OPTIONAL_HEADER; + +static int +match8(void *buf, char *cmp) +{ + return strncmp((char*)buf, cmp, 8) == 0; +} + +/* TODO(czaplinski): 64b windows? */ +/* + * Read from Windows PE/COFF .exe file image. + */ +static int +pedotout(int fd, Fhdr *fp, ExecHdr *hp) +{ + uint32 start, magic; + uint32 symtab, esymtab; + IMAGE_FILE_HEADER fh; + IMAGE_SECTION_HEADER sh; + IMAGE_OPTIONAL_HEADER oh; + uint8 sym[18]; + uint32 *valp; + int i; + + USED(hp); + seek(fd, 0x3c, 0); + if (readn(fd, &start, sizeof(start)) != sizeof(start)) { + werrstr("crippled PE MSDOS header"); + return 0; + } + start = leswal(start); + + seek(fd, start, 0); + if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) { + werrstr("no PE magic number found"); + return 0; + } + if (beswal(magic) != 0x50450000) { /* "PE\0\0" */ + werrstr("incorrect PE magic number"); + return 0; + } + + if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) { + werrstr("crippled PE File Header"); + return 0; + } + if (fh.PointerToSymbolTable == 0) { + werrstr("zero pointer to COFF symbol table"); + return 0; + } + + if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) { + werrstr("crippled PE Optional Header"); + return 0; + } + + seek(fd, start+sizeof(magic)+sizeof(fh)+leswab(fh.SizeOfOptionalHeader), 0); + fp->txtaddr = 0; + fp->dataddr = 0; + for (i=0; i<leswab(fh.NumberOfSections); i++) { + if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) { + werrstr("could not read Section Header %d", i+1); + return 0; + } + if (match8(sh.Name, ".text")) + settext(fp, leswal(sh.VirtualAddress), leswal(oh.AddressOfEntryPoint), leswal(sh.VirtualSize), leswal(sh.PointerToRawData)); + if (match8(sh.Name, ".data")) + setdata(fp, leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData)); + } + if (fp->txtaddr==0 || fp->dataddr==0) { + werrstr("no .text or .data"); + return 0; + } + + seek(fd, leswal(fh.PointerToSymbolTable), 0); + symtab = esymtab = 0; + for (i=0; i<leswal(fh.NumberOfSymbols); i++) { + if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) { + werrstr("crippled COFF symbol %d", i); + return 0; + } + valp = (uint32 *)&sym[8]; + if (match8(sym, "symtab")) + symtab = leswal(*valp); + if (match8(sym, "esymtab")) + esymtab = leswal(*valp); + } + if (symtab==0 || esymtab==0) { + werrstr("no symtab or esymtab in COFF symbol table"); + return 0; + } + setsym(fp, symtab, esymtab-symtab, 0, 0, 0, 0); + + return 1; +} + static void settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off) { @@ -1267,7 +1455,6 @@ setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong l fp->lnpcsz = lnpcsz; } - static uvlong _round(uvlong a, uint32 b) { |