github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/ld/pe.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // PE (Portable Executable) file writing
     6  // http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
     7  
     8  #include "l.h"
     9  #include "../ld/lib.h"
    10  #include "../ld/pe.h"
    11  #include "../ld/dwarf.h"
    12  
    13  // DOS stub that prints out
    14  // "This program cannot be run in DOS mode."
    15  static char dosstub[] =
    16  {
    17  	0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00,
    18  	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
    19  	0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    20  	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    21  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    22  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    23  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    24  	0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
    25  	0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
    26  	0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
    27  	0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
    28  	0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
    29  	0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
    30  	0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
    31  	0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
    32  	0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    33  };
    34  
    35  // Note: currently only up to 8 chars plus \0.
    36  static char *symlabels[] = {
    37  	"symtab", "esymtab", "pclntab", "epclntab"
    38  };
    39  
    40  static Sym *rsrcsym;
    41  
    42  static char symnames[256]; 
    43  static int  nextsymoff;
    44  
    45  int32 PESECTHEADR;
    46  int32 PEFILEHEADR;
    47  
    48  static int pe64;
    49  static int nsect;
    50  static int nextsectoff;
    51  static int nextfileoff;
    52  static int textsect;
    53  
    54  static IMAGE_FILE_HEADER fh;
    55  static IMAGE_OPTIONAL_HEADER oh;
    56  static PE64_IMAGE_OPTIONAL_HEADER oh64;
    57  static IMAGE_SECTION_HEADER sh[16];
    58  static IMAGE_DATA_DIRECTORY* dd;
    59  
    60  #define	set(n, v)	(pe64 ? (oh64.n = v) : (oh.n = v))
    61  #define	put(v)		(pe64 ? vputl(v) : lputl(v))
    62  
    63  typedef struct Imp Imp;
    64  struct Imp {
    65  	Sym* s;
    66  	uvlong off;
    67  	Imp* next;
    68  };
    69  
    70  typedef struct Dll Dll;
    71  struct Dll {
    72  	char* name;
    73  	uvlong nameoff;
    74  	uvlong thunkoff;
    75  	Imp* ms;
    76  	Dll* next;
    77  };
    78  
    79  static Dll* dr;
    80  
    81  static Sym *dexport[1024];
    82  static int nexport;
    83  
    84  static IMAGE_SECTION_HEADER*
    85  addpesection(char *name, int sectsize, int filesize)
    86  {
    87  	IMAGE_SECTION_HEADER *h;
    88  
    89  	if(nsect == 16) {
    90  		diag("too many sections");
    91  		errorexit();
    92  	}
    93  	h = &sh[nsect++];
    94  	strncpy((char*)h->Name, name, sizeof(h->Name));
    95  	h->VirtualSize = sectsize;
    96  	h->VirtualAddress = nextsectoff;
    97  	nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
    98  	h->PointerToRawData = nextfileoff;
    99  	if(filesize > 0) {
   100  		h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
   101  		nextfileoff += h->SizeOfRawData;
   102  	}
   103  	return h;
   104  }
   105  
   106  static void
   107  chksectoff(IMAGE_SECTION_HEADER *h, vlong off)
   108  {
   109  	if(off != h->PointerToRawData) {
   110  		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off);
   111  		errorexit();
   112  	}
   113  }
   114  
   115  static void
   116  chksectseg(IMAGE_SECTION_HEADER *h, Segment *s)
   117  {
   118  	if(s->vaddr-PEBASE != h->VirtualAddress) {
   119  		diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
   120  		errorexit();
   121  	}
   122  	if(s->fileoff != h->PointerToRawData) {
   123  		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
   124  		errorexit();
   125  	}
   126  }
   127  
   128  void
   129  peinit(void)
   130  {
   131  	int32 l;
   132  
   133  	switch(thechar) {
   134  	// 64-bit architectures
   135  	case '6':
   136  		pe64 = 1;
   137  		l = sizeof(oh64);
   138  		dd = oh64.DataDirectory;
   139  		break;
   140  	// 32-bit architectures
   141  	default:
   142  		l = sizeof(oh);
   143  		dd = oh.DataDirectory;
   144  		break;
   145  	}
   146  	
   147  	PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
   148  	PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
   149  	nextsectoff = PESECTHEADR;
   150  	nextfileoff = PEFILEHEADR;
   151  
   152  	// some mingw libs depend on this symbol, for example, FindPESectionByName
   153  	xdefine("__image_base__", SDATA, PEBASE);
   154  	xdefine("_image_base__", SDATA, PEBASE);
   155  }
   156  
   157  static void
   158  pewrite(void)
   159  {
   160  	cseek(0);
   161  	cwrite(dosstub, sizeof dosstub);
   162  	strnput("PE", 4);
   163  	// TODO: This code should not assume that the
   164  	// memory representation is little-endian or
   165  	// that the structs are packed identically to
   166  	// their file representation.
   167  	cwrite(&fh, sizeof fh);
   168  	if(pe64)
   169  		cwrite(&oh64, sizeof oh64);
   170  	else
   171  		cwrite(&oh, sizeof oh);
   172  	cwrite(sh, nsect * sizeof sh[0]);
   173  }
   174  
   175  static void
   176  strput(char *s)
   177  {
   178  	int n;
   179  
   180  	for(n=0; *s; n++)
   181  		cput(*s++);
   182  	cput('\0');
   183  	n++;
   184  	// string must be padded to even size
   185  	if(n%2)
   186  		cput('\0');
   187  }
   188  
   189  static Dll* 
   190  initdynimport(void)
   191  {
   192  	Imp *m;
   193  	Dll *d;
   194  	Sym *s, *dynamic;
   195  
   196  	dr = nil;
   197  	m = nil;
   198  	for(s = allsym; s != S; s = s->allsym) {
   199  		if(!s->reachable || s->type != SDYNIMPORT)
   200  			continue;
   201  		for(d = dr; d != nil; d = d->next) {
   202  			if(strcmp(d->name,s->dynimplib) == 0) {
   203  				m = mal(sizeof *m);
   204  				break;
   205  			}
   206  		}
   207  		if(d == nil) {
   208  			d = mal(sizeof *d);
   209  			d->name = s->dynimplib;
   210  			d->next = dr;
   211  			dr = d;
   212  			m = mal(sizeof *m);
   213  		}
   214  		m->s = s;
   215  		m->next = d->ms;
   216  		d->ms = m;
   217  	}
   218  	
   219  	dynamic = lookup(".windynamic", 0);
   220  	dynamic->reachable = 1;
   221  	dynamic->type = SWINDOWS;
   222  	for(d = dr; d != nil; d = d->next) {
   223  		for(m = d->ms; m != nil; m = m->next) {
   224  			m->s->type = SWINDOWS | SSUB;
   225  			m->s->sub = dynamic->sub;
   226  			dynamic->sub = m->s;
   227  			m->s->value = dynamic->size;
   228  			dynamic->size += PtrSize;
   229  		}
   230  		dynamic->size += PtrSize;
   231  	}
   232  		
   233  	return dr;
   234  }
   235  
   236  static void
   237  addimports(IMAGE_SECTION_HEADER *datsect)
   238  {
   239  	IMAGE_SECTION_HEADER *isect;
   240  	uvlong n, oftbase, ftbase;
   241  	vlong startoff, endoff;
   242  	Imp *m;
   243  	Dll *d;
   244  	Sym* dynamic;
   245  	
   246  	startoff = cpos();
   247  	dynamic = lookup(".windynamic", 0);
   248  
   249  	// skip import descriptor table (will write it later)
   250  	n = 0;
   251  	for(d = dr; d != nil; d = d->next)
   252  		n++;
   253  	cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));
   254  
   255  	// write dll names
   256  	for(d = dr; d != nil; d = d->next) {
   257  		d->nameoff = cpos() - startoff;
   258  		strput(d->name);
   259  	}
   260  
   261  	// write function names
   262  	for(d = dr; d != nil; d = d->next) {
   263  		for(m = d->ms; m != nil; m = m->next) {
   264  			m->off = nextsectoff + cpos() - startoff;
   265  			wputl(0); // hint
   266  			strput(m->s->extname);
   267  		}
   268  	}
   269  	
   270  	// write OriginalFirstThunks
   271  	oftbase = cpos() - startoff;
   272  	n = cpos();
   273  	for(d = dr; d != nil; d = d->next) {
   274  		d->thunkoff = cpos() - n;
   275  		for(m = d->ms; m != nil; m = m->next)
   276  			put(m->off);
   277  		put(0);
   278  	}
   279  
   280  	// add pe section and pad it at the end
   281  	n = cpos() - startoff;
   282  	isect = addpesection(".idata", n, n);
   283  	isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
   284  		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
   285  	chksectoff(isect, startoff);
   286  	strnput("", isect->SizeOfRawData - n);
   287  	endoff = cpos();
   288  
   289  	// write FirstThunks (allocated in .data section)
   290  	ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
   291  	cseek(datsect->PointerToRawData + ftbase);
   292  	for(d = dr; d != nil; d = d->next) {
   293  		for(m = d->ms; m != nil; m = m->next)
   294  			put(m->off);
   295  		put(0);
   296  	}
   297  	
   298  	// finally write import descriptor table
   299  	cseek(startoff);
   300  	for(d = dr; d != nil; d = d->next) {
   301  		lputl(isect->VirtualAddress + oftbase + d->thunkoff);
   302  		lputl(0);
   303  		lputl(0);
   304  		lputl(isect->VirtualAddress + d->nameoff);
   305  		lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
   306  	}
   307  	lputl(0); //end
   308  	lputl(0);
   309  	lputl(0);
   310  	lputl(0);
   311  	lputl(0);
   312  	
   313  	// update data directory
   314  	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
   315  	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
   316  	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
   317  	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
   318  
   319  	cseek(endoff);
   320  }
   321  
   322  static int
   323  scmp(const void *p1, const void *p2)
   324  {
   325  	Sym *s1, *s2;
   326  
   327  	s1 = *(Sym**)p1;
   328  	s2 = *(Sym**)p2;
   329  	return strcmp(s1->extname, s2->extname);
   330  }
   331  
   332  static void
   333  initdynexport(void)
   334  {
   335  	Sym *s;
   336  	
   337  	nexport = 0;
   338  	for(s = allsym; s != S; s = s->allsym) {
   339  		if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
   340  			continue;
   341  		if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
   342  			diag("pe dynexport table is full");
   343  			errorexit();
   344  		}
   345  		
   346  		dexport[nexport] = s;
   347  		nexport++;
   348  	}
   349  	
   350  	qsort(dexport, nexport, sizeof dexport[0], scmp);
   351  }
   352  
   353  void
   354  addexports(void)
   355  {
   356  	IMAGE_SECTION_HEADER *sect;
   357  	IMAGE_EXPORT_DIRECTORY e;
   358  	int size, i, va, va_name, va_addr, va_na, v;
   359  
   360  	size = sizeof e + 10*nexport + strlen(outfile) + 1;
   361  	for(i=0; i<nexport; i++)
   362  		size += strlen(dexport[i]->extname) + 1;
   363  	
   364  	if (nexport == 0)
   365  		return;
   366  		
   367  	sect = addpesection(".edata", size, size);
   368  	sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
   369  	chksectoff(sect, cpos());
   370  	va = sect->VirtualAddress;
   371  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
   372  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
   373  
   374  	va_name = va + sizeof e + nexport*4;
   375  	va_addr = va + sizeof e;
   376  	va_na = va + sizeof e + nexport*8;
   377  
   378  	e.Characteristics = 0;
   379  	e.MajorVersion = 0;
   380  	e.MinorVersion = 0;
   381  	e.NumberOfFunctions = nexport;
   382  	e.NumberOfNames = nexport;
   383  	e.Name = va + sizeof e + nexport*10; // Program names.
   384  	e.Base = 1;
   385  	e.AddressOfFunctions = va_addr;
   386  	e.AddressOfNames = va_name;
   387  	e.AddressOfNameOrdinals = va_na;
   388  	// put IMAGE_EXPORT_DIRECTORY
   389  	for (i=0; i<sizeof(e); i++)
   390  		cput(((char*)&e)[i]);
   391  	// put EXPORT Address Table
   392  	for(i=0; i<nexport; i++)
   393  		lputl(dexport[i]->value - PEBASE);		
   394  	// put EXPORT Name Pointer Table
   395  	v = e.Name + strlen(outfile)+1;
   396  	for(i=0; i<nexport; i++) {
   397  		lputl(v);
   398  		v += strlen(dexport[i]->extname)+1;
   399  	}
   400  	// put EXPORT Ordinal Table
   401  	for(i=0; i<nexport; i++)
   402  		wputl(i);
   403  	// put Names
   404  	strnput(outfile, strlen(outfile)+1);
   405  	for(i=0; i<nexport; i++)
   406  		strnput(dexport[i]->extname, strlen(dexport[i]->extname)+1);
   407  	strnput("", sect->SizeOfRawData - size);
   408  }
   409  
   410  void
   411  dope(void)
   412  {
   413  	Sym *rel;
   414  
   415  	/* relocation table */
   416  	rel = lookup(".rel", 0);
   417  	rel->reachable = 1;
   418  	rel->type = SELFROSECT;
   419  
   420  	initdynimport();
   421  	initdynexport();
   422  }
   423  
   424  /*
   425   * For more than 8 characters section names, name contains a slash (/) that is 
   426   * followed by an ASCII representation of a decimal number that is an offset into 
   427   * the string table. 
   428   * reference: pecoff_v8.docx Page 24.
   429   * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
   430   */
   431  IMAGE_SECTION_HEADER*
   432  newPEDWARFSection(char *name, vlong size)
   433  {
   434  	IMAGE_SECTION_HEADER *h;
   435  	char s[8];
   436  
   437  	if(size == 0)
   438  		return nil;
   439  
   440  	if(nextsymoff+strlen(name)+1 > sizeof(symnames)) {
   441  		diag("pe string table is full");
   442  		errorexit();
   443  	}
   444  
   445  	strcpy(&symnames[nextsymoff], name);
   446  	sprint(s, "/%d\0", nextsymoff+4);
   447  	nextsymoff += strlen(name);
   448  	symnames[nextsymoff] = 0;
   449  	nextsymoff ++;
   450  	h = addpesection(s, size, size);
   451  	h->Characteristics = IMAGE_SCN_MEM_READ|
   452  		IMAGE_SCN_MEM_DISCARDABLE;
   453  
   454  	return h;
   455  }
   456  
   457  static void
   458  addsymtable(void)
   459  {
   460  	IMAGE_SECTION_HEADER *h;
   461  	int i, size;
   462  	Sym *s;
   463  	
   464  	fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
   465  	size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
   466  	h = addpesection(".symtab", size, size);
   467  	h->Characteristics = IMAGE_SCN_MEM_READ|
   468  		IMAGE_SCN_MEM_DISCARDABLE;
   469  	chksectoff(h, cpos());
   470  	fh.PointerToSymbolTable = cpos();
   471  	
   472  	// put COFF symbol table
   473  	for (i=0; i<fh.NumberOfSymbols; i++) {
   474  		s = rlookup(symlabels[i], 0);
   475  		strnput(s->name, 8);
   476  		lputl(datoff(s->value));
   477  		wputl(textsect);
   478  		wputl(0x0308);  // "array of structs"
   479  		cput(2);        // storage class: external
   480  		cput(0);        // no aux entries
   481  	}
   482  
   483  	// put COFF string table
   484  	lputl(nextsymoff + 4);
   485  	for (i=0; i<nextsymoff; i++)
   486  		cput(symnames[i]);
   487  	strnput("", h->SizeOfRawData - size);
   488  }
   489  
   490  void
   491  setpersrc(Sym *sym)
   492  {
   493  	if(rsrcsym != nil)
   494  		diag("too many .rsrc sections");
   495  	
   496  	rsrcsym = sym;
   497  }
   498  
   499  void
   500  addpersrc(void)
   501  {
   502  	IMAGE_SECTION_HEADER *h;
   503  	uchar *p;
   504  	uint32 val;
   505  	Reloc *r;
   506  
   507  	if(rsrcsym == nil)
   508  		return;
   509  	
   510  	h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size);
   511  	h->Characteristics = IMAGE_SCN_MEM_READ|
   512  		IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
   513  	chksectoff(h, cpos());
   514  	// relocation
   515  	for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
   516  		p = rsrcsym->p + r->off;
   517  		val = h->VirtualAddress + r->add;
   518  		// 32-bit little-endian
   519  		p[0] = val;
   520  		p[1] = val>>8;
   521  		p[2] = val>>16;
   522  		p[3] = val>>24;
   523  	}
   524  	cwrite(rsrcsym->p, rsrcsym->size);
   525  	strnput("", h->SizeOfRawData - rsrcsym->size);
   526  
   527  	// update data directory
   528  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
   529  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
   530  }
   531  
   532  static void
   533  addexcept(IMAGE_SECTION_HEADER *text)
   534  {
   535  	IMAGE_SECTION_HEADER *pdata, *xdata;
   536  	vlong startoff;
   537  	uvlong n;
   538  	Sym *sym;
   539  
   540  	USED(text);
   541  	if(thechar != '6')
   542  		return;
   543  
   544  	// write unwind info
   545  	sym = lookup("runtime.sigtramp", 0);
   546  	startoff = cpos();
   547  	lputl(9);	// version=1, flags=UNW_FLAG_EHANDLER, rest 0
   548  	lputl(sym->value - PEBASE);
   549  	lputl(0);
   550  
   551  	n = cpos() - startoff;
   552  	xdata = addpesection(".xdata", n, n);
   553  	xdata->Characteristics = IMAGE_SCN_MEM_READ|
   554  		IMAGE_SCN_CNT_INITIALIZED_DATA;
   555  	chksectoff(xdata, startoff);
   556  	strnput("", xdata->SizeOfRawData - n);
   557  
   558  	// write a function table entry for the whole text segment
   559  	startoff = cpos();
   560  	lputl(text->VirtualAddress);
   561  	lputl(text->VirtualAddress + text->VirtualSize);
   562  	lputl(xdata->VirtualAddress);
   563  
   564  	n = cpos() - startoff;
   565  	pdata = addpesection(".pdata", n, n);
   566  	pdata->Characteristics = IMAGE_SCN_MEM_READ|
   567  		IMAGE_SCN_CNT_INITIALIZED_DATA;
   568  	chksectoff(pdata, startoff);
   569  	strnput("", pdata->SizeOfRawData - n);
   570  
   571  	dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
   572  	dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
   573  }
   574  
   575  void
   576  asmbpe(void)
   577  {
   578  	IMAGE_SECTION_HEADER *t, *d;
   579  
   580  	switch(thechar) {
   581  	default:
   582  		diag("unknown PE architecture");
   583  		errorexit();
   584  	case '6':
   585  		fh.Machine = IMAGE_FILE_MACHINE_AMD64;
   586  		break;
   587  	case '8':
   588  		fh.Machine = IMAGE_FILE_MACHINE_I386;
   589  		break;
   590  	}
   591  
   592  	t = addpesection(".text", segtext.len, segtext.len);
   593  	t->Characteristics = IMAGE_SCN_CNT_CODE|
   594  		IMAGE_SCN_CNT_INITIALIZED_DATA|
   595  		IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
   596  	chksectseg(t, &segtext);
   597  	textsect = nsect;
   598  
   599  	d = addpesection(".data", segdata.len, segdata.filelen);
   600  	d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
   601  		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
   602  	chksectseg(d, &segdata);
   603  
   604  	if(!debug['s'])
   605  		dwarfaddpeheaders();
   606  
   607  	cseek(nextfileoff);
   608  	addimports(d);
   609  	addexports();
   610  	addsymtable();
   611  	addpersrc();
   612  	addexcept(t);
   613  
   614  	fh.NumberOfSections = nsect;
   615  	fh.TimeDateStamp = time(0);
   616  	fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
   617  		IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
   618  	if (pe64) {
   619  		fh.SizeOfOptionalHeader = sizeof(oh64);
   620  		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
   621  		set(Magic, 0x20b);	// PE32+
   622  	} else {
   623  		fh.SizeOfOptionalHeader = sizeof(oh);
   624  		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
   625  		set(Magic, 0x10b);	// PE32
   626  		oh.BaseOfData = d->VirtualAddress;
   627  	}
   628  	set(MajorLinkerVersion, 3);
   629  	set(MinorLinkerVersion, 0);
   630  	set(SizeOfCode, t->SizeOfRawData);
   631  	set(SizeOfInitializedData, d->SizeOfRawData);
   632  	set(SizeOfUninitializedData, 0);
   633  	set(AddressOfEntryPoint, entryvalue()-PEBASE);
   634  	set(BaseOfCode, t->VirtualAddress);
   635  	set(ImageBase, PEBASE);
   636  	set(SectionAlignment, PESECTALIGN);
   637  	set(FileAlignment, PEFILEALIGN);
   638  	set(MajorOperatingSystemVersion, 4);
   639  	set(MinorOperatingSystemVersion, 0);
   640  	set(MajorImageVersion, 1);
   641  	set(MinorImageVersion, 0);
   642  	set(MajorSubsystemVersion, 4);
   643  	set(MinorSubsystemVersion, 0);
   644  	set(SizeOfImage, nextsectoff);
   645  	set(SizeOfHeaders, PEFILEHEADR);
   646  	if(strcmp(headstring, "windowsgui") == 0)
   647  		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
   648  	else
   649  		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
   650  
   651  	// Disable stack growth as we don't want Windows to
   652  	// fiddle with the thread stack limits, which we set
   653  	// ourselves to circumvent the stack checks in the
   654  	// Windows exception dispatcher.
   655  	// Commit size must be strictly less than reserve
   656  	// size otherwise reserve will be rounded up to a
   657  	// larger size, as verified with VMMap.
   658  
   659  	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
   660  	// That default stack reserve size affects only the main thread,
   661  	// for other threads we specify stack size in runtime explicitly
   662  	// (runtime knows whether cgo is enabled or not).
   663  	// If you change stack reserve sizes here,
   664  	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well.
   665  	if(!iscgo) {
   666  		set(SizeOfStackReserve, 0x00010000);
   667  		set(SizeOfStackCommit, 0x0000ffff);
   668  	} else {
   669  		set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
   670  		// account for 2 guard pages
   671  		set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
   672  	}
   673  	set(SizeOfHeapReserve, 0x00100000);
   674  	set(SizeOfHeapCommit, 0x00001000);
   675  	set(NumberOfRvaAndSizes, 16);
   676  
   677  	pewrite();
   678  }