mirror of
https://github.com/golang/go
synced 2024-10-04 20:21:22 -06:00
70deac67cf
R=rsc, brainman, Joe Poirier, mattn CC=golang-dev https://golang.org/cl/2166041
366 lines
8.1 KiB
C
366 lines
8.1 KiB
C
// 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 <time.h>
|
|
|
|
#include "l.h"
|
|
#include "../ld/lib.h"
|
|
#include "../ld/pe.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
|
|
};
|
|
|
|
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 IMAGE_SECTION_HEADER sh[16];
|
|
|
|
typedef struct Imp Imp;
|
|
struct Imp {
|
|
Sym* s;
|
|
long va;
|
|
long vb;
|
|
Imp* next;
|
|
};
|
|
|
|
typedef struct Dll Dll;
|
|
struct Dll {
|
|
char* name;
|
|
int count;
|
|
Imp* ms;
|
|
Dll* next;
|
|
};
|
|
|
|
static Dll* dr;
|
|
static int ndll, nimp, nsize;
|
|
|
|
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)
|
|
{
|
|
switch(thechar) {
|
|
// 64-bit architectures
|
|
case '6':
|
|
pe64 = 1;
|
|
break;
|
|
// 32-bit architectures
|
|
default:
|
|
break;
|
|
}
|
|
|
|
PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN);
|
|
PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
|
|
nextsectoff = PESECTHEADR;
|
|
nextfileoff = PEFILEHEADR;
|
|
}
|
|
|
|
static void
|
|
pewrite(void)
|
|
{
|
|
int i, j;
|
|
|
|
seek(cout, 0, 0);
|
|
ewrite(cout, dosstub, sizeof dosstub);
|
|
strnput("PE", 4);
|
|
|
|
for (i=0; i<sizeof(fh); i++)
|
|
cput(((char*)&fh)[i]);
|
|
for (i=0; i<sizeof(oh); i++)
|
|
cput(((char*)&oh)[i]);
|
|
for (i=0; i<nsect; i++)
|
|
for (j=0; j<sizeof(sh[i]); j++)
|
|
cput(((char*)&sh[i])[j]);
|
|
}
|
|
|
|
static void
|
|
strput(char *s)
|
|
{
|
|
while(*s)
|
|
cput(*s++);
|
|
cput('\0');
|
|
}
|
|
|
|
static Dll*
|
|
initdynimport(void)
|
|
{
|
|
Imp *m;
|
|
Dll *d;
|
|
Sym *s;
|
|
int i;
|
|
Sym *dynamic;
|
|
|
|
dr = nil;
|
|
ndll = 0;
|
|
nimp = 0;
|
|
nsize = 0;
|
|
|
|
for(i=0; i<NHASH; i++)
|
|
for(s = hash[i]; s != S; s = s->hash) {
|
|
if(!s->reachable || !s->dynimpname)
|
|
continue;
|
|
nimp++;
|
|
for(d = dr; d != nil; d = d->next) {
|
|
if(strcmp(d->name,s->dynimplib) == 0) {
|
|
m = mal(sizeof *m);
|
|
m->s = s;
|
|
m->next = d->ms;
|
|
d->ms = m;
|
|
d->count++;
|
|
nsize += strlen(s->dynimpname)+2+1;
|
|
break;
|
|
}
|
|
}
|
|
if(d == nil) {
|
|
d = mal(sizeof *d);
|
|
d->name = s->dynimplib;
|
|
d->count = 1;
|
|
d->next = dr;
|
|
dr = d;
|
|
m = mal(sizeof *m);
|
|
m->s = s;
|
|
m->next = 0;
|
|
d->ms = m;
|
|
ndll++;
|
|
nsize += strlen(s->dynimpname)+2+1;
|
|
nsize += strlen(s->dynimplib)+1;
|
|
}
|
|
}
|
|
|
|
nsize += 20*ndll + 20;
|
|
nsize += 4*nimp + 4*ndll;
|
|
|
|
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 += 4;
|
|
}
|
|
dynamic->size += 4;
|
|
}
|
|
|
|
return dr;
|
|
}
|
|
|
|
static void
|
|
addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
|
|
{
|
|
IMAGE_SECTION_HEADER *isect;
|
|
uint32 va;
|
|
int noff, aoff, o, last_fn, last_name_off, iat_off;
|
|
Imp *m;
|
|
Dll *d;
|
|
Sym* dynamic;
|
|
|
|
isect = addpesection(".idata", nsize, nsize, 0);
|
|
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
|
|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
|
|
va = isect->VirtualAddress;
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
|
|
|
|
seek(cout, fileoff, 0);
|
|
|
|
dynamic = lookup(".windynamic", 0);
|
|
iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off;
|
|
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
|
|
|
|
noff = va + 20*ndll + 20;
|
|
aoff = noff + 4*nimp + 4*ndll;
|
|
last_fn = 0;
|
|
last_name_off = aoff;
|
|
for(d = dr; d != nil; d = d->next) {
|
|
lputl(noff);
|
|
lputl(0);
|
|
lputl(0);
|
|
lputl(last_name_off);
|
|
lputl(iat_off);
|
|
last_fn = d->count;
|
|
noff += 4*last_fn + 4;
|
|
aoff += 4*last_fn + 4;
|
|
iat_off += 4*last_fn + 4;
|
|
last_name_off += strlen(d->name)+1;
|
|
}
|
|
lputl(0); //end
|
|
lputl(0);
|
|
lputl(0);
|
|
lputl(0);
|
|
lputl(0);
|
|
|
|
// put OriginalFirstThunk
|
|
o = last_name_off;
|
|
for(d = dr; d != nil; d = d->next) {
|
|
for(m = d->ms; m != nil; m = m->next) {
|
|
lputl(o);
|
|
o += 2 + strlen(m->s->dynimpname) + 1;
|
|
}
|
|
lputl(0);
|
|
}
|
|
// put names
|
|
for(d = dr; d != nil; d = d->next) {
|
|
strput(d->name);
|
|
}
|
|
// put hint+name
|
|
for(d = dr; d != nil; d = d->next) {
|
|
for(m = d->ms; m != nil; m = m->next) {
|
|
wputl(0);
|
|
strput(m->s->dynimpname);
|
|
}
|
|
}
|
|
|
|
strnput("", isect->SizeOfRawData - nsize);
|
|
cflush();
|
|
|
|
// put FirstThunk
|
|
o = last_name_off;
|
|
seek(cout, datsect->PointerToRawData + dynamic->value - PEBASE - datsect->VirtualAddress, 0);
|
|
for(d = dr; d != nil; d = d->next) {
|
|
for(m = d->ms; m != nil; m = m->next) {
|
|
lputl(o);
|
|
o += 2 + strlen(m->s->dynimpname) + 1;
|
|
}
|
|
lputl(0);
|
|
}
|
|
cflush();
|
|
seek(cout, 0, 2);
|
|
}
|
|
|
|
void
|
|
dope(void)
|
|
{
|
|
initdynimport();
|
|
}
|
|
|
|
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;
|
|
|
|
addimports(nextfileoff, d);
|
|
|
|
fh.NumberOfSections = nsect;
|
|
fh.TimeDateStamp = time(0);
|
|
fh.SizeOfOptionalHeader = sizeof(oh);
|
|
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
|
|
IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
|
|
if(thechar == '8')
|
|
fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
|
|
|
|
oh.Magic = 0x10b; // PE32
|
|
oh.MajorLinkerVersion = 1;
|
|
oh.MinorLinkerVersion = 0;
|
|
oh.SizeOfCode = t->SizeOfRawData;
|
|
oh.SizeOfInitializedData = d->SizeOfRawData;
|
|
oh.SizeOfUninitializedData = 0;
|
|
oh.AddressOfEntryPoint = entryvalue()-PEBASE;
|
|
oh.BaseOfCode = t->VirtualAddress;
|
|
oh.BaseOfData = d->VirtualAddress;
|
|
|
|
oh.ImageBase = PEBASE;
|
|
oh.SectionAlignment = PESECTALIGN;
|
|
oh.FileAlignment = PEFILEALIGN;
|
|
oh.MajorOperatingSystemVersion = 4;
|
|
oh.MinorOperatingSystemVersion = 0;
|
|
oh.MajorImageVersion = 1;
|
|
oh.MinorImageVersion = 0;
|
|
oh.MajorSubsystemVersion = 4;
|
|
oh.MinorSubsystemVersion = 0;
|
|
oh.SizeOfImage = nextsectoff;
|
|
oh.SizeOfHeaders = PEFILEHEADR;
|
|
oh.Subsystem = 3; // WINDOWS_CUI
|
|
oh.SizeOfStackReserve = 0x00200000;
|
|
oh.SizeOfStackCommit = 0x00001000;
|
|
oh.SizeOfHeapReserve = 0x00100000;
|
|
oh.SizeOfHeapCommit = 0x00001000;
|
|
oh.NumberOfRvaAndSizes = 16;
|
|
|
|
pewrite();
|
|
}
|