Commit 977e19d6 authored by Hector Chu's avatar Hector Chu Committed by Russ Cox

8l: add support for PE output.

R=rsc
https://golang.org/cl/166080
parent 2ef330eb
...@@ -17,6 +17,7 @@ OFILES=\ ...@@ -17,6 +17,7 @@ OFILES=\
obj.$O\ obj.$O\
optab.$O\ optab.$O\
pass.$O\ pass.$O\
pe.$O\
span.$O\ span.$O\
go.$O\ go.$O\
...@@ -25,6 +26,7 @@ HFILES=\ ...@@ -25,6 +26,7 @@ HFILES=\
../8l/8.out.h\ ../8l/8.out.h\
../ld/elf.h\ ../ld/elf.h\
../ld/macho.h\ ../ld/macho.h\
../ld/pe.h\
$(TARG): $(OFILES) $(TARG): $(OFILES)
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "../ld/lib.h" #include "../ld/lib.h"
#include "../ld/elf.h" #include "../ld/elf.h"
#include "../ld/macho.h" #include "../ld/macho.h"
#include "../ld/pe.h"
#define Dbufslop 100 #define Dbufslop 100
...@@ -531,6 +532,7 @@ asmb(void) ...@@ -531,6 +532,7 @@ asmb(void)
case 7: case 7:
case 8: case 8:
case 9: case 9:
case 10:
v = rnd(HEADR+textsize, INITRND); v = rnd(HEADR+textsize, INITRND);
seek(cout, v, 0); seek(cout, v, 0);
break; break;
...@@ -588,6 +590,7 @@ asmb(void) ...@@ -588,6 +590,7 @@ asmb(void)
case 7: case 7:
case 8: case 8:
case 9: case 9:
case 10:
symo = rnd(HEADR+textsize, INITRND)+datsize; symo = rnd(HEADR+textsize, INITRND)+datsize;
symo = rnd(symo, INITRND); symo = rnd(symo, INITRND);
break; break;
...@@ -605,6 +608,8 @@ asmb(void) ...@@ -605,6 +608,8 @@ asmb(void)
asmlc(); asmlc();
if(dlm) if(dlm)
asmdyn(); asmdyn();
if(HEADTYPE == 10)
strnput("", INITRND-(8+symsize+lcsize)%INITRND);
cflush(); cflush();
seek(cout, symo, 0); seek(cout, symo, 0);
lputl(symsize); lputl(symsize);
...@@ -1018,6 +1023,10 @@ asmb(void) ...@@ -1018,6 +1023,10 @@ asmb(void)
if(a+elfwriteinterp() > ELFRESERVE) if(a+elfwriteinterp() > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break; break;
case 10:
asmbpe();
break;
} }
cflush(); cflush();
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "../ld/lib.h" #include "../ld/lib.h"
#include "../ld/elf.h" #include "../ld/elf.h"
#include "../ld/macho.h" #include "../ld/macho.h"
#include "../ld/pe.h"
#include <ar.h> #include <ar.h>
#ifndef DEFAULT #ifndef DEFAULT
...@@ -94,7 +95,7 @@ main(int argc, char *argv[]) ...@@ -94,7 +95,7 @@ main(int argc, char *argv[])
listinit(); listinit();
memset(debug, 0, sizeof(debug)); memset(debug, 0, sizeof(debug));
nerrors = 0; nerrors = 0;
outfile = "8.out"; outfile = nil;
HEADTYPE = -1; HEADTYPE = -1;
INITTEXT = -1; INITTEXT = -1;
INITDAT = -1; INITDAT = -1;
...@@ -145,7 +146,7 @@ main(int argc, char *argv[]) ...@@ -145,7 +146,7 @@ main(int argc, char *argv[])
if(*argv == 0) if(*argv == 0)
usage(); usage();
libinit(); mywhatsys(); // get goos
if(HEADTYPE == -1) { if(HEADTYPE == -1) {
HEADTYPE = 2; HEADTYPE = 2;
...@@ -161,9 +162,21 @@ main(int argc, char *argv[]) ...@@ -161,9 +162,21 @@ main(int argc, char *argv[])
if(strcmp(goos, "freebsd") == 0) if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9; HEADTYPE = 9;
else else
print("goos is not known: %sn", goos); if(strcmp(goos, "mingw") == 0)
HEADTYPE = 10;
else
print("goos is not known: %s\n", goos);
}
if(outfile == nil) {
if(HEADTYPE == 10)
outfile = "8.out.exe";
else
outfile = "8.out";
} }
libinit();
switch(HEADTYPE) { switch(HEADTYPE) {
default: default:
diag("unknown -H option"); diag("unknown -H option");
...@@ -260,6 +273,16 @@ main(int argc, char *argv[]) ...@@ -260,6 +273,16 @@ main(int argc, char *argv[])
if(INITRND == -1) if(INITRND == -1)
INITRND = 4096; INITRND = 4096;
break; break;
case 10: /* PE executable */
peinit();
HEADR = PERESERVE;
if(INITTEXT == -1)
INITTEXT = PEBASE+0x1000;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = PEALIGN;
break;
} }
if(INITDAT != 0 && INITRND != 0) if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%lux is ignored because of -R0x%lux\n", print("warning: -D0x%lux is ignored because of -R0x%lux\n",
...@@ -387,6 +410,8 @@ main(int argc, char *argv[]) ...@@ -387,6 +410,8 @@ main(int argc, char *argv[])
doprof2(); doprof2();
span(); span();
doinit(); doinit();
if(HEADTYPE == 10)
dope();
asmb(); asmb();
undef(); undef();
if(debug['v']) { if(debug['v']) {
......
...@@ -358,6 +358,27 @@ patch(void) ...@@ -358,6 +358,27 @@ patch(void)
s = lookup("exit", 0); s = lookup("exit", 0);
vexit = s->value; vexit = s->value;
for(p = firstp; p != P; p = p->link) { for(p = firstp; p != P; p = p->link) {
if(HEADTYPE == 10) {
// Convert
// op n(GS), reg
// to
// MOVL 0x2C(FS), 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) {
q = appendp(p);
q->from = p->from;
q->from.type += p->to.type-D_GS;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x2C;
}
}
if(p->as == ATEXT) if(p->as == ATEXT)
curtext = p; curtext = p;
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
...@@ -575,10 +596,23 @@ dostkoff(void) ...@@ -575,10 +596,23 @@ dostkoff(void)
if(pmorestack != P) if(pmorestack != P)
if(!(p->from.scale & NOSPLIT)) { if(!(p->from.scale & NOSPLIT)) {
p = appendp(p); // load g into CX p = appendp(p); // load g into CX
if(HEADTYPE == 10) {
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x2c;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_CX;
} else {
p->as = AMOVL; p->as = AMOVL;
p->from.type = D_INDIR+D_GS; p->from.type = D_INDIR+D_GS;
p->from.offset = tlsoffset + 0; p->from.offset = tlsoffset + 0;
p->to.type = D_CX; p->to.type = D_CX;
}
if(debug['K']) { if(debug['K']) {
// 8l -K means check not only for stack // 8l -K means check not only for stack
......
...@@ -38,8 +38,11 @@ ...@@ -38,8 +38,11 @@
int int
systemtype(int sys) systemtype(int sys)
{ {
#ifdef __MINGW32__
return sys&Windows;
#else
return sys&Plan9; return sys&Plan9;
#endif
} }
int int
......
// Copyright 2009 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.
// PE (Portable Executable) file writing
// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
#include <time.h>
#include "l.h"
#include "../ld/lib.h"
#include "../ld/pe.h"
static int pe64;
static int nsect;
static int sect_virt_begin;
static int sect_raw_begin = PERESERVE;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
static IMAGE_SECTION_HEADER sh[16];
static IMAGE_SECTION_HEADER *textsect, *datsect, *bsssect;
static IMAGE_SECTION_HEADER*
new_section(char *name, int size, int noraw)
{
IMAGE_SECTION_HEADER *h;
if(nsect == 16) {
diag("too many sections");
errorexit();
}
h = &sh[nsect++];
strncpy(h->Name, name, sizeof(h->Name));
h->VirtualSize = size;
if(!sect_virt_begin)
sect_virt_begin = 0x1000;
h->VirtualAddress = sect_virt_begin;
sect_virt_begin = rnd(sect_virt_begin+size, 0x1000);
if(!noraw) {
h->SizeOfRawData = rnd(size, PEALIGN);
h->PointerToRawData = sect_raw_begin;
sect_raw_begin += h->SizeOfRawData;
}
return h;
}
void
peinit(void)
{
switch(thechar) {
// 64-bit architectures
case '6':
pe64 = 1;
break;
// 32-bit architectures
default:
break;
}
}
static void
pewrite(void)
{
int i, j;
strnput("MZ", 0x3c);
LPUT(0x40); // file offset to PE header
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]);
}
void
dope(void)
{
textsect = new_section(".text", textsize, 0);
textsect->Characteristics = IMAGE_SCN_CNT_CODE|
IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
datsect = new_section(".data", datsize, 0);
datsect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
INITDAT = PEBASE+datsect->VirtualAddress;
bsssect = new_section(".bss", bsssize, 1);
bsssect->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
void
asmbpe(void)
{
switch(thechar) {
default:
diag("unknown PE architecture");
errorexit();
case '6':
fh.Machine = IMAGE_FILE_MACHINE_AMD64;
break;
case '8':
fh.Machine = IMAGE_FILE_MACHINE_I386;
break;
}
if(!debug['s']) {
IMAGE_SECTION_HEADER *symsect;
symsect = new_section(".symdat", 8+symsize+lcsize, 0);
symsect->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_CNT_INITIALIZED_DATA;
}
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 = textsect->SizeOfRawData;
oh.SizeOfInitializedData = datsect->SizeOfRawData;
oh.SizeOfUninitializedData = bsssect->SizeOfRawData;
oh.AddressOfEntryPoint = entryvalue()-PEBASE;
oh.BaseOfCode = textsect->VirtualAddress;
oh.BaseOfData = datsect->VirtualAddress;
oh.ImageBase = PEBASE;
oh.SectionAlignment = 0x00001000;
oh.FileAlignment = PEALIGN;
oh.MajorOperatingSystemVersion = 4;
oh.MinorOperatingSystemVersion = 0;
oh.MajorImageVersion = 1;
oh.MinorImageVersion = 0;
oh.MajorSubsystemVersion = 4;
oh.MinorSubsystemVersion = 0;
oh.SizeOfImage = sect_virt_begin;
oh.SizeOfHeaders = PERESERVE;
oh.Subsystem = 3; // WINDOWS_CUI
oh.SizeOfStackReserve = 0x00200000;
oh.SizeOfStackCommit = 0x00001000;
oh.SizeOfHeapReserve = 0x00100000;
oh.SizeOfHeapCommit = 0x00001000;
oh.NumberOfRvaAndSizes = 16;
pewrite();
}
// Copyright 2009 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.
typedef struct {
uint16 Machine;
uint16 NumberOfSections;
uint32 TimeDateStamp;
uint32 PointerToSymbolTable;
uint32 NumberOfSymbols;
uint16 SizeOfOptionalHeader;
uint16 Characteristics;
} IMAGE_FILE_HEADER;
typedef struct {
uint32 VirtualAddress;
uint32 Size;
} IMAGE_DATA_DIRECTORY;
typedef struct {
uint16 Magic;
uint8 MajorLinkerVersion;
uint8 MinorLinkerVersion;
uint32 SizeOfCode;
uint32 SizeOfInitializedData;
uint32 SizeOfUninitializedData;
uint32 AddressOfEntryPoint;
uint32 BaseOfCode;
uint32 BaseOfData;
uint32 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;
uint32 SizeOfStackReserve;
uint32 SizeOfStackCommit;
uint32 SizeOfHeapReserve;
uint32 SizeOfHeapCommit;
uint32 LoaderFlags;
uint32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER;
typedef struct {
uint8 Name[8];
uint32 VirtualSize;
uint32 VirtualAddress;
uint32 SizeOfRawData;
uint32 PointerToRawData;
uint32 PointerToRelocations;
uint32 PointerToLineNumbers;
uint16 NumberOfRelocations;
uint16 NumberOfLineNumbers;
uint32 Characteristics;
} IMAGE_SECTION_HEADER;
#define PERESERVE 0x400
#define PEALIGN 0x200
#define PEBASE 0x00400000
enum {
IMAGE_FILE_MACHINE_I386 = 0x14c,
IMAGE_FILE_MACHINE_AMD64 = 0x8664,
IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
IMAGE_FILE_32BIT_MACHINE = 0x0100,
IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
IMAGE_SCN_CNT_CODE = 0x00000020,
IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
IMAGE_SCN_MEM_EXECUTE = 0x20000000,
IMAGE_SCN_MEM_READ = 0x40000000,
IMAGE_SCN_MEM_WRITE = 0x80000000,
};
void peinit(void);
void dope(void);
void asmbpe(void);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment