summaryrefslogtreecommitdiff
path: root/src/cmd/ld/pe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/pe.c')
-rw-r--r--src/cmd/ld/pe.c89
1 files changed, 78 insertions, 11 deletions
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 334c9959f..df6c95976 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; i<fh.NumberOfSymbols; i++) {
+ s = rlookup(symlabels[i], 0);
+ strnput(s->name, 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; i<nextsymoff; i++)
cput(symnames[i]);
strnput("", h->SizeOfRawData - size);
@@ -510,6 +525,48 @@ addpersrc(void)
dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
}
+static void
+addexcept(IMAGE_SECTION_HEADER *text)
+{
+ IMAGE_SECTION_HEADER *pdata, *xdata;
+ vlong startoff;
+ uvlong n;
+ Sym *sym;
+
+ if(thechar != '6')
+ return;
+
+ // write unwind info
+ sym = lookup("runtime.sigtramp", 0);
+ startoff = cpos();
+ lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0
+ lputl(sym->value - PEBASE);
+ lputl(0);
+
+ n = cpos() - startoff;
+ xdata = addpesection(".xdata", n, n);
+ xdata->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_CNT_INITIALIZED_DATA;
+ chksectoff(xdata, startoff);
+ strnput("", xdata->SizeOfRawData - n);
+
+ // write a function table entry for the whole text segment
+ startoff = cpos();
+ lputl(text->VirtualAddress);
+ lputl(text->VirtualAddress + text->VirtualSize);
+ lputl(xdata->VirtualAddress);
+
+ n = cpos() - startoff;
+ pdata = addpesection(".pdata", n, n);
+ pdata->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_CNT_INITIALIZED_DATA;
+ chksectoff(pdata, startoff);
+ strnput("", pdata->SizeOfRawData - n);
+
+ dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
+}
+
void
asmbpe(void)
{
@@ -532,6 +589,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|
@@ -546,7 +604,8 @@ asmbpe(void)
addexports();
addsymtable();
addpersrc();
-
+ addexcept(t);
+
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
@@ -583,8 +642,16 @@ asmbpe(void)
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
else
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
- set(SizeOfStackReserve, 0x0040000);
- set(SizeOfStackCommit, 0x00001000);
+
+ // Disable stack growth as we don't want Windows to
+ // fiddle with the thread stack limits, which we set
+ // ourselves to circumvent the stack checks in the
+ // Windows exception dispatcher.
+ // Commit size must be strictly less than reserve
+ // size otherwise reserve will be rounded up to a
+ // larger size, as verified with VMMap.
+ set(SizeOfStackReserve, 0x00010000);
+ set(SizeOfStackCommit, 0x0000ffff);
set(SizeOfHeapReserve, 0x00100000);
set(SizeOfHeapCommit, 0x00001000);
set(NumberOfRvaAndSizes, 16);