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