diff options
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 29 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 176 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.h | 1 | ||||
-rw-r--r-- | src/cmd/ld/ldpe.c | 406 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 4 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 1 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 419 | ||||
-rw-r--r-- | src/cmd/ld/pe.h | 50 |
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; |