summaryrefslogtreecommitdiff
path: root/src/cmd/ld
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld')
-rw-r--r--src/cmd/ld/data.c29
-rw-r--r--src/cmd/ld/dwarf.c176
-rw-r--r--src/cmd/ld/dwarf.h1
-rw-r--r--src/cmd/ld/ldpe.c406
-rw-r--r--src/cmd/ld/lib.c4
-rw-r--r--src/cmd/ld/lib.h1
-rw-r--r--src/cmd/ld/pe.c419
-rw-r--r--src/cmd/ld/pe.h50
8 files changed, 901 insertions, 185 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 210f10ab5..0551232cf 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -240,6 +240,33 @@ void
dynrelocsym(Sym *s)
{
Reloc *r;
+
+ if(thechar == '8' && HEADTYPE == 10) { // Windows PE
+ Sym *rel, *targ;
+
+ rel = lookup(".rel", 0);
+ if(s == rel)
+ return;
+ for(r=s->r; r<s->r+s->nr; r++) {
+ targ = r->sym;
+ if(r->sym->plt == -2) { // make dynimport JMP table for PE object files.
+ targ->plt = rel->size;
+ r->sym = rel;
+ r->add = targ->plt;
+
+ // jmp *addr
+ adduint8(rel, 0xff);
+ adduint8(rel, 0x25);
+ addaddr(rel, targ);
+ adduint8(rel, 0x90);
+ adduint8(rel, 0x90);
+ } else if(r->sym->plt >= 0) {
+ r->sym = rel;
+ r->add = targ->plt;
+ }
+ }
+ return;
+ }
for(r=s->r; r<s->r+s->nr; r++)
if(r->sym->type == SDYNIMPORT || r->type >= 256)
@@ -871,7 +898,7 @@ address(void)
segdata.rwx = 06;
segdata.vaddr = va;
segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
- if(thechar == '8' && HEADTYPE == 10) // Windows PE
+ if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Windows PE
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
if(thechar == '8' && HEADTYPE == 2) { // Plan 9
segdata.vaddr = va = rnd(va, 4096);
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 506c6e5db..5df3515f5 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -19,6 +19,7 @@
#include "../ld/dwarf_defs.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/pe.h"
/*
* Offsets and sizes of the debug_* sections in the cout file.
@@ -453,19 +454,6 @@ getattr(DWDie *die, uint8 attr)
return nil;
}
-static void
-delattr(DWDie *die, uint8 attr)
-{
- DWAttr **a;
-
- a = &die->attr;
- while (*a != nil)
- if ((*a)->atr == attr)
- *a = (*a)->link;
- else
- a = &((*a)->link);
-}
-
// Every DIE has at least a DW_AT_name attribute (but it will only be
// written out if it is listed in the abbrev). If its parent is
// keeping an index, the new DIE will be inserted there.
@@ -768,10 +756,8 @@ enum {
KindUint32,
KindUint64,
KindUintptr,
- KindFloat,
KindFloat32,
KindFloat64,
- KindComplex,
KindComplex64,
KindComplex128,
KindArray,
@@ -799,6 +785,17 @@ decode_reloc(Sym *s, int32 off)
return nil;
}
+static Sym*
+decode_reloc_sym(Sym *s, int32 off)
+{
+ Reloc *r;
+
+ r = decode_reloc(s,off);
+ if (r == nil)
+ return nil;
+ return r->sym;
+}
+
static uvlong
decode_inuxi(uchar* p, int sz)
{
@@ -852,7 +849,7 @@ decodetype_size(Sym *s)
static Sym*
decodetype_arrayelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
static vlong
@@ -865,26 +862,26 @@ decodetype_arraylen(Sym *s)
static Sym*
decodetype_ptrelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
// Type.MapType.key, elem
static Sym*
decodetype_mapkey(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
static Sym*
decodetype_mapvalue(Sym *s)
{
- return decode_reloc(s, 6*PtrSize + 8)->sym; // 0x20 / 0x38
+ return decode_reloc_sym(s, 6*PtrSize + 8); // 0x20 / 0x38
}
// Type.ChanType.elem
static Sym*
decodetype_chanelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
@@ -913,7 +910,9 @@ decodetype_funcintype(Sym *s, int i)
Reloc *r;
r = decode_reloc(s, 6*PtrSize + 8);
- return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
static Sym*
@@ -922,7 +921,9 @@ decodetype_funcouttype(Sym *s, int i)
Reloc *r;
r = decode_reloc(s, 7*PtrSize + 16);
- return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
// Type.StructType.fields.Slice::len
@@ -936,21 +937,20 @@ decodetype_structfieldcount(Sym *s)
static char*
decodetype_structfieldname(Sym *s, int i)
{
- Reloc* r;
-
- r = decode_reloc(s, 6*PtrSize + 0x10 + i*5*PtrSize); // go.string."foo" 0x28 / 0x40
- if (r == nil) // embedded structs have a nil name.
+ // go.string."foo" 0x28 / 0x40
+ s = decode_reloc_sym(s, 6*PtrSize + 0x10 + i*5*PtrSize);
+ if (s == nil) // embedded structs have a nil name.
return nil;
- r = decode_reloc(r->sym, 0); // string."foo"
- if (r == nil) // shouldn't happen.
+ s = decode_reloc_sym(s, 0); // string."foo"
+ if (s == nil) // shouldn't happen.
return nil;
- return (char*)r->sym->p; // the c-string
+ return (char*)s->p; // the c-string
}
static Sym*
decodetype_structfieldtype(Sym *s, int i)
{
- return decode_reloc(s, 8*PtrSize + 0x10 + i*5*PtrSize)->sym; // 0x30 / 0x50
+ return decode_reloc_sym(s, 8*PtrSize + 0x10 + i*5*PtrSize); // 0x30 / 0x50
}
static vlong
@@ -977,6 +977,20 @@ enum {
static DWDie* defptrto(DWDie *dwtype); // below
+// Lookup predefined types
+static Sym*
+lookup_or_diag(char *n)
+{
+ Sym *s;
+
+ s = lookup(n, 0);
+ if (s->size == 0) {
+ diag("dwarf: missing type: %s", n);
+ errorexit();
+ }
+ return s;
+}
+
// Define gotype, for composite ones recurse into constituents.
static DWDie*
defgotype(Sym *gotype)
@@ -995,7 +1009,7 @@ defgotype(Sym *gotype)
diag("Type name doesn't start with \".type\": %s", gotype->name);
return find_or_diag(&dwtypes, "<unspecified>");
}
- name = gotype->name + 5; // Altenatively decode from Type.string
+ name = gotype->name + 5; // could also decode from Type.string
die = find(&dwtypes, name);
if (die != nil)
@@ -1049,7 +1063,6 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
- case KindFloat:
case KindFloat32:
case KindFloat64:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
@@ -1057,7 +1070,6 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
- case KindComplex:
case KindComplex64:
case KindComplex128:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
@@ -1107,9 +1119,9 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_ifacemethodcount(gotype);
if (nfields == 0)
- s = lookup("type.runtime.eface", 0);
+ s = lookup_or_diag("type.runtime.eface");
else
- s = lookup("type.runtime.iface", 0);
+ s = lookup_or_diag("type.runtime.iface");
newrefattr(die, DW_AT_type, defgotype(s));
break;
@@ -1226,7 +1238,7 @@ synthesizestringtypes(DWDie* die)
{
DWDie *prototype;
- prototype = defgotype(lookup("type.runtime.string_", 0));
+ prototype = defgotype(lookup_or_diag("type.runtime._string"));
if (prototype == nil)
return;
@@ -1242,7 +1254,7 @@ synthesizeslicetypes(DWDie *die)
{
DWDie *prototype, *elem;
- prototype = defgotype(lookup("type.runtime.slice",0));
+ prototype = defgotype(lookup_or_diag("type.runtime.slice"));
if (prototype == nil)
return;
@@ -1281,22 +1293,22 @@ synthesizemaptypes(DWDie *die)
{
DWDie *hash, *hash_subtable, *hash_entry,
- *dwh, *dwhs, *dwhe, *keytype, *valtype, *fld;
+ *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld;
int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
DWAttr *a;
- hash = defgotype(lookup("type.runtime.hash",0));
- hash_subtable = defgotype(lookup("type.runtime.hash_subtable",0));
- hash_entry = defgotype(lookup("type.runtime.hash_entry",0));
+ hash = defgotype(lookup_or_diag("type.runtime.hmap"));
+ hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
+ hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
if (hash == nil || hash_subtable == nil || hash_entry == nil)
return;
- dwh = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
- if (dwh == nil)
+ dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
+ if (dwhash == nil)
return;
- hashsize = getattr(dwh, DW_AT_byte_size)->value;
+ hashsize = getattr(dwhash, DW_AT_byte_size)->value;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_MAPTYPE)
@@ -1328,13 +1340,19 @@ synthesizemaptypes(DWDie *die)
mkinternaltypename("hash_entry",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
- copychildren(dwhe, hash_entry);
- substitutetype(dwhe, "key", keytype);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
+ newrefattr(fld, DW_AT_type, dwhash);
+ newmemberoffsetattr(fld, 0);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
+ newrefattr(fld, DW_AT_type, keytype);
+ newmemberoffsetattr(fld, hashsize);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
if (valsize > MaxValsize)
valtype = defptrto(valtype);
- substitutetype(dwhe, "val", valtype);
- fld = find_or_diag(dwhe, "val");
- delattr(fld, DW_AT_data_member_location);
+ newrefattr(fld, DW_AT_type, valtype);
newmemberoffsetattr(fld, hashsize + datavo);
newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
@@ -1371,10 +1389,10 @@ synthesizechantypes(DWDie *die)
DWAttr *a;
int elemsize, linksize, sudogsize;
- sudog = defgotype(lookup("type.runtime.sudoG",0));
- waitq = defgotype(lookup("type.runtime.waitQ",0));
- link = defgotype(lookup("type.runtime.link",0));
- hchan = defgotype(lookup("type.runtime.hChan",0));
+ sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
+ waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
+ link = defgotype(lookup_or_diag("type.runtime.link"));
+ hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
if (sudog == nil || waitq == nil || link == nil || hchan == nil)
return;
@@ -2281,6 +2299,13 @@ writegdbscript(void)
return sectionstart;
}
+static void
+align(vlong size)
+{
+ if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Only Windows PE need section align.
+ strnput("", rnd(size, PEFILEALIGN) - size);
+}
+
/*
* This is the main entry point for generating dwarf. After emitting
* the mandatory debug_abbrev section, it calls writelines() to set up
@@ -2313,15 +2338,18 @@ dwarfemitdebugsections(void)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
// Needed by the prettyprinter code for interface inspection.
- defgotype(lookup("type.runtime.commonType",0));
- defgotype(lookup("type.runtime.InterfaceType",0));
- defgotype(lookup("type.runtime.itab",0));
+ defgotype(lookup_or_diag("type.runtime.commonType"));
+ defgotype(lookup_or_diag("type.runtime.InterfaceType"));
+ defgotype(lookup_or_diag("type.runtime.itab"));
genasmsym(defdwsymb);
writeabbrev();
+ align(abbrevsize);
writelines();
+ align(linesize);
writeframes();
+ align(framesize);
synthesizestringtypes(dwtypes.child);
synthesizeslicetypes(dwtypes.child);
@@ -2354,16 +2382,23 @@ dwarfemitdebugsections(void)
}
}
infosize = infoe - infoo;
+ align(infosize);
pubnameso = writepub(ispubname);
+ pubnamessize = cpos() - pubnameso;
+ align(pubnamessize);
+
pubtypeso = writepub(ispubtype);
+ pubtypessize = cpos() - pubtypeso;
+ align(pubtypessize);
+
arangeso = writearanges();
- gdbscripto = writegdbscript();
+ arangessize = cpos() - arangeso;
+ align(arangessize);
- pubnamessize = pubtypeso - pubnameso;
- pubtypessize = arangeso - pubtypeso;
- arangessize = gdbscripto - arangeso;
+ gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto;
+ align(gdbscriptsize);
}
/*
@@ -2545,3 +2580,24 @@ dwarfaddmachoheaders(void)
ms->filesize += msect->size;
}
}
+
+/*
+ * Windows PE
+ */
+void
+dwarfaddpeheaders(void)
+{
+ dwarfemitdebugsections();
+ newPEDWARFSection(".debug_abbrev", abbrevsize);
+ newPEDWARFSection(".debug_line", linesize);
+ newPEDWARFSection(".debug_frame", framesize);
+ newPEDWARFSection(".debug_info", infosize);
+ if (pubnamessize > 0)
+ newPEDWARFSection(".debug_pubnames", pubnamessize);
+ if (pubtypessize > 0)
+ newPEDWARFSection(".debug_pubtypes", pubtypessize);
+ if (arangessize > 0)
+ newPEDWARFSection(".debug_aranges", arangessize);
+ if (gdbscriptsize > 0)
+ newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
index 7881213c2..f0df2f9b1 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -27,3 +27,4 @@ void dwarfaddshstrings(Sym *shstrtab);
*/
void dwarfaddelfheaders(void);
void dwarfaddmachoheaders(void);
+void dwarfaddpeheaders(void);
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
new file mode 100644
index 000000000..d8b0a6fc2
--- /dev/null
+++ b/src/cmd/ld/ldpe.c
@@ -0,0 +1,406 @@
+// Copyright 2010 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.
+
+#include "l.h"
+#include "lib.h"
+#include "../ld/pe.h"
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE (-1)
+#define IMAGE_SYM_DEBUG (-2)
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+#define IMAGE_SYM_TYPE_PCODE 32768
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 0x10
+#define IMAGE_SYM_DTYPE_FUNCTION 0x20
+#define IMAGE_SYM_DTYPE_ARRAY 0x30
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1)
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_SYM_CLASS_CLR_TOKEN 107
+
+#define IMAGE_REL_I386_ABSOLUTE 0x0000
+#define IMAGE_REL_I386_DIR16 0x0001
+#define IMAGE_REL_I386_REL16 0x0002
+#define IMAGE_REL_I386_DIR32 0x0006
+#define IMAGE_REL_I386_DIR32NB 0x0007
+#define IMAGE_REL_I386_SEG12 0x0009
+#define IMAGE_REL_I386_SECTION 0x000A
+#define IMAGE_REL_I386_SECREL 0x000B
+#define IMAGE_REL_I386_TOKEN 0x000C
+#define IMAGE_REL_I386_SECREL7 0x000D
+#define IMAGE_REL_I386_REL32 0x0014
+
+typedef struct PeSym PeSym;
+typedef struct PeSect PeSect;
+typedef struct PeObj PeObj;
+
+struct PeSym {
+ char* name;
+ uint32 value;
+ uint16 sectnum;
+ uint16 type;
+ uint8 sclass;
+ uint8 aux;
+ Sym* sym;
+};
+
+struct PeSect {
+ char* name;
+ uchar* base;
+ uint64 size;
+ Sym* sym;
+ IMAGE_SECTION_HEADER sh;
+};
+
+struct PeObj {
+ Biobuf *f;
+ char *name;
+ uint32 base;
+
+ PeSect *sect;
+ uint nsect;
+ PeSym *pesym;
+ uint npesym;
+
+ IMAGE_FILE_HEADER fh;
+ char* snames;
+};
+
+static int map(PeObj *obj, PeSect *sect);
+static int readsym(PeObj *obj, int i, PeSym **sym);
+
+void
+ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ char *name;
+ int32 base;
+ int i, j, l, numaux;
+ PeObj *obj;
+ PeSect *sect, *rsect;
+ IMAGE_SECTION_HEADER sh;
+ uchar symbuf[18];
+ Sym *s;
+ Reloc *r, *rp;
+ PeSym *sym;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
+
+ version++;
+ base = Boffset(f);
+
+ obj = mal(sizeof *obj);
+ obj->f = f;
+ obj->base = base;
+ obj->name = pn;
+ // read header
+ if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
+ goto bad;
+ // load section list
+ obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
+ obj->nsect = obj->fh.NumberOfSections;
+ for(i=0; i < obj->fh.NumberOfSections; i++) {
+ if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
+ goto bad;
+ obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
+ obj->sect[i].name = (char*)obj->sect[i].sh.Name;
+ // TODO return error if found .cormeta .rsrc
+ }
+ // load string table
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, &l, sizeof l) != sizeof l)
+ goto bad;
+ obj->snames = mal(l);
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, obj->snames, l) != l)
+ goto bad;
+ // read symbols
+ obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
+ obj->npesym = obj->fh.NumberOfSymbols;
+ Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
+ for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
+ if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
+ goto bad;
+
+ if((symbuf[0] == 0) && (symbuf[1] == 0) &&
+ (symbuf[2] == 0) && (symbuf[3] == 0)) {
+ l = le32(&symbuf[4]);
+ obj->pesym[i].name = (char*)&obj->snames[l];
+ } else { // sym name length <= 8
+ obj->pesym[i].name = mal(9);
+ strncpy(obj->pesym[i].name, (char*)symbuf, 8);
+ obj->pesym[i].name[8] = 0;
+ }
+ obj->pesym[i].value = le32(&symbuf[8]);
+ obj->pesym[i].sectnum = le16(&symbuf[12]);
+ obj->pesym[i].sclass = symbuf[16];
+ obj->pesym[i].aux = symbuf[17];
+ obj->pesym[i].type = le16(&symbuf[14]);
+ numaux = obj->pesym[i].aux;
+ if (numaux < 0)
+ numaux = 0;
+ }
+ // create symbols for mapped sections
+ for(i=0; i<obj->nsect; i++) {
+ sect = &obj->sect[i];
+ if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ if(map(obj, sect) < 0)
+ goto bad;
+
+ name = smprint("%s(%s)", pn, sect->name);
+ s = lookup(name, version);
+ free(name);
+ switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
+ s->type = SRODATA;
+ break;
+ case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
+ s->type = SDATA;
+ break;
+ case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
+ s->type = STEXT;
+ break;
+ default:
+ werrstr("unexpected flags for PE section %s", sect->name);
+ goto bad;
+ }
+ s->p = sect->base;
+ s->np = sect->size;
+ s->size = sect->size;
+ if(s->type == STEXT) {
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ }
+ sect->sym = s;
+ }
+
+ // load relocations
+ for(i=0; i<obj->nsect; i++) {
+ rsect = &obj->sect[i];
+ if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
+ continue;
+ if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
+ Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
+ for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
+ rp = &r[j];
+ if(Bread(f, symbuf, 10) != 10)
+ goto bad;
+
+ uint32 rva, symindex;
+ uint16 type;
+ rva = le32(&symbuf[0]);
+ symindex = le32(&symbuf[4]);
+ type = le16(&symbuf[8]);
+ if(readsym(obj, symindex, &sym) < 0)
+ goto bad;
+ if(sym->sym == nil) {
+ werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
+ goto bad;
+ }
+ rp->sym = sym->sym;
+ rp->siz = 4;
+ rp->off = rva;
+ switch(type) {
+ default:
+ diag("%s: unknown relocation type %d;", pn, type);
+ case IMAGE_REL_I386_REL32:
+ rp->type = D_PCREL;
+ rp->add = 0;
+ break;
+ case IMAGE_REL_I386_DIR32:
+ rp->type = D_ADDR;
+ // load addend from image
+ rp->add = le32(rsect->base+rp->off);
+ break;
+ }
+ }
+ qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
+
+ s = rsect->sym;
+ s->r = r;
+ s->nr = rsect->sh.NumberOfRelocations;
+ }
+
+ // enter sub-symbols into symbol table.
+ // frist 2 entry is file name.
+ for(i=2; i<obj->npesym; i++) {
+ if(obj->pesym[i].name == 0)
+ continue;
+ if(obj->pesym[i].name[0] == '.') //skip section
+ continue;
+ if(obj->pesym[i].sectnum > 0) {
+ sect = &obj->sect[obj->pesym[i].sectnum-1];
+ if(sect->sym == 0)
+ continue;
+ }
+ if(readsym(obj, i, &sym) < 0)
+ goto bad;
+
+ s = sym->sym;
+ if(sym->sectnum == 0) {// extern
+ if(s->type == SDYNIMPORT)
+ s->plt = -2; // flag for dynimport in PE object files.
+ continue;
+ } else if (sym->sectnum > 0) {
+ sect = &obj->sect[sym->sectnum-1];
+ if(sect->sym == 0)
+ diag("%s: %s sym == 0!", pn, s->name);
+ } else {
+ diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum);
+ }
+
+ s->sub = sect->sym->sub;
+ sect->sym->sub = s;
+ s->type = sect->sym->type | SSUB;
+ s->value = sym->value;
+ s->size = 4;
+ s->outer = sect->sym;
+ if(sect->sym->type == STEXT) {
+ Prog *p;
+
+ if(s->text != P)
+ diag("%s: duplicate definition of %s", pn, s->name);
+ // build a TEXT instruction with a unique pc
+ // just to make the rest of the linker happy.
+ p = prg();
+ p->as = ATEXT;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->textflag = 7;
+ p->to.type = D_CONST;
+ p->link = nil;
+ p->pc = pc++;
+ s->text = p;
+
+ etextp->next = s;
+ etextp = s;
+ }
+ }
+
+ return;
+bad:
+ diag("%s: malformed pe file: %r", pn);
+}
+
+static int
+map(PeObj *obj, PeSect *sect)
+{
+ if(sect->base != nil)
+ return 0;
+
+ sect->base = mal(sect->sh.SizeOfRawData);
+ werrstr("short read");
+ if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 ||
+ Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
+ return -1;
+
+ return 0;
+}
+
+static int
+readsym(PeObj *obj, int i, PeSym **y)
+{
+ Sym *s;
+ PeSym *sym;
+ char *name, *p;
+
+ if(i >= obj->npesym || i < 0) {
+ werrstr("invalid pe symbol index");
+ return -1;
+ }
+
+ sym = &obj->pesym[i];
+ *y = sym;
+ s = nil;
+
+ name = sym->name;
+ if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
+ name = obj->sect[sym->sectnum-1].sym->name;
+ if(strncmp(sym->name, "__imp__", 6) == 0)
+ name = &sym->name[7]; // __imp__Name => Name
+ else if(sym->name[0] == '_')
+ name = &sym->name[1]; // _Name => Name
+ // remove last @XXX
+ p = strchr(name, '@');
+ if(p)
+ *p = 0;
+
+ switch(sym->type) {
+ default:
+ werrstr("%s: invalid symbol type %d", sym->name, sym->type);
+ return -1;
+ case IMAGE_SYM_DTYPE_FUNCTION:
+ case IMAGE_SYM_DTYPE_NULL:
+ switch(sym->sclass) {
+ case IMAGE_SYM_CLASS_EXTERNAL: //global
+ s = lookup(name, 0);
+ break;
+ case IMAGE_SYM_CLASS_NULL:
+ case IMAGE_SYM_CLASS_STATIC:
+ s = lookup(name, version);
+ break;
+ default:
+ werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
+ return -1;
+ }
+ break;
+ }
+
+ if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
+ s->type = SXREF;
+ sym->sym = s;
+
+ return 0;
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index ae77247c3..b1a62f25e 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -406,6 +406,10 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
ldmacho(f, pkg, len, pn);
return;
}
+ if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
+ ldpe(f, pkg, len, pn);
+ return;
+ }
/* check the header */
line = Brdline(f, '\n');
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index bcf297116..4ac5d37f9 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -130,6 +130,7 @@ void ldobj1(Biobuf *f, char*, int64 len, char *pn);
void ldobj(Biobuf*, char*, int64, char*, int);
void ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*);
+void ldpe(Biobuf*, char*, int64, char*);
void ldpkg(Biobuf*, char*, int64, char*, int);
void mark(Sym *s);
void mkfwd(void);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 82c6941f2..2c34daab4 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -10,6 +10,7 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/pe.h"
+#include "../ld/dwarf.h"
// DOS stub that prints out
// "This program cannot be run in DOS mode."
@@ -33,6 +34,9 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+static char symnames[256];
+static int nextsymoff;
+
int32 PESECTHEADR;
int32 PEFILEHEADR;
@@ -43,26 +47,33 @@ static int nextfileoff;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
+static PE64_IMAGE_OPTIONAL_HEADER oh64;
static IMAGE_SECTION_HEADER sh[16];
+static IMAGE_DATA_DIRECTORY* dd;
+
+#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v))
+#define put(v) (pe64 ? vputl(v) : lputl(v))
typedef struct Imp Imp;
struct Imp {
Sym* s;
- long va;
- long vb;
+ uvlong off;
Imp* next;
};
typedef struct Dll Dll;
struct Dll {
char* name;
- int count;
+ uvlong nameoff;
+ uvlong thunkoff;
Imp* ms;
Dll* next;
};
static Dll* dr;
-static int ndll, nimp, nsize;
+
+static Sym *dexport[1024];
+static int nexport;
static IMAGE_SECTION_HEADER*
addpesection(char *name, int sectsize, int filesize, Segment *s)
@@ -99,17 +110,23 @@ addpesection(char *name, int sectsize, int filesize, Segment *s)
void
peinit(void)
{
+ int32 l;
+
switch(thechar) {
// 64-bit architectures
case '6':
pe64 = 1;
+ l = sizeof(oh64);
+ dd = oh64.DataDirectory;
break;
// 32-bit architectures
default:
+ l = sizeof(oh);
+ dd = oh.DataDirectory;
break;
}
-
- PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN);
+
+ PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
nextsectoff = PESECTHEADR;
nextfileoff = PEFILEHEADR;
@@ -118,27 +135,34 @@ peinit(void)
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]);
+ cflush();
+ // TODO: This code should not assume that the
+ // memory representation is little-endian or
+ // that the structs are packed identically to
+ // their file representation.
+ ewrite(cout, &fh, sizeof fh);
+ if(pe64)
+ ewrite(cout, &oh64, sizeof oh64);
+ else
+ ewrite(cout, &oh, sizeof oh);
+ ewrite(cout, &sh, nsect * sizeof sh[0]);
}
static void
strput(char *s)
{
- while(*s)
+ int n;
+
+ for(n=0; *s; n++)
cput(*s++);
cput('\0');
+ n++;
+ // string must be padded to even size
+ if(n%2)
+ cput('\0');
}
static Dll*
@@ -146,50 +170,33 @@ initdynimport(void)
{
Imp *m;
Dll *d;
- Sym *s;
+ Sym *s, *dynamic;
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)
+ if(!s->reachable || !s->dynimpname || s->dynexport)
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;
}
+ m->s = s;
+ m->next = d->ms;
+ d->ms = m;
}
- nsize += 20*ndll + 20;
- nsize += 4*nimp + 4*ndll;
-
dynamic = lookup(".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
@@ -199,9 +206,9 @@ initdynimport(void)
m->s->sub = dynamic->sub;
dynamic->sub = m->s;
m->s->value = dynamic->size;
- dynamic->size += 4;
+ dynamic->size += PtrSize;
}
- dynamic->size += 4;
+ dynamic->size += PtrSize;
}
return dr;
@@ -211,90 +218,245 @@ 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;
+ uvlong n, oftbase, ftbase;
Imp *m;
Dll *d;
Sym* dynamic;
- isect = addpesection(".idata", nsize, nsize, 0);
+ dynamic = lookup(".windynamic", 0);
+
+ // skip import descriptor table (will write it later)
+ n = 0;
+ for(d = dr; d != nil; d = d->next)
+ n++;
+ seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0);
+
+ // write dll names
+ for(d = dr; d != nil; d = d->next) {
+ d->nameoff = cpos() - fileoff;
+ strput(d->name);
+ }
+
+ // write function names
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ m->off = nextsectoff + cpos() - fileoff;
+ wputl(0); // hint
+ strput(m->s->dynimpname);
+ }
+ }
+
+ // write OriginalFirstThunks
+ oftbase = cpos() - fileoff;
+ n = cpos();
+ for(d = dr; d != nil; d = d->next) {
+ d->thunkoff = cpos() - n;
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+
+ // add pe section and pad it at the end
+ n = cpos() - fileoff;
+ isect = addpesection(".idata", n, n, 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;
+ strnput("", isect->SizeOfRawData - n);
+ cflush();
+ // write FirstThunks (allocated in .data section)
+ ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
+ seek(cout, datsect->PointerToRawData + ftbase, 0);
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+ cflush();
+
+ // finally write import descriptor table
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(isect->VirtualAddress + oftbase + d->thunkoff);
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(isect->VirtualAddress + d->nameoff);
+ lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
}
lputl(0); //end
lputl(0);
lputl(0);
lputl(0);
lputl(0);
+ cflush();
- // 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);
+ // update data directory
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
+
+ seek(cout, 0, 2);
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+ Sym *s1, *s2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+ return strcmp(s1->dynimpname, s2->dynimpname);
+}
+
+static void
+initdynexport(void)
+{
+ int i;
+ Sym *s;
+
+ nexport = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->hash) {
+ if(!s->reachable || !s->dynimpname || !s->dynexport)
+ continue;
+ if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
+ diag("pe dynexport table is full");
+ errorexit();
}
+
+ dexport[nexport] = s;
+ nexport++;
}
- strnput("", isect->SizeOfRawData - nsize);
- cflush();
+ qsort(dexport, nexport, sizeof dexport[0], scmp);
+}
- // 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);
+void
+addexports(vlong fileoff)
+{
+ IMAGE_SECTION_HEADER *sect;
+ IMAGE_EXPORT_DIRECTORY e;
+ int size, i, va, va_name, va_addr, va_na, v;
+
+ size = sizeof e + 10*nexport + strlen(outfile) + 1;
+ for(i=0; i<nexport; i++)
+ size += strlen(dexport[i]->dynimpname) + 1;
+
+ if (nexport == 0)
+ return;
+
+ sect = addpesection(".edata", size, size, 0);
+ sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
+ va = sect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
+
+ seek(cout, fileoff, 0);
+ va_name = va + sizeof e + nexport*4;
+ va_addr = va + sizeof e;
+ va_na = va + sizeof e + nexport*8;
+
+ e.Characteristics = 0;
+ e.MajorVersion = 0;
+ e.MinorVersion = 0;
+ e.NumberOfFunctions = nexport;
+ e.NumberOfNames = nexport;
+ e.Name = va + sizeof e + nexport*10; // Program names.
+ e.Base = 1;
+ e.AddressOfFunctions = va_addr;
+ e.AddressOfNames = va_name;
+ e.AddressOfNameOrdinals = va_na;
+ // put IMAGE_EXPORT_DIRECTORY
+ for (i=0; i<sizeof(e); i++)
+ cput(((char*)&e)[i]);
+ // put EXPORT Address Table
+ for(i=0; i<nexport; i++)
+ lputl(dexport[i]->value - PEBASE);
+ // put EXPORT Name Pointer Table
+ v = e.Name + strlen(outfile)+1;
+ for(i=0; i<nexport; i++) {
+ lputl(v);
+ v += strlen(dexport[i]->dynimpname)+1;
}
+ // put EXPORT Ordinal Table
+ for(i=0; i<nexport; i++)
+ wputl(i);
+ // put Names
+ strnput(outfile, strlen(outfile)+1);
+ for(i=0; i<nexport; i++)
+ strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
+ strnput("", sect->SizeOfRawData - size);
cflush();
+
seek(cout, 0, 2);
}
void
dope(void)
{
+ Sym *rel;
+
+ /* relocation table */
+ rel = lookup(".rel", 0);
+ rel->reachable = 1;
+ rel->type = SELFDATA;
+
initdynimport();
+ initdynexport();
+}
+
+/*
+ * 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
+ * the string table.
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+IMAGE_SECTION_HEADER*
+newPEDWARFSection(char *name, vlong size)
+{
+ IMAGE_SECTION_HEADER *h;
+ char s[8];
+
+ 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 ++;
+ h = addpesection(s, size, size, 0);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+
+ return h;
+}
+
+static void
+addsymtable(void)
+{
+ IMAGE_SECTION_HEADER *h;
+ int i, size;
+
+ if(nextsymoff == 0)
+ return;
+
+ size = nextsymoff + 4;
+ h = addpesection(".symtab", size, size, 0);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+ fh.PointerToSymbolTable = cpos();
+ fh.NumberOfSymbols = 0;
+ // put symbol string table
+ lputl(size);
+ for (i=0; i<nextsymoff; i++)
+ cput(symnames[i]);
+ strnput("", h->SizeOfRawData - size);
+ cflush();
}
void
@@ -324,42 +486,51 @@ asmbpe(void)
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
addimports(nextfileoff, d);
+
+ addexports(nextfileoff);
+
+ if(!debug['s'])
+ dwarfaddpeheaders();
+ addsymtable();
+
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')
+ if (pe64) {
+ fh.SizeOfOptionalHeader = sizeof(oh64);
+ set(Magic, 0x20b); // PE32+
+ } else {
+ fh.SizeOfOptionalHeader = sizeof(oh);
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;
+ set(Magic, 0x10b); // PE32
+ oh.BaseOfData = d->VirtualAddress;
+ }
+ set(MajorLinkerVersion, 1);
+ set(MinorLinkerVersion, 0);
+ set(SizeOfCode, t->SizeOfRawData);
+ set(SizeOfInitializedData, d->SizeOfRawData);
+ set(SizeOfUninitializedData, 0);
+ set(AddressOfEntryPoint, entryvalue()-PEBASE);
+ set(BaseOfCode, t->VirtualAddress);
+ set(ImageBase, PEBASE);
+ set(SectionAlignment, PESECTALIGN);
+ set(FileAlignment, PEFILEALIGN);
+ set(MajorOperatingSystemVersion, 4);
+ set(MinorOperatingSystemVersion, 0);
+ set(MajorImageVersion, 1);
+ set(MinorImageVersion, 0);
+ set(MajorSubsystemVersion, 4);
+ set(MinorSubsystemVersion, 0);
+ set(SizeOfImage, nextsectoff);
+ set(SizeOfHeaders, PEFILEHEADR);
+ set(Subsystem, 3); // WINDOWS_CUI
+ set(SizeOfStackReserve, 0x00200000);
+ set(SizeOfStackCommit, 0x00001000);
+ set(SizeOfHeapReserve, 0x00100000);
+ set(SizeOfHeapCommit, 0x00001000);
+ set(NumberOfRvaAndSizes, 16);
pewrite();
}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index f8161cc4a..6dbf6a5be 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -72,6 +72,20 @@ typedef struct {
uint32 FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ uint32 Characteristics;
+ uint32 TimeDateStamp;
+ uint16 MajorVersion;
+ uint16 MinorVersion;
+ uint32 Name;
+ uint32 Base;
+ uint32 NumberOfFunctions;
+ uint32 NumberOfNames;
+ uint32 AddressOfFunctions;
+ uint32 AddressOfNames;
+ uint32 AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY;
+
#define PEBASE 0x00400000
// SectionAlignment must be greater than or equal to FileAlignment.
// The default is the page size for the architecture.
@@ -99,6 +113,7 @@ enum {
IMAGE_SCN_MEM_EXECUTE = 0x20000000,
IMAGE_SCN_MEM_READ = 0x40000000,
IMAGE_SCN_MEM_WRITE = 0x80000000,
+ IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
@@ -122,3 +137,38 @@ void peinit(void);
void asmbpe(void);
void dope(void);
+IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
+
+// X64
+typedef struct {
+ uint16 Magic;
+ uint8 MajorLinkerVersion;
+ uint8 MinorLinkerVersion;
+ uint32 SizeOfCode;
+ uint32 SizeOfInitializedData;
+ uint32 SizeOfUninitializedData;
+ uint32 AddressOfEntryPoint;
+ uint32 BaseOfCode;
+ uint64 ImageBase;
+ uint32 SectionAlignment;
+ uint32 FileAlignment;
+ uint16 MajorOperatingSystemVersion;
+ uint16 MinorOperatingSystemVersion;
+ uint16 MajorImageVersion;
+ uint16 MinorImageVersion;
+ uint16 MajorSubsystemVersion;
+ uint16 MinorSubsystemVersion;
+ uint32 Win32VersionValue;
+ uint32 SizeOfImage;
+ uint32 SizeOfHeaders;
+ uint32 CheckSum;
+ uint16 Subsystem;
+ uint16 DllCharacteristics;
+ uint64 SizeOfStackReserve;
+ uint64 SizeOfStackCommit;
+ uint64 SizeOfHeapReserve;
+ uint64 SizeOfHeapCommit;
+ uint32 LoaderFlags;
+ uint32 NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} PE64_IMAGE_OPTIONAL_HEADER;