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