From eae0a48cf505f5015d59640c9538570eb45ab1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Czapli=C5=84ski?= Date: Mon, 29 Aug 2011 14:25:43 -0400 Subject: [PATCH] libmach: support reading symbols from Windows .exe for nm Fixes #979. R=rsc, alex.brainman CC=golang-dev, vcc.163 https://golang.org/cl/4894051 --- include/mach.h | 1 + src/cmd/ld/pe.c | 32 ++++++-- src/libmach/executable.c | 168 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 8 deletions(-) diff --git a/include/mach.h b/include/mach.h index 5b1ce7b3a9b..cf7151cfd2f 100644 --- a/include/mach.h +++ b/include/mach.h @@ -142,6 +142,7 @@ enum FAMD64B, /* 6.out bootable */ FPOWER64, /* 9.out */ FPOWER64B, /* 9.out bootable */ + FWINPE, /* windows PE executable */ ANONE = 0, /* dissembler types */ AMIPS, diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 334c9959fa0..6379b1ad3a9 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -32,6 +32,11 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +// Note: currently only up to 8 chars plus \0. +static char *symlabels[] = { + "symtab", "esymtab", "pclntab", "epclntab" +}; + static Sym *rsrcsym; static char symnames[256]; @@ -44,6 +49,7 @@ static int pe64; static int nsect; static int nextsectoff; static int nextfileoff; +static int textsect; static IMAGE_FILE_HEADER fh; static IMAGE_OPTIONAL_HEADER oh; @@ -449,20 +455,29 @@ addsymtable(void) { IMAGE_SECTION_HEADER *h; int i, size; + Sym *s; - if(nextsymoff == 0) - return; - - size = nextsymoff + 4 + 18; + fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]); + size = nextsymoff + 4 + 18*fh.NumberOfSymbols; h = addpesection(".symtab", size, size); h->Characteristics = IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_DISCARDABLE; chksectoff(h, cpos()); fh.PointerToSymbolTable = cpos(); - fh.NumberOfSymbols = 1; - strnput("", 18); // one empty symbol - // put symbol string table - lputl(size); + + // put COFF symbol table + for (i=0; iname, 8); + lputl(datoff(s->value)); + wputl(textsect); + wputl(0x0308); // "array of structs" + cput(2); // storage class: external + cput(0); // no aux entries + } + + // put COFF string table + lputl(nextsymoff + 4); for (i=0; iSizeOfRawData - size); @@ -532,6 +547,7 @@ asmbpe(void) IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; chksectseg(t, &segtext); + textsect = nsect; d = addpesection(".data", segdata.len, segdata.filelen); d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| diff --git a/src/libmach/executable.c b/src/libmach/executable.c index 1ad6e3b5d29..fa0fa1b5fdb 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 }, }; @@ -1249,6 +1259,164 @@ 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 = fp->dataddr = 0; + for (i=0; itxtaddr==0 || fp->dataddr==0) { + werrstr("no .text or .data"); + return 0; + } + + seek(fd, leswal(fh.PointerToSymbolTable), 0); + symtab = esymtab = 0; + for (i=0; i