summaryrefslogtreecommitdiff
path: root/src/libmach
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach')
-rw-r--r--src/libmach/executable.c142
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));
}