tccpe: support pe32+ (x86_64) target

This commit is contained in:
grischka 2009-07-06 21:35:25 +02:00 committed by unknown
parent fe8def3303
commit f366cb20fe

118
tccpe.c
View file

@ -36,6 +36,12 @@
#define PE_MERGE_DATA #define PE_MERGE_DATA
// #define PE_PRINT_SECTIONS // #define PE_PRINT_SECTIONS
#ifdef TCC_TARGET_X86_64
# define ADDR3264 ULONGLONG
#else
# define ADDR3264 DWORD
#endif
#if defined _WIN32 && (defined _WIN64) == (defined TCC_TARGET_X86_64) #if defined _WIN32 && (defined _WIN64) == (defined TCC_TARGET_X86_64)
#define TCC_IS_NATIVE #define TCC_IS_NATIVE
#endif #endif
@ -48,6 +54,7 @@
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned long DWORD; typedef unsigned long DWORD;
typedef unsigned long long ULONGLONG;
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */
@ -104,10 +111,11 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD SizeOfUninitializedData; DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint; DWORD AddressOfEntryPoint;
DWORD BaseOfCode; DWORD BaseOfCode;
#ifndef TCC_TARGET_X86_64
DWORD BaseOfData; DWORD BaseOfData;
#endif
/* NT additional fields. */ /* NT additional fields. */
DWORD ImageBase; ADDR3264 ImageBase;
DWORD SectionAlignment; DWORD SectionAlignment;
DWORD FileAlignment; DWORD FileAlignment;
WORD MajorOperatingSystemVersion; WORD MajorOperatingSystemVersion;
@ -122,16 +130,14 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD CheckSum; DWORD CheckSum;
WORD Subsystem; WORD Subsystem;
WORD DllCharacteristics; WORD DllCharacteristics;
DWORD SizeOfStackReserve; ADDR3264 SizeOfStackReserve;
DWORD SizeOfStackCommit; ADDR3264 SizeOfStackCommit;
DWORD SizeOfHeapReserve; ADDR3264 SizeOfHeapReserve;
DWORD SizeOfHeapCommit; ADDR3264 SizeOfHeapCommit;
DWORD LoaderFlags; DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes; DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16]; IMAGE_DATA_DIRECTORY DataDirectory[16];
} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER;
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */
@ -193,7 +199,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
/* ----------------------------------------------------------- */ /* ----------------------------------------------------------- */
#endif /* ndef IMAGE_NT_SIGNATURE */ #endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */ /* ----------------------------------------------------------- */
#pragma pack(push, 1) #pragma pack(push, 1)
struct pe_header struct pe_header
@ -202,7 +207,15 @@ struct pe_header
BYTE dosstub[0x40]; BYTE dosstub[0x40];
DWORD nt_sig; DWORD nt_sig;
IMAGE_FILE_HEADER filehdr; IMAGE_FILE_HEADER filehdr;
#ifdef TCC_TARGET_X86_64
IMAGE_OPTIONAL_HEADER64 opthdr;
#else
#ifdef _WIN64
IMAGE_OPTIONAL_HEADER32 opthdr;
#else
IMAGE_OPTIONAL_HEADER opthdr; IMAGE_OPTIONAL_HEADER opthdr;
#endif
#endif
}; };
struct pe_import_header { struct pe_import_header {
@ -280,17 +293,32 @@ ST_DATA struct pe_header pe_header = {
0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
{ {
/* IMAGE_FILE_HEADER filehdr */ /* IMAGE_FILE_HEADER filehdr */
#ifdef TCC_TARGET_X86_64
0x8664, /*WORD Machine; */
#else
0x014C, /*WORD Machine; */ 0x014C, /*WORD Machine; */
#endif
0x0003, /*WORD NumberOfSections; */ 0x0003, /*WORD NumberOfSections; */
0x00000000, /*DWORD TimeDateStamp; */ 0x00000000, /*DWORD TimeDateStamp; */
0x00000000, /*DWORD PointerToSymbolTable; */ 0x00000000, /*DWORD PointerToSymbolTable; */
0x00000000, /*DWORD NumberOfSymbols; */ 0x00000000, /*DWORD NumberOfSymbols; */
#ifdef TCC_TARGET_X86_64
0x00F0, /*WORD SizeOfOptionalHeader; */
0x022F /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x222E
#else
0x00E0, /*WORD SizeOfOptionalHeader; */ 0x00E0, /*WORD SizeOfOptionalHeader; */
0x030F /*WORD Characteristics; */ 0x030F /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x230E
#endif
},{ },{
/* IMAGE_OPTIONAL_HEADER opthdr */ /* IMAGE_OPTIONAL_HEADER opthdr */
/* Standard fields. */ /* Standard fields. */
#ifdef TCC_TARGET_X86_64
0x020B, /*WORD Magic; */
#else
0x010B, /*WORD Magic; */ 0x010B, /*WORD Magic; */
#endif
0x06, /*BYTE MajorLinkerVersion; */ 0x06, /*BYTE MajorLinkerVersion; */
0x00, /*BYTE MinorLinkerVersion; */ 0x00, /*BYTE MinorLinkerVersion; */
0x00000000, /*DWORD SizeOfCode; */ 0x00000000, /*DWORD SizeOfCode; */
@ -298,8 +326,9 @@ ST_DATA struct pe_header pe_header = {
0x00000000, /*DWORD SizeOfUninitializedData; */ 0x00000000, /*DWORD SizeOfUninitializedData; */
0x00000000, /*DWORD AddressOfEntryPoint; */ 0x00000000, /*DWORD AddressOfEntryPoint; */
0x00000000, /*DWORD BaseOfCode; */ 0x00000000, /*DWORD BaseOfCode; */
#ifndef TCC_TARGET_X86_64
0x00000000, /*DWORD BaseOfData; */ 0x00000000, /*DWORD BaseOfData; */
#endif
/* NT additional fields. */ /* NT additional fields. */
0x00400000, /*DWORD ImageBase; */ 0x00400000, /*DWORD ImageBase; */
0x00001000, /*DWORD SectionAlignment; */ 0x00001000, /*DWORD SectionAlignment; */
@ -317,7 +346,12 @@ ST_DATA struct pe_header pe_header = {
0x0002, /*WORD Subsystem; */ 0x0002, /*WORD Subsystem; */
0x0000, /*WORD DllCharacteristics; */ 0x0000, /*WORD DllCharacteristics; */
0x00100000, /*DWORD SizeOfStackReserve; */ 0x00100000, /*DWORD SizeOfStackReserve; */
#ifdef TCC_TARGET_X86_64
// need to have a __chkstk eventually
0x00008000, /*DWORD SizeOfStackCommit; */
#else
0x00001000, /*DWORD SizeOfStackCommit; */ 0x00001000, /*DWORD SizeOfStackCommit; */
#endif
0x00100000, /*DWORD SizeOfHeapReserve; */ 0x00100000, /*DWORD SizeOfHeapReserve; */
0x00001000, /*DWORD SizeOfHeapCommit; */ 0x00001000, /*DWORD SizeOfHeapCommit; */
0x00000000, /*DWORD LoaderFlags; */ 0x00000000, /*DWORD LoaderFlags; */
@ -561,7 +595,9 @@ ST_FN int pe_write(struct pe_info *pe)
break; break;
case sec_data: case sec_data:
#ifndef TCC_TARGET_X86_64
pe_header.opthdr.BaseOfData = addr; pe_header.opthdr.BaseOfData = addr;
#endif
break; break;
case sec_bss: case sec_bss:
@ -614,7 +650,7 @@ ST_FN int pe_write(struct pe_info *pe)
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase; pe_header.opthdr.ImageBase = pe->imagebase;
if (PE_DLL == pe->type) if (PE_DLL == pe->type)
pe_header.filehdr.Characteristics = 0x230E; pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
else if (PE_GUI != pe->type) else if (PE_GUI != pe->type)
pe_header.opthdr.Subsystem = 3; pe_header.opthdr.Subsystem = 3;
@ -708,7 +744,7 @@ ST_FN void pe_build_imports(struct pe_info *pe)
pe->imp_offs = dll_ptr = pe->thunk->data_offset; pe->imp_offs = dll_ptr = pe->thunk->data_offset;
pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header); pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header);
pe->iat_offs = dll_ptr + pe->imp_size; pe->iat_offs = dll_ptr + pe->imp_size;
pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD); pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
thk_ptr = pe->iat_offs; thk_ptr = pe->iat_offs;
@ -717,7 +753,7 @@ ST_FN void pe_build_imports(struct pe_info *pe)
for (i = 0; i < pe->imp_count; ++i) { for (i = 0; i < pe->imp_count; ++i) {
struct pe_import_header *hdr; struct pe_import_header *hdr;
int k, n; int k, n;
DWORD v; ADDR3264 v;
struct pe_import_info *p = pe->imp_info[i]; struct pe_import_info *p = pe->imp_info[i];
const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name; const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name;
@ -747,7 +783,7 @@ ST_FN void pe_build_imports(struct pe_info *pe)
DLLReference *dllref = pe->s1->loaded_dlls[imp_sym->st_value-1]; DLLReference *dllref = pe->s1->loaded_dlls[imp_sym->st_value-1];
if ( !dllref->handle ) if ( !dllref->handle )
dllref->handle = LoadLibrary(dllref->name); dllref->handle = LoadLibrary(dllref->name);
v = (DWORD)GetProcAddress(dllref->handle, name); v = (ADDR3264)GetProcAddress(dllref->handle, name);
if (!v) if (!v)
error_noabort("undefined symbol '%s'", name); error_noabort("undefined symbol '%s'", name);
} }
@ -755,10 +791,10 @@ ST_FN void pe_build_imports(struct pe_info *pe)
} else { } else {
v = 0; /* last entry is zero */ v = 0; /* last entry is zero */
} }
*(DWORD*)(pe->thunk->data+thk_ptr) = *(ADDR3264*)(pe->thunk->data+thk_ptr) =
*(DWORD*)(pe->thunk->data+ent_ptr) = v; *(ADDR3264*)(pe->thunk->data+ent_ptr) = v;
thk_ptr += sizeof (DWORD); thk_ptr += sizeof (ADDR3264);
ent_ptr += sizeof (DWORD); ent_ptr += sizeof (ADDR3264);
} }
dll_ptr += sizeof(struct pe_import_header); dll_ptr += sizeof(struct pe_import_header);
dynarray_reset(&p->symbols, &p->sym_count); dynarray_reset(&p->symbols, &p->sym_count);
@ -1129,11 +1165,15 @@ ST_FN int pe_check_symbols(struct pe_info *pe)
} else { } else {
char buffer[100]; char buffer[100];
WORD *p;
offset = text_section->data_offset; offset = text_section->data_offset;
/* add the 'jmp IAT[x]' instruction */ /* add the 'jmp IAT[x]' instruction */
*(WORD*)section_ptr_add(text_section, 8) = 0x25FF; p = section_ptr_add(text_section, 8);
*p = 0x25FF;
#ifdef TCC_TARGET_X86_64
*(DWORD*)(p+1) = (DWORD)-4;
#endif
/* add a helper symbol, will be patched later in /* add a helper symbol, will be patched later in
pe_build_imports */ pe_build_imports */
sprintf(buffer, "IAT.%s", name); sprintf(buffer, "IAT.%s", name);
@ -1306,7 +1346,7 @@ ST_FN void pe_print_sections(TCCState *s1, const char *fname)
Section *s; Section *s;
FILE *f; FILE *f;
int i; int i;
f = fopen(fname, "wt"); f = fopen(fname, "w");
for (i = 1; i < s1->nb_sections; ++i) { for (i = 1; i < s1->nb_sections; ++i) {
s = s1->sections[i]; s = s1->sections[i];
pe_print_section(f, s); pe_print_section(f, s);
@ -1454,6 +1494,11 @@ quit:
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
#endif
ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
{ {
@ -1461,7 +1506,7 @@ ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
unsigned long addr = 0; unsigned long addr = 0;
int pe_type = 0; int pe_type = 0;
if (find_elf_sym(symtab_section, "_WinMain@16")) if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
pe_type = PE_GUI; pe_type = PE_GUI;
else else
if (TCC_OUTPUT_DLL == s1->output_type) { if (TCC_OUTPUT_DLL == s1->output_type) {
@ -1473,7 +1518,7 @@ ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
start_symbol = start_symbol =
TCC_OUTPUT_MEMORY == s1->output_type TCC_OUTPUT_MEMORY == s1->output_type
? PE_GUI == pe_type ? "_runwinmain" : NULL ? PE_GUI == pe_type ? "_runwinmain" : NULL
: PE_DLL == pe_type ? "__dllstart@12" : PE_DLL == pe_type ? PE_STDSYM("_dllstart","@12")
: PE_GUI == pe_type ? "_winstart" : "_start" : PE_GUI == pe_type ? "_winstart" : "_start"
; ;
@ -1485,22 +1530,21 @@ ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
SHN_UNDEF, start_symbol); SHN_UNDEF, start_symbol);
if (0 == s1->nostdlib) { if (0 == s1->nostdlib) {
tcc_add_library(s1, "tcc1"); static const char *libs[] = {
#ifdef __CYGWIN__ "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
tcc_add_library(s1, "cygwin1"); };
#else const char **pp, *p;
tcc_add_library(s1, "msvcrt"); for (pp = libs; 0 != (p = *pp); ++pp) {
#endif if (0 == *p) {
tcc_add_library(s1, "kernel32"); if (PE_DLL != pe_type && PE_GUI != pe_type)
if (PE_DLL == pe_type || PE_GUI == pe_type) { break;
tcc_add_library(s1, "user32"); } else if (tcc_add_library(s1, p) < 0)
tcc_add_library(s1, "gdi32"); error_noabort("cannot find library: %s", p);
} }
} }
pe->type = pe_type;
if (start_symbol) { if (start_symbol) {
addr = (unsigned long)tcc_get_symbol_err(s1, start_symbol); addr = (ADDR3264)tcc_get_symbol_err(s1, start_symbol);
if (s1->output_type == TCC_OUTPUT_MEMORY && addr) if (s1->output_type == TCC_OUTPUT_MEMORY && addr)
/* for -run GUI's, put '_runwinmain' instead of 'main' */ /* for -run GUI's, put '_runwinmain' instead of 'main' */
add_elf_sym(symtab_section, add_elf_sym(symtab_section,
@ -1508,6 +1552,8 @@ ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
text_section->sh_num, "main"); text_section->sh_num, "main");
} }
pe->type = pe_type;
pe->start_addr = addr; pe->start_addr = addr;
} }