From 3aec5516ed89ac01f8885b3c17b6f1fe5ee26fc5 Mon Sep 17 00:00:00 2001 From: Wei Guangjing Date: Thu, 20 Jan 2011 09:21:10 -0500 Subject: [PATCH] 6l: windows/amd64 port R=rsc CC=golang-dev https://golang.org/cl/3746044 --- src/cmd/6l/Makefile | 2 + src/cmd/6l/asm.c | 13 ++++- src/cmd/6l/l.h | 1 + src/cmd/6l/obj.c | 16 ++++++ src/cmd/6l/pass.c | 38 +++++++++++++ src/cmd/ld/data.c | 2 +- src/cmd/ld/pe.c | 135 +++++++++++++++++++++++++++++--------------- src/cmd/ld/pe.h | 33 +++++++++++ 8 files changed, 192 insertions(+), 48 deletions(-) diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index fba1b42ae4..f7d2a550c3 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -22,6 +22,7 @@ OFILES=\ obj.$O\ optab.$O\ pass.$O\ + pe.$O\ prof.$O\ span.$O\ symtab.$O\ @@ -33,6 +34,7 @@ HFILES=\ ../ld/elf.h\ ../ld/macho.h\ ../ld/dwarf.h\ + ../ld/pe.h\ include ../../Make.ccmd diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 9726d227cd..2119395b38 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -35,6 +35,7 @@ #include "../ld/elf.h" #include "../ld/dwarf.h" #include "../ld/macho.h" +#include "../ld/pe.h" #define Dbufslop 100 @@ -782,6 +783,8 @@ asmb(void) if(!debug['d']) elftextsh += 10; break; + case 10: + break; } symsize = 0; @@ -807,6 +810,10 @@ asmb(void) symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen; symo = rnd(symo, INITRND); break; + case 10: + symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; + symo = rnd(symo, PEFILEALIGN); + break; } /* * the symbol information is stored as @@ -829,7 +836,7 @@ asmb(void) lputl(symsize); lputl(lcsize); cflush(); - if(!debug['s']) { + if(HEADTYPE != 10 && !debug['s']) { elfsymo = symo+8+symsize+lcsize; seek(cout, elfsymo, 0); asmelfsym64(); @@ -1090,6 +1097,9 @@ asmb(void) if(a+elfwriteinterp() > ELFRESERVE) diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); break; + case 10: + asmbpe(); + break; } cflush(); } @@ -1143,6 +1153,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) case SDATA: case SELFDATA: case SMACHOGOT: + case SWINDOWS: if(!s->reachable) continue; put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index d3639d0f2b..01896d3599 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -183,6 +183,7 @@ enum SRODATA, SDATA, SMACHOGOT, + SWINDOWS, SBSS, SXREF, diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 96d78c3b99..eae76e5d86 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -36,6 +36,7 @@ #include "../ld/elf.h" #include "../ld/macho.h" #include "../ld/dwarf.h" +#include "../ld/pe.h" #include char *noname = ""; @@ -132,6 +133,9 @@ main(int argc, char *argv[]) else if(strcmp(goos, "freebsd") == 0) HEADTYPE = 9; + else + if(strcmp(goos, "windows") == 0) + HEADTYPE = 10; else print("goos is not known: %s\n", goos); } @@ -200,6 +204,16 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; + case 10: /* PE executable */ + peinit(); + HEADR = PEFILEHEADR; + if(INITTEXT == -1) + INITTEXT = PEBASE+PESECTHEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = PESECTALIGN; + break; } if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%llux is ignored because of -R0x%ux\n", @@ -245,6 +259,8 @@ main(int argc, char *argv[]) else doprof2(); span(); + if(HEADTYPE == 10) + dope(); addexport(); textaddress(); pclntab(); diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index 5c4ed00a69..5eb221a35d 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -277,6 +277,29 @@ patch(void) vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { + if(HEADTYPE == 10) { + // Windows + // Convert + // op n(GS), reg + // to + // MOVL 0x58(GS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI + && p->from.offset != 0x58) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + } + } if(HEADTYPE == 7 || HEADTYPE == 9) { // ELF uses FS instead of GS. if(p->from.type == D_INDIR+D_GS) @@ -411,6 +434,21 @@ dostkoff(void) p->from.type = D_INDIR+D_GS; p->from.offset = tlsoffset+0; p->to.type = D_CX; + if(HEADTYPE == 10) { // Windows + // movq %gs:0x58, %rcx + // movq (%rcx), %rcx + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + p->to.type = D_CX; + + + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + } if(debug['K']) { // 6l -K means check not only for stack diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 210f10ab56..27e0078d74 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -871,7 +871,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/pe.c b/src/cmd/ld/pe.c index 661d307185..b8ce99e3e5 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -43,6 +43,7 @@ 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]; typedef struct Imp Imp; @@ -102,13 +103,14 @@ peinit(void) // 64-bit architectures case '6': pe64 = 1; + PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh64)+sizeof(sh), PEFILEALIGN); break; // 32-bit architectures default: + PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN); break; } - - PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN); + PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); nextsectoff = PESECTHEADR; nextfileoff = PEFILEHEADR; @@ -125,8 +127,13 @@ pewrite(void) for (i=0; is->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; @@ -233,8 +240,8 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) for(d = dr; d != nil; d = d->next) { d->thunkoff = cpos() - n; for(m = d->ms; m != nil; m = m->next) - lputl(m->off); - lputl(0); + pe64 ? vputl(m->off) : lputl(m->off); + pe64 ? vputl(0): lputl(0); } // add pe section and pad it at the end @@ -250,11 +257,11 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) seek(cout, datsect->PointerToRawData + ftbase, 0); for(d = dr; d != nil; d = d->next) { for(m = d->ms; m != nil; m = m->next) - lputl(m->off); - lputl(0); + pe64 ? vputl(m->off) : lputl(m->off); + pe64 ? vputl(0): lputl(0); } cflush(); - + // finally write import descriptor table seek(cout, fileoff, 0); for(d = dr; d != nil; d = d->next) { @@ -272,10 +279,17 @@ addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) cflush(); // update data directory - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; + if(pe64) { + oh64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; + oh64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; + oh64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; + oh64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; + } else { + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; + } seek(cout, 0, 2); } @@ -308,7 +322,7 @@ asmbpe(void) IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ; - d = addpesection(".data", segdata.len, segdata.filelen, &segdata); + d = addpesection(".data", segdata.len, pe64 ? segdata.len : segdata.filelen, &segdata); d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; @@ -316,39 +330,68 @@ asmbpe(void) 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; + if (pe64) { + fh.SizeOfOptionalHeader = sizeof(oh64); + oh64.Magic = 0x20b; // PE32+ + oh64.MajorLinkerVersion = 1; + oh64.MinorLinkerVersion = 0; + oh64.SizeOfCode = t->SizeOfRawData; + oh64.SizeOfInitializedData = d->SizeOfRawData; + oh64.SizeOfUninitializedData = 0; + oh64.AddressOfEntryPoint = entryvalue()-PEBASE; + oh64.BaseOfCode = t->VirtualAddress; + + oh64.ImageBase = PEBASE; + oh64.SectionAlignment = PESECTALIGN; + oh64.FileAlignment = PEFILEALIGN; + oh64.MajorOperatingSystemVersion = 4; + oh64.MinorOperatingSystemVersion = 0; + oh64.MajorImageVersion = 1; + oh64.MinorImageVersion = 0; + oh64.MajorSubsystemVersion = 4; + oh64.MinorSubsystemVersion = 0; + oh64.SizeOfImage = nextsectoff; + oh64.SizeOfHeaders = PEFILEHEADR; + oh64.Subsystem = 3; // WINDOWS_CUI + oh64.SizeOfStackReserve = 0x00200000; + oh64.SizeOfStackCommit = 0x00001000; + oh64.SizeOfHeapReserve = 0x00100000; + oh64.SizeOfHeapCommit = 0x00001000; + oh64.NumberOfRvaAndSizes = 16; + } 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; + } pewrite(); } diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index f8161cc4a6..7c19630f41 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -122,3 +122,36 @@ void peinit(void); void asmbpe(void); void dope(void); +// 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; -- 2.50.0