diff options
Diffstat (limited to 'src/cmd/ld/pe.c')
-rw-r--r-- | src/cmd/ld/pe.c | 583 |
1 files changed, 0 insertions, 583 deletions
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c deleted file mode 100644 index 9ac0a50d8..000000000 --- a/src/cmd/ld/pe.c +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// PE (Portable Executable) file writing -// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx - -#include "l.h" -#include "../ld/lib.h" -#include "../ld/pe.h" -#include "../ld/dwarf.h" - -// DOS stub that prints out -// "This program cannot be run in DOS mode." -static char dosstub[] = -{ - 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, - 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static Sym *rsrcsym; - -static char symnames[256]; -static int nextsymoff; - -int32 PESECTHEADR; -int32 PEFILEHEADR; - -static int pe64; -static int nsect; -static int nextsectoff; -static int nextfileoff; - -static IMAGE_FILE_HEADER fh; -static IMAGE_OPTIONAL_HEADER oh; -static PE64_IMAGE_OPTIONAL_HEADER oh64; -static IMAGE_SECTION_HEADER sh[16]; -static IMAGE_DATA_DIRECTORY* dd; - -#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v)) -#define put(v) (pe64 ? vputl(v) : lputl(v)) - -typedef struct Imp Imp; -struct Imp { - Sym* s; - uvlong off; - Imp* next; -}; - -typedef struct Dll Dll; -struct Dll { - char* name; - uvlong nameoff; - uvlong thunkoff; - Imp* ms; - Dll* next; -}; - -static Dll* dr; - -static Sym *dexport[1024]; -static int nexport; - -static IMAGE_SECTION_HEADER* -addpesection(char *name, int sectsize, int filesize, Segment *s) -{ - IMAGE_SECTION_HEADER *h; - - if(nsect == 16) { - diag("too many sections"); - errorexit(); - } - h = &sh[nsect++]; - strncpy((char*)h->Name, name, sizeof(h->Name)); - h->VirtualSize = sectsize; - h->VirtualAddress = nextsectoff; - nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN); - h->PointerToRawData = nextfileoff; - if(filesize > 0) { - h->SizeOfRawData = rnd(filesize, PEFILEALIGN); - nextfileoff += h->SizeOfRawData; - } - if(s) { - if(s->vaddr-PEBASE != h->VirtualAddress) { - diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE)); - errorexit(); - } - if(s->fileoff != h->PointerToRawData) { - diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff)); - errorexit(); - } - } - return h; -} - -void -peinit(void) -{ - int32 l; - - switch(thechar) { - // 64-bit architectures - case '6': - pe64 = 1; - l = sizeof(oh64); - dd = oh64.DataDirectory; - break; - // 32-bit architectures - default: - l = sizeof(oh); - dd = oh.DataDirectory; - break; - } - - PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); - PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); - nextsectoff = PESECTHEADR; - nextfileoff = PEFILEHEADR; -} - -static void -pewrite(void) -{ - seek(cout, 0, 0); - ewrite(cout, dosstub, sizeof dosstub); - strnput("PE", 4); - cflush(); - // TODO: This code should not assume that the - // memory representation is little-endian or - // that the structs are packed identically to - // their file representation. - ewrite(cout, &fh, sizeof fh); - if(pe64) - ewrite(cout, &oh64, sizeof oh64); - else - ewrite(cout, &oh, sizeof oh); - ewrite(cout, sh, nsect * sizeof sh[0]); -} - -static void -strput(char *s) -{ - int n; - - for(n=0; *s; n++) - cput(*s++); - cput('\0'); - n++; - // string must be padded to even size - if(n%2) - cput('\0'); -} - -static Dll* -initdynimport(void) -{ - Imp *m; - Dll *d; - Sym *s, *dynamic; - - dr = nil; - m = nil; - for(s = allsym; s != S; s = s->allsym) { - if(!s->reachable || !s->dynimpname || s->dynexport) - continue; - for(d = dr; d != nil; d = d->next) { - if(strcmp(d->name,s->dynimplib) == 0) { - m = mal(sizeof *m); - break; - } - } - if(d == nil) { - d = mal(sizeof *d); - d->name = s->dynimplib; - d->next = dr; - dr = d; - m = mal(sizeof *m); - } - m->s = s; - m->next = d->ms; - d->ms = m; - } - - dynamic = lookup(".windynamic", 0); - dynamic->reachable = 1; - dynamic->type = SWINDOWS; - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->s->type = SWINDOWS | SSUB; - m->s->sub = dynamic->sub; - dynamic->sub = m->s; - m->s->value = dynamic->size; - dynamic->size += PtrSize; - } - dynamic->size += PtrSize; - } - - return dr; -} - -static void -addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) -{ - IMAGE_SECTION_HEADER *isect; - uvlong n, oftbase, ftbase; - Imp *m; - Dll *d; - Sym* dynamic; - - dynamic = lookup(".windynamic", 0); - - // skip import descriptor table (will write it later) - n = 0; - for(d = dr; d != nil; d = d->next) - n++; - seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0); - - // write dll names - for(d = dr; d != nil; d = d->next) { - d->nameoff = cpos() - fileoff; - strput(d->name); - } - - // write function names - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - m->off = nextsectoff + cpos() - fileoff; - wputl(0); // hint - strput(m->s->dynimpname); - } - } - - // write OriginalFirstThunks - oftbase = cpos() - fileoff; - n = cpos(); - for(d = dr; d != nil; d = d->next) { - d->thunkoff = cpos() - n; - for(m = d->ms; m != nil; m = m->next) - put(m->off); - put(0); - } - - // add pe section and pad it at the end - n = cpos() - fileoff; - isect = addpesection(".idata", n, n, 0); - isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - strnput("", isect->SizeOfRawData - n); - cflush(); - - // write FirstThunks (allocated in .data section) - ftbase = dynamic->value - datsect->VirtualAddress - PEBASE; - seek(cout, datsect->PointerToRawData + ftbase, 0); - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) - put(m->off); - put(0); - } - cflush(); - - // finally write import descriptor table - seek(cout, fileoff, 0); - for(d = dr; d != nil; d = d->next) { - lputl(isect->VirtualAddress + oftbase + d->thunkoff); - lputl(0); - lputl(0); - lputl(isect->VirtualAddress + d->nameoff); - lputl(datsect->VirtualAddress + ftbase + d->thunkoff); - } - lputl(0); //end - lputl(0); - lputl(0); - lputl(0); - lputl(0); - cflush(); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; - dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; - dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; - - seek(cout, 0, 2); -} - -static int -scmp(const void *p1, const void *p2) -{ - Sym *s1, *s2; - - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; - return strcmp(s1->dynimpname, s2->dynimpname); -} - -static void -initdynexport(void) -{ - Sym *s; - - nexport = 0; - for(s = allsym; s != S; s = s->allsym) { - if(!s->reachable || !s->dynimpname || !s->dynexport) - continue; - if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { - diag("pe dynexport table is full"); - errorexit(); - } - - dexport[nexport] = s; - nexport++; - } - - qsort(dexport, nexport, sizeof dexport[0], scmp); -} - -void -addexports(vlong fileoff) -{ - IMAGE_SECTION_HEADER *sect; - IMAGE_EXPORT_DIRECTORY e; - int size, i, va, va_name, va_addr, va_na, v; - - size = sizeof e + 10*nexport + strlen(outfile) + 1; - for(i=0; i<nexport; i++) - size += strlen(dexport[i]->dynimpname) + 1; - - if (nexport == 0) - return; - - sect = addpesection(".edata", size, size, 0); - sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ; - va = sect->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va; - dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize; - - seek(cout, fileoff, 0); - va_name = va + sizeof e + nexport*4; - va_addr = va + sizeof e; - va_na = va + sizeof e + nexport*8; - - e.Characteristics = 0; - e.MajorVersion = 0; - e.MinorVersion = 0; - e.NumberOfFunctions = nexport; - e.NumberOfNames = nexport; - e.Name = va + sizeof e + nexport*10; // Program names. - e.Base = 1; - e.AddressOfFunctions = va_addr; - e.AddressOfNames = va_name; - e.AddressOfNameOrdinals = va_na; - // put IMAGE_EXPORT_DIRECTORY - for (i=0; i<sizeof(e); i++) - cput(((char*)&e)[i]); - // put EXPORT Address Table - for(i=0; i<nexport; i++) - lputl(dexport[i]->value - PEBASE); - // put EXPORT Name Pointer Table - v = e.Name + strlen(outfile)+1; - for(i=0; i<nexport; i++) { - lputl(v); - v += strlen(dexport[i]->dynimpname)+1; - } - // put EXPORT Ordinal Table - for(i=0; i<nexport; i++) - wputl(i); - // put Names - strnput(outfile, strlen(outfile)+1); - for(i=0; i<nexport; i++) - strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1); - strnput("", sect->SizeOfRawData - size); - cflush(); - - seek(cout, 0, 2); -} - -void -dope(void) -{ - Sym *rel; - - /* relocation table */ - rel = lookup(".rel", 0); - rel->reachable = 1; - rel->type = SELFDATA; - - initdynimport(); - initdynexport(); -} - -/* - * For more than 8 characters section names, name contains a slash (/) that is - * followed by an ASCII representation of a decimal number that is an offset into - * the string table. - * reference: pecoff_v8.docx Page 24. - * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> - */ -IMAGE_SECTION_HEADER* -newPEDWARFSection(char *name, vlong size) -{ - IMAGE_SECTION_HEADER *h; - char s[8]; - - if(size == 0) - return nil; - - if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { - diag("pe string table is full"); - errorexit(); - } - - strcpy(&symnames[nextsymoff], name); - sprint(s, "/%d\0", nextsymoff+4); - nextsymoff += strlen(name); - symnames[nextsymoff] = 0; - nextsymoff ++; - h = addpesection(s, size, size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - - return h; -} - -static void -addsymtable(void) -{ - IMAGE_SECTION_HEADER *h; - int i, size; - - if(nextsymoff == 0) - return; - - size = nextsymoff + 4; - h = addpesection(".symtab", size, size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_DISCARDABLE; - fh.PointerToSymbolTable = cpos(); - fh.NumberOfSymbols = 0; - // put symbol string table - lputl(size); - for (i=0; i<nextsymoff; i++) - cput(symnames[i]); - strnput("", h->SizeOfRawData - size); - cflush(); -} - -void -setpersrc(Sym *sym) -{ - if(rsrcsym != nil) - diag("too many .rsrc sections"); - - rsrcsym = sym; -} - -void -addpersrc(void) -{ - IMAGE_SECTION_HEADER *h; - uchar *p; - uint32 val; - Reloc *r; - - if(rsrcsym == nil) - return; - - h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0); - h->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; - // relocation - for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) { - p = rsrcsym->p + r->off; - val = h->VirtualAddress + r->add; - // 32-bit little-endian - p[0] = val; - p[1] = val>>8; - p[2] = val>>16; - p[3] = val>>24; - } - ewrite(cout, rsrcsym->p, rsrcsym->size); - strnput("", h->SizeOfRawData - rsrcsym->size); - cflush(); - - // update data directory - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; -} - -void -asmbpe(void) -{ - IMAGE_SECTION_HEADER *t, *d; - - switch(thechar) { - default: - diag("unknown PE architecture"); - errorexit(); - case '6': - fh.Machine = IMAGE_FILE_MACHINE_AMD64; - break; - case '8': - fh.Machine = IMAGE_FILE_MACHINE_I386; - break; - } - - t = addpesection(".text", segtext.len, segtext.len, &segtext); - t->Characteristics = IMAGE_SCN_CNT_CODE| - IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; - - d = addpesection(".data", segdata.len, segdata.filelen, &segdata); - d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| - IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - - if(!debug['s']) - dwarfaddpeheaders(); - - addimports(nextfileoff, d); - - addexports(nextfileoff); - - addsymtable(); - - addpersrc(); - - fh.NumberOfSections = nsect; - fh.TimeDateStamp = time(0); - fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| - IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; - if (pe64) { - fh.SizeOfOptionalHeader = sizeof(oh64); - fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - set(Magic, 0x20b); // PE32+ - } else { - fh.SizeOfOptionalHeader = sizeof(oh); - fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE; - set(Magic, 0x10b); // PE32 - oh.BaseOfData = d->VirtualAddress; - } - set(MajorLinkerVersion, 1); - set(MinorLinkerVersion, 0); - set(SizeOfCode, t->SizeOfRawData); - set(SizeOfInitializedData, d->SizeOfRawData); - set(SizeOfUninitializedData, 0); - set(AddressOfEntryPoint, entryvalue()-PEBASE); - set(BaseOfCode, t->VirtualAddress); - set(ImageBase, PEBASE); - set(SectionAlignment, PESECTALIGN); - set(FileAlignment, PEFILEALIGN); - set(MajorOperatingSystemVersion, 4); - set(MinorOperatingSystemVersion, 0); - set(MajorImageVersion, 1); - set(MinorImageVersion, 0); - set(MajorSubsystemVersion, 4); - set(MinorSubsystemVersion, 0); - set(SizeOfImage, nextsectoff); - set(SizeOfHeaders, PEFILEHEADR); - if(strcmp(headstring, "windowsgui") == 0) - set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI); - else - set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI); - set(SizeOfStackReserve, 0x0040000); - set(SizeOfStackCommit, 0x00001000); - set(SizeOfHeapReserve, 0x00100000); - set(SizeOfHeapCommit, 0x00001000); - set(NumberOfRvaAndSizes, 16); - - pewrite(); -} |