diff options
Diffstat (limited to 'src/libmach')
-rw-r--r-- | src/libmach/executable.c | 142 |
1 files changed, 87 insertions, 55 deletions
diff --git a/src/libmach/executable.c b/src/libmach/executable.c index a93a8c268..91c0cbe76 100644 --- a/src/libmach/executable.c +++ b/src/libmach/executable.c @@ -1030,8 +1030,8 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) uvlong textsize, datasize, bsssize; uchar *cmdbuf; uchar *cmdp; - int i, hdrsize; - uint32 textva, textoff, datava, dataoff; + int i, j, hdrsize; + uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize; mp = &hp->e.machhdr; if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) { @@ -1116,6 +1116,10 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) textsize = 0; datasize = 0; bsssize = 0; + symoff = 0; + symsize = 0; + pclnoff = 0; + pclnsize = 0; for (i = 0; i < mp->ncmds; i++) { MachCmd *c; @@ -1141,33 +1145,24 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) if (strcmp(seg32->segname, "__TEXT") == 0) { textva = seg32->vmaddr; textoff = seg32->fileoff; + textsize = seg32->vmsize; sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); - if (strcmp(sect32->sectname, "__text") == 0) { - textsize = swal(sect32->size); - } else { - werrstr("no text section"); - goto bad; + for(j = 0; j < seg32->nsects; j++, sect32++) { + if (strcmp(sect32->sectname, "__gosymtab") == 0) { + symoff = swal(sect32->offset); + symsize = swal(sect32->size); + } + if (strcmp(sect32->sectname, "__gopclntab") == 0) { + pclnoff = swal(sect32->offset); + pclnsize = swal(sect32->size); + } } } if (strcmp(seg32->segname, "__DATA") == 0) { datava = seg32->vmaddr; dataoff = seg32->fileoff; - sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32)); - if (strcmp(sect32->sectname, "__data") == 0) { - datasize = swal(sect32->size); - } else { - werrstr("no data section"); - goto bad; - } - sect32++; - if (strcmp(sect32->sectname, "__nl_symbol_ptr") == 0) - sect32++; - if (strcmp(sect32->sectname, "__bss") == 0) { - bsssize = swal(sect32->size); - } else { - werrstr("no bss section"); - goto bad; - } + datasize = seg32->filesize; + bsssize = seg32->vmsize - seg32->filesize; } break; @@ -1188,42 +1183,38 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) if (strcmp(seg->segname, "__TEXT") == 0) { textva = seg->vmaddr; textoff = seg->fileoff; + textsize = seg->vmsize; sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); - if (strcmp(sect->sectname, "__text") == 0) { - textsize = swav(sect->size); - } else { - werrstr("no text section"); - goto bad; + for(j = 0; j < seg->nsects; j++, sect++) { + if (strcmp(sect->sectname, "__gosymtab") == 0) { + symoff = swal(sect->offset); + symsize = swal(sect->size); + } + if (strcmp(sect->sectname, "__gopclntab") == 0) { + pclnoff = swal(sect->offset); + pclnsize = swal(sect->size); + } } } if (strcmp(seg->segname, "__DATA") == 0) { datava = seg->vmaddr; dataoff = seg->fileoff; - sect = (MachSect64*)(cmdp + sizeof(MachSeg64)); - if (strcmp(sect->sectname, "__data") == 0) { - datasize = swav(sect->size); - } else { - werrstr("no data section"); - goto bad; - } - sect++; - if (strcmp(sect->sectname, "__nl_symbol_ptr") == 0) - sect++; - if (strcmp(sect->sectname, "__bss") == 0) { - bsssize = swav(sect->size); - } else { - werrstr("no bss section"); - goto bad; - } + datasize = seg->filesize; + bsssize = seg->vmsize - seg->filesize; } break; case MACH_UNIXTHREAD: break; case MACH_SYMSEG: - if (symtab == 0) + if (symtab == 0) { symtab = (MachSymSeg*)c; - else if (pclntab == 0) + symoff = swal(symtab->fileoff); + symsize = swal(symtab->filesize); + } else if (pclntab == 0) { pclntab = (MachSymSeg*)c; + pclnoff = swal(pclntab->fileoff); + pclnsize = swal(pclntab->filesize); + } break; } cmdp += c->size; @@ -1236,8 +1227,8 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp) /* compute entry by taking address after header - weird - BUG? */ settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff); setdata(fp, datava, datasize, dataoff, bsssize); - if(symtab != 0) - setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0); + if(symoff > 0) + setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize); free(cmd); free(cmdbuf); return 1; @@ -1335,13 +1326,45 @@ typedef struct { IMAGE_DATA_DIRECTORY DataDirectory[16]; } IMAGE_OPTIONAL_HEADER; +typedef struct { + uint16 Magic; + uint8 MajorLinkerVersion; + uint8 MinorLinkerVersion; + uint32 SizeOfCode; + uint32 SizeOfInitializedData; + uint32 SizeOfUninitializedData; + uint32 AddressOfEntryPoint; + uint32 BaseOfCode; + uint64 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; + uint64 SizeOfStackReserve; + uint64 SizeOfStackCommit; + uint64 SizeOfHeapReserve; + uint64 SizeOfHeapCommit; + uint32 LoaderFlags; + uint32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} PE64_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. */ @@ -1353,9 +1376,10 @@ pedotout(int fd, Fhdr *fp, ExecHdr *hp) IMAGE_FILE_HEADER fh; IMAGE_SECTION_HEADER sh; IMAGE_OPTIONAL_HEADER oh; + PE64_IMAGE_OPTIONAL_HEADER oh64; uint8 sym[18]; - uint32 *valp, ib; - int i; + uint32 *valp, ib, entry; + int i, ohoffset; USED(hp); seek(fd, 0x3c, 0); @@ -1384,6 +1408,7 @@ pedotout(int fd, Fhdr *fp, ExecHdr *hp) return 0; } + ohoffset = seek(fd, 0, 1); if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) { werrstr("crippled PE Optional Header"); return 0; @@ -1392,17 +1417,24 @@ pedotout(int fd, Fhdr *fp, ExecHdr *hp) switch(oh.Magic) { case 0x10b: // PE32 fp->type = FI386; + ib = leswal(oh.ImageBase); + entry = leswal(oh.AddressOfEntryPoint); break; case 0x20b: // PE32+ fp->type = FAMD64; + seek(fd, ohoffset, 0); + if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) { + werrstr("crippled PE32+ Optional Header"); + return 0; + } + ib = leswal(oh64.ImageBase); + entry = leswal(oh64.AddressOfEntryPoint); break; default: - werrstr("invalid PE Optional magic number"); + werrstr("invalid PE Optional Header magic number"); return 0; } - ib=leswal(oh.ImageBase); - 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++) { @@ -1411,7 +1443,7 @@ pedotout(int fd, Fhdr *fp, ExecHdr *hp) return 0; } if (match8(sh.Name, ".text")) - settext(fp, ib+leswal(oh.AddressOfEntryPoint), ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData)); + settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData)); if (match8(sh.Name, ".data")) setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData)); } |