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.c212
1 files changed, 123 insertions, 89 deletions
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 7b9a596fc..c26cd5264 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -32,15 +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 LSym *rsrcsym;
-static char symnames[256];
-static int nextsymoff;
+static char* strtbl;
+static int strtblnextoff;
+static int strtblsize;
int32 PESECTHEADR;
int32 PEFILEHEADR;
@@ -50,6 +46,7 @@ static int nsect;
static int nextsectoff;
static int nextfileoff;
static int textsect;
+static int datasect;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
@@ -62,7 +59,7 @@ static IMAGE_DATA_DIRECTORY* dd;
typedef struct Imp Imp;
struct Imp {
- Sym* s;
+ LSym* s;
uvlong off;
Imp* next;
};
@@ -78,9 +75,21 @@ struct Dll {
static Dll* dr;
-static Sym *dexport[1024];
+static LSym *dexport[1024];
static int nexport;
+typedef struct COFFSym COFFSym;
+struct COFFSym
+{
+ LSym* sym;
+ int strtbloff;
+ int sect;
+ vlong value;
+};
+
+static COFFSym* coffsym;
+static int ncoffsym;
+
static IMAGE_SECTION_HEADER*
addpesection(char *name, int sectsize, int filesize)
{
@@ -191,11 +200,11 @@ initdynimport(void)
{
Imp *m;
Dll *d;
- Sym *s, *dynamic;
+ LSym *s, *dynamic;
dr = nil;
m = nil;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
@@ -216,7 +225,7 @@ initdynimport(void)
d->ms = m;
}
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
for(d = dr; d != nil; d = d->next) {
@@ -241,10 +250,10 @@ addimports(IMAGE_SECTION_HEADER *datsect)
vlong startoff, endoff;
Imp *m;
Dll *d;
- Sym* dynamic;
+ LSym* dynamic;
startoff = cpos();
- dynamic = lookup(".windynamic", 0);
+ dynamic = linklookup(ctxt, ".windynamic", 0);
// skip import descriptor table (will write it later)
n = 0;
@@ -322,20 +331,20 @@ addimports(IMAGE_SECTION_HEADER *datsect)
static int
scmp(const void *p1, const void *p2)
{
- Sym *s1, *s2;
+ LSym *s1, *s2;
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
+ s1 = *(LSym**)p1;
+ s2 = *(LSym**)p2;
return strcmp(s1->extname, s2->extname);
}
static void
initdynexport(void)
{
- Sym *s;
+ LSym *s;
nexport = 0;
- for(s = allsym; s != S; s = s->allsym) {
+ for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
@@ -410,10 +419,10 @@ addexports(void)
void
dope(void)
{
- Sym *rel;
+ LSym *rel;
/* relocation table */
- rel = lookup(".rel", 0);
+ rel = linklookup(ctxt, ".rel", 0);
rel->reachable = 1;
rel->type = SELFROSECT;
@@ -421,6 +430,24 @@ dope(void)
initdynexport();
}
+static int
+strtbladd(char *name)
+{
+ int newsize, thisoff;
+
+ newsize = strtblnextoff + strlen(name) + 1;
+ if(newsize > strtblsize) {
+ strtblsize = 2 * (newsize + (1<<18));
+ strtbl = realloc(strtbl, strtblsize);
+ }
+ thisoff = strtblnextoff+4; // first string starts at offset=4
+ strcpy(&strtbl[strtblnextoff], name);
+ strtblnextoff += strlen(name);
+ strtbl[strtblnextoff] = 0;
+ strtblnextoff++;
+ return thisoff;
+}
+
/*
* 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
@@ -433,20 +460,13 @@ newPEDWARFSection(char *name, vlong size)
{
IMAGE_SECTION_HEADER *h;
char s[8];
+ int off;
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 ++;
+ off = strtbladd(name);
+ sprint(s, "/%d\0", off);
h = addpesection(s, size, size);
h->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_MEM_DISCARDABLE;
@@ -455,40 +475,97 @@ newPEDWARFSection(char *name, vlong size)
}
static void
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
+{
+ COFFSym *cs;
+ USED(name);
+ USED(addr);
+ USED(size);
+ USED(ver);
+ USED(gotype);
+
+ if(s == nil)
+ return;
+
+ if(s->sect == nil)
+ return;
+
+ switch(type) {
+ default:
+ return;
+ case 'D':
+ case 'B':
+ case 'T':
+ break;
+ }
+
+ if(coffsym) {
+ cs = &coffsym[ncoffsym];
+ cs->sym = s;
+ if(strlen(s->name) > 8)
+ cs->strtbloff = strtbladd(s->name);
+ if(s->value >= segdata.vaddr) {
+ cs->value = s->value - segdata.vaddr;
+ cs->sect = datasect;
+ } else if(s->value >= segtext.vaddr) {
+ cs->value = s->value - segtext.vaddr;
+ cs->sect = textsect;
+ } else {
+ cs->value = 0;
+ cs->sect = 0;
+ diag("addsym %#llx", addr);
+ }
+ }
+ ncoffsym++;
+}
+
+static void
addsymtable(void)
{
IMAGE_SECTION_HEADER *h;
int i, size;
- Sym *s;
-
- fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
- size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
+ COFFSym *s;
+
+ if(!debug['s']) {
+ genasmsym(addsym);
+ coffsym = mal(ncoffsym * sizeof coffsym[0]);
+ ncoffsym = 0;
+ genasmsym(addsym);
+ }
+
+ size = strtblnextoff + 4 + 18*ncoffsym;
h = addpesection(".symtab", size, size);
h->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_MEM_DISCARDABLE;
chksectoff(h, cpos());
fh.PointerToSymbolTable = cpos();
+ fh.NumberOfSymbols = ncoffsym;
// 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);
+ for (i=0; i<ncoffsym; i++) {
+ s = &coffsym[i];
+ if(s->strtbloff == 0)
+ strnput(s->sym->name, 8);
+ else {
+ lputl(0);
+ lputl(s->strtbloff);
+ }
+ lputl(s->value);
+ wputl(s->sect);
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]);
+ lputl(strtblnextoff + 4);
+ for (i=0; i<strtblnextoff; i++)
+ cput(strtbl[i]);
strnput("", h->SizeOfRawData - size);
}
void
-setpersrc(Sym *sym)
+setpersrc(LSym *sym)
{
if(rsrcsym != nil)
diag("too many .rsrc sections");
@@ -529,49 +606,6 @@ 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;
-
- USED(text);
- 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)
{
@@ -600,6 +634,7 @@ asmbpe(void)
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
chksectseg(d, &segdata);
+ datasect = nsect;
if(!debug['s'])
dwarfaddpeheaders();
@@ -609,7 +644,6 @@ asmbpe(void)
addexports();
addsymtable();
addpersrc();
- addexcept(t);
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);