summaryrefslogtreecommitdiff
path: root/tccpe.c
diff options
context:
space:
mode:
authorThomas Preud'homme <thomas.preudhomme@celest.fr>2011-06-17 00:21:43 +0200
committerThomas Preud'homme <thomas.preudhomme@celest.fr>2011-06-17 00:21:43 +0200
commitcfef8921f4b5dfa31fd2336484d86e24e3beb2f3 (patch)
tree73f4399c5558a3ec75a1ee7128315d7d32bcc1b1 /tccpe.c
parent406bee985de85229e0ba54a9efa767c194262d0c (diff)
Imported Upstream version 0.9.26+git20110616.330d2ee
Diffstat (limited to 'tccpe.c')
-rw-r--r--tccpe.c1231
1 files changed, 789 insertions, 442 deletions
diff --git a/tccpe.c b/tccpe.c
index 1e3fdb3..de2575a 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -18,11 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifdef TCC_TARGET_PE
-
-#define ST_FN static
-#define ST_DATA static
-#define PUB_FN
+#include "tcc.h"
#ifndef _WIN32
#define stricmp strcasecmp
@@ -36,6 +32,29 @@
#define PE_MERGE_DATA
// #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)
+#define TCC_IS_NATIVE
+#endif
+
+#ifdef _WIN32
+void dbg_printf (const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list arg;
+ int x;
+ va_start(arg, fmt);
+ x = vsprintf (buffer, fmt, arg);
+ strcpy(buffer+x, "\n");
+ OutputDebugString(buffer);
+}
+#endif
+
/* ----------------------------------------------------------- */
#ifndef IMAGE_NT_SIGNATURE
/* ----------------------------------------------------------- */
@@ -43,7 +62,8 @@
typedef unsigned char BYTE;
typedef unsigned short WORD;
-typedef unsigned long DWORD;
+typedef unsigned int DWORD;
+typedef unsigned long long ULONGLONG;
#pragma pack(push, 1)
typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */
@@ -100,10 +120,11 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
+#ifndef TCC_TARGET_X86_64
DWORD BaseOfData;
-
+#endif
/* NT additional fields. */
- DWORD ImageBase;
+ ADDR3264 ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
@@ -118,16 +139,14 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
- DWORD SizeOfStackReserve;
- DWORD SizeOfStackCommit;
- DWORD SizeOfHeapReserve;
- DWORD SizeOfHeapCommit;
+ ADDR3264 SizeOfStackReserve;
+ ADDR3264 SizeOfStackCommit;
+ ADDR3264 SizeOfHeapReserve;
+ ADDR3264 SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16];
-
-} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
-
+} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER;
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */
@@ -167,6 +186,31 @@ typedef struct _IMAGE_SECTION_HEADER {
#define IMAGE_SIZEOF_SECTION_HEADER 40
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ DWORD Characteristics;
+ DWORD TimeDateStamp;
+ WORD MajorVersion;
+ WORD MinorVersion;
+ DWORD Name;
+ DWORD Base;
+ DWORD NumberOfFunctions;
+ DWORD NumberOfNames;
+ DWORD AddressOfFunctions;
+ DWORD AddressOfNames;
+ DWORD AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
+
+typedef struct _IMAGE_IMPORT_DESCRIPTOR {
+ union {
+ DWORD Characteristics;
+ DWORD OriginalFirstThunk;
+ };
+ DWORD TimeDateStamp;
+ DWORD ForwarderChain;
+ DWORD Name;
+ DWORD FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR;
+
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
@@ -189,7 +233,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
/* ----------------------------------------------------------- */
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
-
#pragma pack(push, 1)
struct pe_header
@@ -198,28 +241,15 @@ struct pe_header
BYTE dosstub[0x40];
DWORD nt_sig;
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;
-};
-
-struct pe_import_header {
- DWORD first_entry;
- DWORD time_date;
- DWORD forwarder;
- DWORD lib_name_offset;
- DWORD first_thunk;
-};
-
-struct pe_export_header {
- DWORD Characteristics;
- DWORD TimeDateStamp;
- DWORD Version;
- DWORD Name;
- DWORD Base;
- DWORD NumberOfFunctions;
- DWORD NumberOfNames;
- DWORD AddressOfFunctions;
- DWORD AddressOfNames;
- DWORD AddressOfNameOrdinals;
+#endif
+#endif
};
struct pe_reloc_header {
@@ -240,90 +270,6 @@ struct pe_rsrc_reloc {
#pragma pack(pop)
-/* ----------------------------------------------------------- */
-ST_DATA struct pe_header pe_header = {
-{
- /* IMAGE_DOS_HEADER doshdr */
- 0x5A4D, /*WORD e_magic; Magic number */
- 0x0090, /*WORD e_cblp; Bytes on last page of file */
- 0x0003, /*WORD e_cp; Pages in file */
- 0x0000, /*WORD e_crlc; Relocations */
-
- 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */
- 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */
- 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */
- 0x0000, /*WORD e_ss; Initial (relative) SS value */
-
- 0x00B8, /*WORD e_sp; Initial SP value */
- 0x0000, /*WORD e_csum; Checksum */
- 0x0000, /*WORD e_ip; Initial IP value */
- 0x0000, /*WORD e_cs; Initial (relative) CS value */
- 0x0040, /*WORD e_lfarlc; File address of relocation table */
- 0x0000, /*WORD e_ovno; Overlay number */
- {0,0,0,0}, /*WORD e_res[4]; Reserved words */
- 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */
- 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */
- {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */
- 0x00000080 /*DWORD e_lfanew; File address of new exe header */
-},{
- /* BYTE dosstub[0x40] */
- /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
- 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
- 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
- 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
- 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-},
- 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
-{
- /* IMAGE_FILE_HEADER filehdr */
- 0x014C, /*WORD Machine; */
- 0x0003, /*WORD NumberOfSections; */
- 0x00000000, /*DWORD TimeDateStamp; */
- 0x00000000, /*DWORD PointerToSymbolTable; */
- 0x00000000, /*DWORD NumberOfSymbols; */
- 0x00E0, /*WORD SizeOfOptionalHeader; */
- 0x030F /*WORD Characteristics; */
-},{
- /* IMAGE_OPTIONAL_HEADER opthdr */
- /* Standard fields. */
- 0x010B, /*WORD Magic; */
- 0x06, /*BYTE MajorLinkerVersion; */
- 0x00, /*BYTE MinorLinkerVersion; */
- 0x00000000, /*DWORD SizeOfCode; */
- 0x00000000, /*DWORD SizeOfInitializedData; */
- 0x00000000, /*DWORD SizeOfUninitializedData; */
- 0x00000000, /*DWORD AddressOfEntryPoint; */
- 0x00000000, /*DWORD BaseOfCode; */
- 0x00000000, /*DWORD BaseOfData; */
-
- /* NT additional fields. */
- 0x00400000, /*DWORD ImageBase; */
- 0x00001000, /*DWORD SectionAlignment; */
- 0x00000200, /*DWORD FileAlignment; */
- 0x0004, /*WORD MajorOperatingSystemVersion; */
- 0x0000, /*WORD MinorOperatingSystemVersion; */
- 0x0000, /*WORD MajorImageVersion; */
- 0x0000, /*WORD MinorImageVersion; */
- 0x0004, /*WORD MajorSubsystemVersion; */
- 0x0000, /*WORD MinorSubsystemVersion; */
- 0x00000000, /*DWORD Win32VersionValue; */
- 0x00000000, /*DWORD SizeOfImage; */
- 0x00000200, /*DWORD SizeOfHeaders; */
- 0x00000000, /*DWORD CheckSum; */
- 0x0002, /*WORD Subsystem; */
- 0x0000, /*WORD DllCharacteristics; */
- 0x00100000, /*DWORD SizeOfStackReserve; */
- 0x00001000, /*DWORD SizeOfStackCommit; */
- 0x00100000, /*DWORD SizeOfHeapReserve; */
- 0x00001000, /*DWORD SizeOfHeapCommit; */
- 0x00000000, /*DWORD LoaderFlags; */
- 0x00000010, /*DWORD NumberOfRvaAndSizes; */
-
- /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */
- {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0},
- {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
-}};
-
/* ------------------------------------------------------------- */
/* internal temporary structures */
@@ -343,6 +289,7 @@ enum {
sec_data ,
sec_bss ,
sec_idata ,
+ sec_pdata ,
sec_other ,
sec_rsrc ,
sec_stab ,
@@ -350,11 +297,12 @@ enum {
sec_last
};
-ST_DATA DWORD pe_sec_flags[] = {
+static const DWORD pe_sec_flags[] = {
0x60000020, /* ".text" , */
0xC0000040, /* ".data" , */
0xC0000080, /* ".bss" , */
0x40000040, /* ".idata" , */
+ 0x40000040, /* ".pdata" , */
0xE0000060, /* < other > , */
0x40000040, /* ".rsrc" , */
0x42000802, /* ".stab" , */
@@ -399,113 +347,67 @@ struct pe_info {
DWORD iat_size;
DWORD exp_offs;
DWORD exp_size;
+ int subsystem;
+ DWORD section_align;
+ DWORD file_align;
struct section_info *sec_info;
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
};
-/* ------------------------------------------------------------- */
-
#define PE_NUL 0
#define PE_DLL 1
#define PE_GUI 2
#define PE_EXE 3
-
-void error_noabort(const char *, ...);
-
-#ifdef _WIN32
-void dbg_printf (const char *fmt, ...)
-{
- char buffer[4000];
- va_list arg;
- int x;
- va_start(arg, fmt);
- x = vsprintf (buffer, fmt, arg);
- strcpy(buffer+x, "\n");
- OutputDebugString(buffer);
-}
-#endif
+#define PE_RUN 4
/* --------------------------------------------*/
-ST_FN const char* get_alt_symbol(char *buffer, const char *symbol)
+static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym)
{
- const char *p;
- p = strrchr(symbol, '@');
- if (p && isnum(p[1]) && symbol[0] == '_') { /* stdcall decor */
- strcpy(buffer, symbol+1)[p-symbol-1] = 0;
- } else if (symbol[0] != '_') { /* try non-ansi function */
- buffer[0] = '_', strcpy(buffer + 1, symbol);
- } else if (0 == memcmp(symbol, "__imp__", 7)) { /* mingw 2.0 */
- strcpy(buffer, symbol + 6);
- } else if (0 == memcmp(symbol, "_imp___", 7)) { /* mingw 3.7 */
- strcpy(buffer, symbol + 6);
- } else {
- return symbol;
- }
- return buffer;
+ const char *name = symtab_section->link->data + sym->st_name;
+ if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & 2))
+ return name + 1;
+ return name;
}
-ST_FN int pe_find_import(TCCState * s1, const char *symbol)
+static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
{
char buffer[200];
- const char *s;
+ const char *s, *p;
int sym_index, n = 0;
+
do {
- s = n ? get_alt_symbol(buffer, symbol) : symbol;
+ s = pe_export_name(s1, sym);
+ if (n) {
+ /* second try: */
+ if (sym->st_other & 2) {
+ /* try w/0 stdcall deco (windows API convention) */
+ p = strrchr(s, '@');
+ if (!p || s[0] != '_')
+ break;
+ strcpy(buffer, s+1)[p-s-1] = 0;
+ } else if (s[0] != '_') { /* try non-ansi function */
+ buffer[0] = '_', strcpy(buffer + 1, s);
+ } else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */
+ strcpy(buffer, s + 6);
+ } else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */
+ strcpy(buffer, s + 6);
+ } else {
+ break;
+ }
+ s = buffer;
+ }
sym_index = find_elf_sym(s1->dynsymtab_section, s);
- // printf("find %d %s\n", sym_index, s);
+ // printf("find (%d) %d %s\n", n, sym_index, s);
} while (0 == sym_index && ++n < 2);
return sym_index;
}
-#if defined _WIN32 || defined __CYGWIN__
-
-#ifdef __CYGWIN__
-# include <dlfcn.h>
-# define LoadLibrary(s) dlopen(s, RTLD_NOW)
-# define GetProcAddress(h,s) dlsym(h, s)
-#else
-# define dlclose(h) FreeLibrary(h)
-#endif
-
-/* for the -run option: dynamically load symbol from dll */
-void *resolve_sym(struct TCCState *s1, const char *symbol, int type)
-{
- char buffer[100];
- int sym_index, dll_index;
- void *addr, **m;
- DLLReference *dllref;
-
- sym_index = pe_find_import(s1, symbol);
- if (0 == sym_index)
- return NULL;
- dll_index = ((Elf32_Sym *)s1->dynsymtab_section->data + sym_index)->st_value;
- dllref = s1->loaded_dlls[dll_index-1];
- if ( !dllref->handle )
- {
- dllref->handle = LoadLibrary(dllref->name);
- }
- addr = GetProcAddress(dllref->handle, symbol);
- if (NULL == addr)
- addr = GetProcAddress(dllref->handle, get_alt_symbol(buffer, symbol));
-
- if (addr && STT_OBJECT == type) {
- /* need to return a pointer to the address for data objects */
- m = (void**)tcc_malloc(sizeof addr), *m = addr, addr = m;
-#ifdef MEM_DEBUG
- /* yep, we don't free it */
- mem_cur_size -= sizeof (void*);
-#endif
- }
- return addr;
-}
-#endif
-
/*----------------------------------------------------------------------------*/
-ST_FN int dynarray_assoc(void **pp, int n, int key)
+static int dynarray_assoc(void **pp, int n, int key)
{
int i;
for (i = 0; i < n; ++i, ++pp)
@@ -521,76 +423,205 @@ ST_FN DWORD umin(DWORD a, DWORD b)
}
#endif
-ST_FN DWORD umax(DWORD a, DWORD b)
+static DWORD umax(DWORD a, DWORD b)
{
return a < b ? b : a;
}
-ST_FN void pe_fpad(FILE *fp, DWORD new_pos)
-{
- DWORD pos = ftell(fp);
- while (++pos <= new_pos)
- fputc(0, fp);
-}
-
-ST_FN DWORD pe_file_align(DWORD n)
+static DWORD pe_file_align(struct pe_info *pe, DWORD n)
{
- return (n + (0x200 - 1)) & ~(0x200 - 1);
+ return (n + (pe->file_align - 1)) & ~(pe->file_align - 1);
}
-ST_FN DWORD pe_virtual_align(DWORD n)
+static DWORD pe_virtual_align(struct pe_info *pe, DWORD n)
{
- return (n + (0x1000 - 1)) & ~(0x1000 - 1);
+ return (n + (pe->section_align - 1)) & ~(pe->section_align - 1);
}
-ST_FN void pe_align_section(Section *s, int a)
+static void pe_align_section(Section *s, int a)
{
int i = s->data_offset & (a-1);
if (i)
section_ptr_add(s, a - i);
}
-ST_FN void pe_set_datadir(int dir, DWORD addr, DWORD size)
+static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size)
+{
+ hdr->opthdr.DataDirectory[dir].VirtualAddress = addr;
+ hdr->opthdr.DataDirectory[dir].Size = size;
+}
+
+static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
{
- pe_header.opthdr.DataDirectory[dir].VirtualAddress = addr;
- pe_header.opthdr.DataDirectory[dir].Size = size;
+ if (psum) {
+ DWORD sum = *psum;
+ WORD *p = data;
+ int i;
+ for (i = len; i > 0; i -= 2) {
+ sum += (i >= 2) ? *p++ : *(BYTE*)p;
+ sum = (sum + (sum >> 16)) & 0xFFFF;
+ }
+ *psum = sum;
+ }
+ return len == fwrite(data, 1, len, fp) ? 0 : -1;
+}
+
+static void pe_fpad(FILE *fp, DWORD new_pos)
+{
+ DWORD pos = ftell(fp);
+ while (++pos <= new_pos)
+ fputc(0, fp);
}
/*----------------------------------------------------------------------------*/
-ST_FN int pe_write(struct pe_info *pe)
+static int pe_write(struct pe_info *pe)
{
+ static const struct pe_header pe_template = {
+ {
+ /* IMAGE_DOS_HEADER doshdr */
+ 0x5A4D, /*WORD e_magic; Magic number */
+ 0x0090, /*WORD e_cblp; Bytes on last page of file */
+ 0x0003, /*WORD e_cp; Pages in file */
+ 0x0000, /*WORD e_crlc; Relocations */
+
+ 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */
+ 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */
+ 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */
+ 0x0000, /*WORD e_ss; Initial (relative) SS value */
+
+ 0x00B8, /*WORD e_sp; Initial SP value */
+ 0x0000, /*WORD e_csum; Checksum */
+ 0x0000, /*WORD e_ip; Initial IP value */
+ 0x0000, /*WORD e_cs; Initial (relative) CS value */
+ 0x0040, /*WORD e_lfarlc; File address of relocation table */
+ 0x0000, /*WORD e_ovno; Overlay number */
+ {0,0,0,0}, /*WORD e_res[4]; Reserved words */
+ 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */
+ 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */
+ {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */
+ 0x00000080 /*DWORD e_lfanew; File address of new exe header */
+ },{
+ /* BYTE dosstub[0x40] */
+ /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
+ 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
+ 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
+ 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
+ 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ },
+ 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
+ {
+ /* IMAGE_FILE_HEADER filehdr */
+#if defined(TCC_TARGET_I386)
+ 0x014C, /*WORD Machine; */
+#elif defined(TCC_TARGET_X86_64)
+ 0x8664, /*WORD Machine; */
+#elif defined(TCC_TARGET_ARM)
+ 0x01C0, /*WORD Machine; */
+#endif
+ 0x0003, /*WORD NumberOfSections; */
+ 0x00000000, /*DWORD TimeDateStamp; */
+ 0x00000000, /*DWORD PointerToSymbolTable; */
+ 0x00000000, /*DWORD NumberOfSymbols; */
+#if defined(TCC_TARGET_X86_64)
+ 0x00F0, /*WORD SizeOfOptionalHeader; */
+ 0x022F /*WORD Characteristics; */
+#define CHARACTERISTICS_DLL 0x222E
+#elif defined(TCC_TARGET_I386)
+ 0x00E0, /*WORD SizeOfOptionalHeader; */
+ 0x030F /*WORD Characteristics; */
+#define CHARACTERISTICS_DLL 0x230E
+#elif defined(TCC_TARGET_ARM)
+ 0x00E0, /*WORD SizeOfOptionalHeader; */
+ 0x010F, /*WORD Characteristics; */
+#define CHARACTERISTICS_DLL 0x230F
+#endif
+},{
+ /* IMAGE_OPTIONAL_HEADER opthdr */
+ /* Standard fields. */
+#ifdef TCC_TARGET_X86_64
+ 0x020B, /*WORD Magic; */
+#else
+ 0x010B, /*WORD Magic; */
+#endif
+ 0x06, /*BYTE MajorLinkerVersion; */
+ 0x00, /*BYTE MinorLinkerVersion; */
+ 0x00000000, /*DWORD SizeOfCode; */
+ 0x00000000, /*DWORD SizeOfInitializedData; */
+ 0x00000000, /*DWORD SizeOfUninitializedData; */
+ 0x00000000, /*DWORD AddressOfEntryPoint; */
+ 0x00000000, /*DWORD BaseOfCode; */
+#ifndef TCC_TARGET_X86_64
+ 0x00000000, /*DWORD BaseOfData; */
+#endif
+ /* NT additional fields. */
+#if defined(TCC_TARGET_ARM)
+ 0x00100000, /*DWORD ImageBase; */
+#else
+ 0x00400000, /*DWORD ImageBase; */
+#endif
+ 0x00001000, /*DWORD SectionAlignment; */
+ 0x00000200, /*DWORD FileAlignment; */
+ 0x0004, /*WORD MajorOperatingSystemVersion; */
+ 0x0000, /*WORD MinorOperatingSystemVersion; */
+ 0x0000, /*WORD MajorImageVersion; */
+ 0x0000, /*WORD MinorImageVersion; */
+ 0x0004, /*WORD MajorSubsystemVersion; */
+ 0x0000, /*WORD MinorSubsystemVersion; */
+ 0x00000000, /*DWORD Win32VersionValue; */
+ 0x00000000, /*DWORD SizeOfImage; */
+ 0x00000200, /*DWORD SizeOfHeaders; */
+ 0x00000000, /*DWORD CheckSum; */
+ 0x0002, /*WORD Subsystem; */
+ 0x0000, /*WORD DllCharacteristics; */
+ 0x00100000, /*DWORD SizeOfStackReserve; */
+ 0x00001000, /*DWORD SizeOfStackCommit; */
+ 0x00100000, /*DWORD SizeOfHeapReserve; */
+ 0x00001000, /*DWORD SizeOfHeapCommit; */
+ 0x00000000, /*DWORD LoaderFlags; */
+ 0x00000010, /*DWORD NumberOfRvaAndSizes; */
+
+ /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */
+ {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0},
+ {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+ }};
+
+ struct pe_header pe_header = pe_template;
+
int i;
FILE *op;
- DWORD file_offset, r;
+ DWORD file_offset, sum;
+ struct section_info *si;
+ IMAGE_SECTION_HEADER *psh;
op = fopen(pe->filename, "wb");
if (NULL == op) {
error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
- return 1;
+ return -1;
}
- pe->sizeofheaders = pe_file_align(
- sizeof pe_header
+ pe->sizeofheaders = pe_file_align(pe,
+ sizeof (struct pe_header)
+ pe->sec_count * sizeof (IMAGE_SECTION_HEADER)
);
file_offset = pe->sizeofheaders;
- pe_fpad(op, file_offset);
if (2 == pe->s1->verbose)
printf("-------------------------------"
"\n virt file size section" "\n");
-
for (i = 0; i < pe->sec_count; ++i) {
- struct section_info *si = pe->sec_info + i;
- const char *sh_name = si->name;
- unsigned long addr = si->sh_addr - pe->imagebase;
- unsigned long size = si->sh_size;
- IMAGE_SECTION_HEADER *psh = &si->ish;
+ DWORD addr, size;
+ const char *sh_name;
+
+ si = pe->sec_info + i;
+ sh_name = si->name;
+ addr = si->sh_addr - pe->imagebase;
+ size = si->sh_size;
+ psh = &si->ish;
if (2 == pe->s1->verbose)
- printf("%6lx %6lx %6lx %s\n",
- addr, file_offset, size, sh_name);
+ printf("%6x %6x %6x %s\n",
+ (unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name);
switch (si->cls) {
case sec_text:
@@ -599,18 +630,24 @@ ST_FN int pe_write(struct pe_info *pe)
break;
case sec_data:
+#ifndef TCC_TARGET_X86_64
pe_header.opthdr.BaseOfData = addr;
+#endif
break;
case sec_bss:
break;
case sec_reloc:
- pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
break;
case sec_rsrc:
- pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
+ break;
+
+ case sec_pdata:
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
break;
case sec_stab:
@@ -619,13 +656,13 @@ ST_FN int pe_write(struct pe_info *pe)
if (pe->thunk == pe->s1->sections[si->ord]) {
if (pe->imp_size) {
- pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT,
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs + addr, pe->imp_size);
- pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT,
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs + addr, pe->iat_size);
}
if (pe->exp_size) {
- pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT,
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs + addr, pe->exp_size);
}
}
@@ -636,52 +673,102 @@ ST_FN int pe_write(struct pe_info *pe)
psh->VirtualAddress = addr;
psh->Misc.VirtualSize = size;
pe_header.opthdr.SizeOfImage =
- umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage);
+ umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage);
if (si->data_size) {
- psh->PointerToRawData = r = file_offset;
- fwrite(si->data, 1, si->data_size, op);
- file_offset = pe_file_align(file_offset + si->data_size);
- psh->SizeOfRawData = file_offset - r;
- pe_fpad(op, file_offset);
+ psh->PointerToRawData = file_offset;
+ file_offset = pe_file_align(pe, file_offset + si->data_size);
+ psh->SizeOfRawData = file_offset - psh->PointerToRawData;
}
}
- // pe_header.filehdr.TimeDateStamp = time(NULL);
+ //pe_header.filehdr.TimeDateStamp = time(NULL);
pe_header.filehdr.NumberOfSections = pe->sec_count;
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase;
if (PE_DLL == pe->type)
- pe_header.filehdr.Characteristics = 0x230E;
+ pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
else if (PE_GUI != pe->type)
pe_header.opthdr.Subsystem = 3;
+ if (pe->subsystem == 9) // WinCE
+ pe_header.opthdr.Subsystem = 9;
- fseek(op, SEEK_SET, 0);
- fwrite(&pe_header, 1, sizeof pe_header, op);
+ sum = 0;
+ pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
for (i = 0; i < pe->sec_count; ++i)
- fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op);
+ pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
+ pe_fpad(op, pe->sizeofheaders);
+ for (i = 0; i < pe->sec_count; ++i) {
+ si = pe->sec_info + i;
+ psh = &si->ish;
+ if (si->data_size) {
+ pe_fwrite(si->data, si->data_size, op, &sum);
+ file_offset = psh->PointerToRawData + psh->SizeOfRawData;
+ pe_fpad(op, file_offset);
+ }
+ }
+
+ pe_header.opthdr.CheckSum = sum + file_offset;
+ fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
+ pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
fclose (op);
if (2 == pe->s1->verbose)
printf("-------------------------------\n");
if (pe->s1->verbose)
- printf("<- %s (%lu bytes)\n", pe->filename, file_offset);
+ printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset);
return 0;
}
/*----------------------------------------------------------------------------*/
-ST_FN struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
+#if defined(TCC_TARGET_X86_64)
+#define ELFW_R_(type) ELF64_R_##type
+#define ElfW_Rel ElfW(Rela)
+
+#define REL_TYPE_DIRECT R_X86_64_64
+#define R_XXX_THUNKFIX R_X86_64_PC32
+#define R_XXX_RELATIVE R_X86_64_RELATIVE
+
+#define ELFW_ST_BIND ELF64_ST_BIND
+#define ELFW_ST_TYPE ELF64_ST_TYPE
+#define ELFW_ST_INFO ELF64_ST_INFO
+#elif defined(TCC_TARGET_I386)
+#define ELFW_R_(type) ELF32_R_##type
+#define ElfW_Rel ElfW(Rel)
+
+#define REL_TYPE_DIRECT R_386_32
+#define R_XXX_THUNKFIX R_386_32
+#define R_XXX_RELATIVE R_386_RELATIVE
+
+#define ELFW_ST_BIND ELF32_ST_BIND
+#define ELFW_ST_TYPE ELF32_ST_TYPE
+#define ELFW_ST_INFO ELF32_ST_INFO
+#elif defined(TCC_TARGET_ARM)
+#define ELFW_R_(type) ELF32_R_##type
+#define ElfW_Rel ElfW(Rel)
+
+#define REL_TYPE_DIRECT R_ARM_ABS32
+#define R_XXX_THUNKFIX R_ARM_ABS32
+#define R_XXX_RELATIVE R_ARM_RELATIVE
+
+#define ELFW_ST_BIND ELF32_ST_BIND
+#define ELFW_ST_TYPE ELF32_ST_TYPE
+#define ELFW_ST_INFO ELF32_ST_INFO
+#endif
+/*----------------------------------------------------------------------------*/
+
+static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
{
int i;
int dll_index;
struct pe_import_info *p;
struct import_symbol *s;
+ ElfW(Sym) *isym;
- dll_index = ((Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index)->st_value;
- if (0 == dll_index)
- return NULL;
+ isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
+ dll_index = isym->st_size;
i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index);
if (-1 != i) {
@@ -704,7 +791,7 @@ found_dll:
}
/*----------------------------------------------------------------------------*/
-ST_FN void pe_build_imports(struct pe_info *pe)
+static void pe_build_imports(struct pe_info *pe)
{
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
@@ -719,34 +806,41 @@ ST_FN void pe_build_imports(struct pe_info *pe)
pe_align_section(pe->thunk, 16);
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(IMAGE_IMPORT_DESCRIPTOR);
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);
thk_ptr = pe->iat_offs;
ent_ptr = pe->iat_offs + pe->iat_size;
for (i = 0; i < pe->imp_count; ++i) {
- struct pe_import_header *hdr;
- int k, n, v;
+ IMAGE_IMPORT_DESCRIPTOR *hdr;
+ int k, n, dllindex;
+ ADDR3264 v;
struct pe_import_info *p = pe->imp_info[i];
- const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name;
+ const char *name;
+ DLLReference *dllref;
+
+ dllindex = p->dll_index;
+ if (dllindex)
+ name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name;
+ else
+ name = "", dllref = NULL;
/* put the dll name into the import header */
v = put_elf_str(pe->thunk, name);
-
- hdr = (struct pe_import_header*)(pe->thunk->data + dll_ptr);
- hdr->first_thunk = thk_ptr + rva_base;
- hdr->first_entry = ent_ptr + rva_base;
- hdr->lib_name_offset = v + rva_base;
+ hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr);
+ hdr->FirstThunk = thk_ptr + rva_base;
+ hdr->OriginalFirstThunk = ent_ptr + rva_base;
+ hdr->Name = v + rva_base;
for (k = 0, n = p->sym_count; k <= n; ++k) {
if (k < n) {
- DWORD iat_index = p->symbols[k]->iat_index;
+ int iat_index = p->symbols[k]->iat_index;
int sym_index = p->symbols[k]->sym_index;
- Elf32_Sym *imp_sym = (Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index;
- Elf32_Sym *org_sym = (Elf32_Sym *)symtab_section->data + iat_index;
+ ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
+ ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index;
const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
org_sym->st_value = thk_ptr;
@@ -754,49 +848,55 @@ ST_FN void pe_build_imports(struct pe_info *pe)
v = pe->thunk->data_offset + rva_base;
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
put_elf_str(pe->thunk, name);
-
+#ifdef TCC_IS_NATIVE
+ if (pe->type == PE_RUN) {
+ v = imp_sym->st_value;
+ if (dllref) {
+ if ( !dllref->handle )
+ dllref->handle = LoadLibrary(dllref->name);
+ v = (ADDR3264)GetProcAddress(dllref->handle, name);
+ }
+ if (!v)
+ error_noabort("undefined symbol '%s'", name);
+ }
+#endif
} else {
v = 0; /* last entry is zero */
}
- *(DWORD*)(pe->thunk->data+thk_ptr) =
- *(DWORD*)(pe->thunk->data+ent_ptr) = v;
- thk_ptr += sizeof (DWORD);
- ent_ptr += sizeof (DWORD);
+ *(ADDR3264*)(pe->thunk->data+thk_ptr) =
+ *(ADDR3264*)(pe->thunk->data+ent_ptr) = v;
+ thk_ptr += sizeof (ADDR3264);
+ ent_ptr += sizeof (ADDR3264);
}
- dll_ptr += sizeof(struct pe_import_header);
+ dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
dynarray_reset(&p->symbols, &p->sym_count);
}
dynarray_reset(&pe->imp_info, &pe->imp_count);
}
/* ------------------------------------------------------------- */
-/*
- For now only functions are exported. Export of data
- would work, but import requires compiler support to
- do an additional indirection.
-
- For instance:
- __declspec(dllimport) extern int something;
-
- needs to be translated to:
- *(int*)something
-*/
+struct pe_sort_sym
+{
+ int index;
+ const char *name;
+};
-ST_FN int sym_cmp(const void *va, const void *vb)
+static int sym_cmp(const void *va, const void *vb)
{
- const char *ca = ((const char **)va)[1];
- const char *cb = ((const char **)vb)[1];
+ const char *ca = (*(struct pe_sort_sym**)va)->name;
+ const char *cb = (*(struct pe_sort_sym**)vb)->name;
return strcmp(ca, cb);
}
-ST_FN void pe_build_exports(struct pe_info *pe)
+static void pe_build_exports(struct pe_info *pe)
{
- Elf32_Sym *sym;
+ ElfW(Sym) *sym;
int sym_index, sym_end;
DWORD rva_base, func_o, name_o, ord_o, str_o;
- struct pe_export_header *hdr;
- int sym_count, n, ord, *sorted, *sp;
+ IMAGE_EXPORT_DIRECTORY *hdr;
+ int sym_count, ord;
+ struct pe_sort_sym **sorted, *p;
FILE *op;
char buf[MAX_PATH];
@@ -804,19 +904,20 @@ ST_FN void pe_build_exports(struct pe_info *pe)
const char *name;
rva_base = pe->thunk->sh_addr - pe->imagebase;
- sym_count = 0, n = 1, sorted = NULL, op = NULL;
+ sym_count = 0, sorted = NULL, op = NULL;
- sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
+ sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- sym = (Elf32_Sym*)symtab_section->data + sym_index;
- name = symtab_section->link->data + sym->st_name;
+ sym = (ElfW(Sym)*)symtab_section->data + sym_index;
+ name = pe_export_name(pe->s1, sym);
if ((sym->st_other & 1)
/* export only symbols from actually written sections */
&& pe->s1->sections[sym->st_shndx]->sh_addr) {
- dynarray_add((void***)&sorted, &sym_count, (void*)n);
- dynarray_add((void***)&sorted, &sym_count, (void*)name);
+ p = tcc_malloc(sizeof *p);
+ p->index = sym_index;
+ p->name = name;
+ dynarray_add((void***)&sorted, &sym_count, p);
}
- ++n;
#if 0
if (sym->st_other & 1)
printf("export: %s\n", name);
@@ -827,14 +928,14 @@ ST_FN void pe_build_exports(struct pe_info *pe)
if (0 == sym_count)
return;
- sym_count /= 2;
- qsort (sorted, sym_count, 2 * sizeof sorted[0], sym_cmp);
+ qsort (sorted, sym_count, sizeof *sorted, sym_cmp);
+
pe_align_section(pe->thunk, 16);
dllname = tcc_basename(pe->filename);
pe->exp_offs = pe->thunk->data_offset;
- func_o = pe->exp_offs + sizeof(struct pe_export_header);
+ func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
name_o = func_o + sym_count * sizeof (DWORD);
ord_o = name_o + sym_count * sizeof (DWORD);
str_o = ord_o + sym_count * sizeof(WORD);
@@ -864,12 +965,12 @@ ST_FN void pe_build_exports(struct pe_info *pe)
}
#endif
- for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2)
+ for (ord = 0; ord < sym_count; ++ord)
{
- sym_index = sp[0], name = (const char *)sp[1];
+ p = sorted[ord], sym_index = p->index, name = p->name;
/* insert actual address later in pe_relocate_rva */
put_elf_reloc(symtab_section, pe->thunk,
- func_o, R_386_RELATIVE, sym_index);
+ func_o, R_XXX_RELATIVE, sym_index);
*(DWORD*)(pe->thunk->data + name_o)
= pe->thunk->data_offset + rva_base;
*(WORD*)(pe->thunk->data + ord_o)
@@ -878,20 +979,21 @@ ST_FN void pe_build_exports(struct pe_info *pe)
func_o += sizeof (DWORD);
name_o += sizeof (DWORD);
ord_o += sizeof (WORD);
-
if (op)
fprintf(op, "%s\n", name);
}
pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
- tcc_free(sorted);
+ dynarray_reset(&sorted, &sym_count);
+ if (op)
+ fclose(op);
}
/* ------------------------------------------------------------- */
-ST_FN void pe_build_reloc (struct pe_info *pe)
+static void pe_build_reloc (struct pe_info *pe)
{
DWORD offset, block_ptr, addr;
int count, i;
- Elf32_Rel *rel, *rel_end;
+ ElfW_Rel *rel, *rel_end;
Section *s = NULL, *sr;
offset = addr = block_ptr = count = i = 0;
@@ -899,10 +1001,10 @@ ST_FN void pe_build_reloc (struct pe_info *pe)
for(;;) {
if (rel < rel_end) {
- int type = ELF32_R_TYPE(rel->r_info);
+ int type = ELFW_R_(TYPE)(rel->r_info);
addr = rel->r_offset + s->sh_addr;
++ rel;
- if (type != R_386_32)
+ if (type != REL_TYPE_DIRECT)
continue;
if (count == 0) { /* new block */
block_ptr = pe->reloc->data_offset;
@@ -920,8 +1022,8 @@ ST_FN void pe_build_reloc (struct pe_info *pe)
} else if (i < pe->sec_count) {
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
if (sr) {
- rel = (Elf32_Rel *)sr->data;
- rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
+ rel = (ElfW_Rel *)sr->data;
+ rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
}
continue;
}
@@ -943,7 +1045,7 @@ ST_FN void pe_build_reloc (struct pe_info *pe)
}
/* ------------------------------------------------------------- */
-ST_FN int pe_section_class(Section *s)
+static int pe_section_class(Section *s)
{
int type, flags;
const char *name;
@@ -961,6 +1063,8 @@ ST_FN int pe_section_class(Section *s)
return sec_rsrc;
if (0 == strcmp(name, ".iedat"))
return sec_idata;
+ if (0 == strcmp(name, ".pdata"))
+ return sec_pdata;
return sec_other;
} else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE)
@@ -975,7 +1079,7 @@ ST_FN int pe_section_class(Section *s)
return -1;
}
-ST_FN int pe_assign_addresses (struct pe_info *pe)
+static int pe_assign_addresses (struct pe_info *pe)
{
int i, k, o, c;
DWORD addr;
@@ -1010,7 +1114,7 @@ ST_FN int pe_assign_addresses (struct pe_info *pe)
#ifdef PE_MERGE_DATA
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
/* append .bss to .data */
- s->sh_addr = addr = ((addr-1) | 15) + 1;
+ s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
addr += s->data_offset;
si[-1].sh_size = addr - si[-1].sh_addr;
continue;
@@ -1019,7 +1123,7 @@ ST_FN int pe_assign_addresses (struct pe_info *pe)
strcpy(si->name, s->name);
si->cls = c;
si->ord = k;
- si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr);
+ si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
si->sh_flags = s->sh_flags;
if (c == sec_data && NULL == pe->thunk)
@@ -1058,7 +1162,7 @@ ST_FN int pe_assign_addresses (struct pe_info *pe)
type == SHT_NOBITS ? "nobits" :
type == SHT_SYMTAB ? "symtab" :
type == SHT_STRTAB ? "strtab" :
- type == SHT_REL ? "rel" : "???",
+ type == SHT_RELX ? "rel" : "???",
s->data_offset,
flags & SHF_ALLOC ? "alloc" : "",
flags & SHF_WRITE ? "write" : "",
@@ -1073,48 +1177,73 @@ ST_FN int pe_assign_addresses (struct pe_info *pe)
}
/* ------------------------------------------------------------- */
-ST_FN void pe_relocate_rva (struct pe_info *pe, Section *s)
+static void pe_relocate_rva (struct pe_info *pe, Section *s)
{
Section *sr = s->reloc;
- Elf32_Rel *rel, *rel_end;
- rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
- for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++)
- if (ELF32_R_TYPE(rel->r_info) == R_386_RELATIVE) {
- int sym_index = ELF32_R_SYM(rel->r_info);
+ ElfW_Rel *rel, *rel_end;
+ rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+ for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
+ if (ELFW_R_(TYPE)(rel->r_info) == R_XXX_RELATIVE) {
+ int sym_index = ELFW_R_(SYM)(rel->r_info);
DWORD addr = s->sh_addr;
if (sym_index) {
- Elf32_Sym *sym = (Elf32_Sym *)symtab_section->data + sym_index;
+ ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
addr = sym->st_value;
}
+ // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
*(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
}
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int pe_isafunc(int sym_index)
+{
+ Section *sr = text_section->reloc;
+ ElfW_Rel *rel, *rel_end;
+ Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32);
+ if (!sr)
+ return 0;
+ rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+ for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++)
+ if (rel->r_info == info)
+ return 1;
+ return 0;
}
/*----------------------------------------------------------------------------*/
-ST_FN int pe_check_symbols(struct pe_info *pe)
+static int pe_check_symbols(struct pe_info *pe)
{
- Elf32_Sym *sym;
+ ElfW(Sym) *sym;
int sym_index, sym_end;
int ret = 0;
pe_align_section(text_section, 8);
- sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
+ sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
- sym = (Elf32_Sym*)symtab_section->data + sym_index;
+ sym = (ElfW(Sym) *)symtab_section->data + sym_index;
if (sym->st_shndx == SHN_UNDEF) {
const char *name = symtab_section->link->data + sym->st_name;
- unsigned type = ELF32_ST_TYPE(sym->st_info);
- int imp_sym = pe_find_import(pe->s1, name);
+ unsigned type = ELFW_ST_TYPE(sym->st_info);
+ int imp_sym = pe_find_import(pe->s1, sym);
struct import_symbol *is;
if (0 == imp_sym)
goto not_found;
+
+ if (type == STT_NOTYPE) {
+ /* symbols from assembler have no type, find out which */
+ if (pe_isafunc(sym_index))
+ type = STT_FUNC;
+ else
+ type = STT_OBJECT;
+ }
+
is = pe_add_import(pe, imp_sym);
- if (!is)
- goto not_found;
if (type == STT_FUNC) {
unsigned long offset = is->thk_offset;
@@ -1123,25 +1252,40 @@ ST_FN int pe_check_symbols(struct pe_info *pe)
} else {
char buffer[100];
+ WORD *p;
offset = text_section->data_offset;
/* add the 'jmp IAT[x]' instruction */
- *(WORD*)section_ptr_add(text_section, 8) = 0x25FF;
-
+#ifdef TCC_TARGET_ARM
+ p = section_ptr_add(text_section, 8+4); // room for code and address
+ (*(DWORD*)(p)) = 0xE59FC000; // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx
+ (*(DWORD*)(p+2)) = 0xE59CF000; // arm code ldr pc, [ip]
+#else
+ p = section_ptr_add(text_section, 8);
+ *p = 0x25FF;
+#ifdef TCC_TARGET_X86_64
+ *(DWORD*)(p+1) = (DWORD)-4;
+#endif
+#endif
/* add a helper symbol, will be patched later in
pe_build_imports */
sprintf(buffer, "IAT.%s", name);
is->iat_index = put_elf_sym(
symtab_section, 0, sizeof(DWORD),
- ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
+ ELFW_ST_INFO(STB_GLOBAL, STT_OBJECT),
0, SHN_UNDEF, buffer);
+#ifdef TCC_TARGET_ARM
+ put_elf_reloc(symtab_section, text_section,
+ offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position
+#else
put_elf_reloc(symtab_section, text_section,
- offset + 2, R_386_32, is->iat_index);
+ offset + 2, R_XXX_THUNKFIX, is->iat_index);
+#endif
is->thk_offset = offset;
}
/* tcc_realloc might have altered sym's address */
- sym = (Elf32_Sym*)symtab_section->data + sym_index;
+ sym = (ElfW(Sym) *)symtab_section->data + sym_index;
/* patch the original symbol */
sym->st_value = offset;
@@ -1160,10 +1304,10 @@ ST_FN int pe_check_symbols(struct pe_info *pe)
not_found:
error_noabort("undefined symbol '%s'", name);
- ret = 1;
+ ret = -1;
} else if (pe->s1->rdynamic
- && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
+ && ELFW_ST_BIND(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
sym->st_other |= 1;
}
@@ -1173,7 +1317,7 @@ ST_FN int pe_check_symbols(struct pe_info *pe)
/*----------------------------------------------------------------------------*/
#ifdef PE_PRINT_SECTIONS
-ST_FN void pe_print_section(FILE * f, Section * s)
+static void pe_print_section(FILE * f, Section * s)
{
/* just if you'r curious */
BYTE *p, *e, b;
@@ -1187,8 +1331,8 @@ ST_FN void pe_print_section(FILE * f, Section * s)
fprintf(f, "\nlink \"%s\"", s->link->name);
if (s->reloc)
fprintf(f, "\nreloc \"%s\"", s->reloc->name);
- fprintf(f, "\nv_addr %08X", s->sh_addr);
- fprintf(f, "\ncontents %08X", l);
+ fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr);
+ fprintf(f, "\ncontents %08X", (unsigned)l);
fprintf(f, "\n\n");
if (s->sh_type == SHT_NOBITS)
@@ -1198,9 +1342,9 @@ ST_FN void pe_print_section(FILE * f, Section * s)
return;
if (s->sh_type == SHT_SYMTAB)
- m = sizeof(Elf32_Sym);
- if (s->sh_type == SHT_REL)
- m = sizeof(Elf32_Rel);
+ m = sizeof(ElfW(Sym));
+ else if (s->sh_type == SHT_RELX)
+ m = sizeof(ElfW_Rel);
else
m = 16;
@@ -1209,7 +1353,7 @@ ST_FN void pe_print_section(FILE * f, Section * s)
fprintf(f, " %02x", i);
n = 56;
- if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_REL) {
+ if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) {
const char *fields1[] = {
"name",
"value",
@@ -1256,25 +1400,28 @@ ST_FN void pe_print_section(FILE * f, Section * s)
}
if (s->sh_type == SHT_SYMTAB) {
- Elf32_Sym *sym = (Elf32_Sym *) (p + i);
+ ElfW(Sym) *sym = (ElfW(Sym) *) (p + i);
const char *name = s->link->data + sym->st_name;
fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"",
- sym->st_name,
- sym->st_value,
- sym->st_size,
- ELF32_ST_BIND(sym->st_info),
- ELF32_ST_TYPE(sym->st_info),
- sym->st_other, sym->st_shndx, name);
-
- } else if (s->sh_type == SHT_REL) {
- Elf32_Rel *rel = (Elf32_Rel *) (p + i);
- Elf32_Sym *sym =
- (Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info);
+ (unsigned)sym->st_name,
+ (unsigned)sym->st_value,
+ (unsigned)sym->st_size,
+ (unsigned)ELFW_ST_BIND(sym->st_info),
+ (unsigned)ELFW_ST_TYPE(sym->st_info),
+ (unsigned)sym->st_other,
+ (unsigned)sym->st_shndx,
+ name);
+
+ } else if (s->sh_type == SHT_RELX) {
+ ElfW_Rel *rel = (ElfW_Rel *) (p + i);
+ ElfW(Sym) *sym =
+ (ElfW(Sym) *) s->link->data + ELFW_R_(SYM)(rel->r_info);
const char *name = s->link->link->data + sym->st_name;
fprintf(f, " %04X %02X %04X \"%s\"",
- rel->r_offset,
- ELF32_R_TYPE(rel->r_info),
- ELF32_R_SYM(rel->r_info), name);
+ (unsigned)rel->r_offset,
+ (unsigned)ELFW_R_(TYPE)(rel->r_info),
+ (unsigned)ELFW_R_(SYM)(rel->r_info),
+ name);
} else {
fprintf(f, " ");
for (n = 0; n < m; ++n) {
@@ -1292,12 +1439,12 @@ ST_FN void pe_print_section(FILE * f, Section * s)
fprintf(f, "\n\n");
}
-ST_FN void pe_print_sections(TCCState *s1, const char *fname)
+static void pe_print_sections(TCCState *s1, const char *fname)
{
Section *s;
FILE *f;
int i;
- f = fopen(fname, "wt");
+ f = fopen(fname, "w");
for (i = 1; i < s1->nb_sections; ++i) {
s = s1->sections[i];
pe_print_section(f, s);
@@ -1307,74 +1454,136 @@ ST_FN void pe_print_sections(TCCState *s1, const char *fname)
}
#endif
-/* -------------------------------------------------------------
- * This is for compiled windows resources in 'coff' format
- * as generated by 'windres.exe -O coff ...'.
- */
+/* ------------------------------------------------------------- */
+/* helper function for load/store to insert one more indirection */
-PUB_FN int pe_test_res_file(void *v, int size)
+ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
{
- struct pe_rsrc_header *p = (struct pe_rsrc_header *)v;
- return
- size >= IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_SHORT_NAME /* = 28 */
- && p->filehdr.Machine == 0x014C
- && 1 == p->filehdr.NumberOfSections
- && 0 == strcmp(p->sectionhdr.Name, ".rsrc")
- ;
+ Sym *sym;
+ ElfW(Sym) *esym;
+ int r2;
+
+ if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
+ return sv;
+ sym = sv->sym;
+ if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN)
+ return sv;
+ if (!sym->c)
+ put_extern_sym(sym, NULL, 0, 0);
+ esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+ if (!(esym->st_other & 4))
+ return sv;
+
+ // printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
+
+ memset(v2, 0, sizeof *v2);
+ v2->type.t = VT_PTR;
+ v2->r = VT_CONST | VT_SYM | VT_LVAL;
+ v2->sym = sv->sym;
+
+ r2 = get_reg(RC_INT);
+ load(r2, v2);
+ v2->r = r2;
+
+ if (sv->c.ui) {
+ vpushv(v2);
+ vpushi(sv->c.ui);
+ gen_opi('+');
+ *v2 = *vtop--;
+ }
+
+ v2->type.t = sv->type.t;
+ v2->r |= sv->r & VT_LVAL;
+ return v2;
}
-ST_FN int read_n(int fd, void *ptr, unsigned size)
+ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, const void *value)
{
- return size == read(fd, ptr, size);
+ return add_elf_sym(
+ s1->dynsymtab_section,
+ (uplong)value,
+ dllindex, /* st_size */
+ ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+ 0,
+ value ? SHN_ABS : SHN_UNDEF,
+ name
+ );
}
-PUB_FN int pe_load_res_file(TCCState *s1, int fd)
+static int add_dllref(TCCState *s1, const char *dllname)
+{
+ DLLReference *dllref;
+ int i;
+ for (i = 0; i < s1->nb_loaded_dlls; ++i)
+ if (0 == strcmp(s1->loaded_dlls[i]->name, dllname))
+ return i + 1;
+ dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
+ strcpy(dllref->name, dllname);
+ dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+ return s1->nb_loaded_dlls;
+}
+
+/* ------------------------------------------------------------- */
+
+static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
+{
+ fseek(fp, offset, 0);
+ return len == fread(buffer, 1, len, fp);
+}
+
+/* -------------------------------------------------------------
+ * This is for compiled windows resources in 'coff' format
+ * as generated by 'windres.exe -O coff ...'.
+ */
+
+static int pe_load_res(TCCState *s1, FILE *fp)
{
struct pe_rsrc_header hdr;
Section *rsrc_section;
int i, ret = -1;
BYTE *ptr;
+ unsigned offs;
- lseek (fd, 0, SEEK_SET);
- if (!read_n(fd, &hdr, sizeof hdr))
+ if (!read_mem(fp, 0, &hdr, sizeof hdr))
goto quit;
- if (!pe_test_res_file(&hdr, sizeof hdr))
+
+ if (hdr.filehdr.Machine != 0x014C
+ || hdr.filehdr.NumberOfSections != 1
+ || strcmp(hdr.sectionhdr.Name, ".rsrc") != 0)
goto quit;
rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
- lseek (fd, hdr.sectionhdr.PointerToRawData, SEEK_SET);
- if (!read_n(fd, ptr, hdr.sectionhdr.SizeOfRawData))
+ offs = hdr.sectionhdr.PointerToRawData;
+ if (!read_mem(fp, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit;
-
- lseek (fd, hdr.sectionhdr.PointerToRelocations, SEEK_SET);
+ offs = hdr.sectionhdr.PointerToRelocations;
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
{
struct pe_rsrc_reloc rel;
- if (!read_n(fd, &rel, sizeof rel))
+ if (!read_mem(fp, offs, &rel, sizeof rel))
goto quit;
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
if (rel.type != 7) /* DIR32NB */
goto quit;
put_elf_reloc(symtab_section, rsrc_section,
- rel.offset, R_386_RELATIVE, 0);
+ rel.offset, R_XXX_RELATIVE, 0);
+ offs += sizeof rel;
}
ret = 0;
quit:
- if (ret)
- error_noabort("unrecognized resource file format");
return ret;
}
/* ------------------------------------------------------------- */
-ST_FN char *trimfront(char *p)
+static char *trimfront(char *p)
{
while (*p && (unsigned char)*p <= ' ')
++p;
return p;
}
-ST_FN char *trimback(char *a, char *e)
+static char *trimback(char *a, char *e)
{
while (e > a && (unsigned char)e[-1] <= ' ')
--e;
@@ -1382,7 +1591,7 @@ ST_FN char *trimback(char *a, char *e)
return a;
}
-ST_FN char *get_line(char *line, int size, FILE *fp)
+static char *get_line(char *line, int size, FILE *fp)
{
if (NULL == fgets(line, size, fp))
return NULL;
@@ -1391,15 +1600,10 @@ ST_FN char *get_line(char *line, int size, FILE *fp)
}
/* ------------------------------------------------------------- */
-PUB_FN int pe_load_def_file(TCCState *s1, int fd)
+static int pe_load_def(TCCState *s1, FILE *fp)
{
- DLLReference *dllref;
- int state = 0, ret = -1;
+ int state = 0, ret = -1, dllindex = 0;
char line[400], dllname[80], *p;
- FILE *fp = fdopen(dup(fd), "rb");
-
- if (NULL == fp)
- goto quit;
for (;;) {
p = get_line(line, sizeof line, fp);
@@ -1422,37 +1626,134 @@ PUB_FN int pe_load_def_file(TCCState *s1, int fd)
continue;
case 2:
- dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
- strcpy(dllref->name, dllname);
- dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+ dllindex = add_dllref(s1, dllname);
++state;
default:
- add_elf_sym(s1->dynsymtab_section,
- s1->nb_loaded_dlls, 0,
- ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 0,
- text_section->sh_num, p);
+ pe_putimport(s1, dllindex, p, NULL);
continue;
}
}
ret = 0;
quit:
- if (fp)
+ return ret;
+}
+
+/* ------------------------------------------------------------- */
+#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
+#include "win32/tools/tiny_impdef.c"
+
+static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp)
+{
+ char *p, *q;
+ int index;
+ p = get_export_names(fp);
+ if (!p)
+ return -1;
+ index = add_dllref(s1, dllname);
+ for (q = p; *q; q += 1 + strlen(q))
+ pe_putimport(s1, index, q, NULL);
+ tcc_free(p);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
+{
+ FILE *fp = fdopen(dup(fd), "rb");
+ int ret = -1;
+ char buf[10];
+ if (fp) {
+ if (0 == strcmp(tcc_fileextension(filename), ".def"))
+ ret = pe_load_def(s1, fp);
+ else if (pe_load_res(s1, fp) == 0)
+ ret = 0;
+ else if (read_mem(fp, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
+ ret = pe_load_dll(s1, tcc_basename(filename), fp);
fclose(fp);
- if (ret)
- error_noabort("unrecognized export definition file format");
+ }
return ret;
}
+ST_FUNC int pe_add_dll(struct TCCState *s, const char *libname)
+{
+ static const char *pat[] = {
+ "%s.def", "lib%s.def", "%s.dll", "lib%s.dll", NULL
+ };
+ const char **p = pat;
+ do {
+ char buf[MAX_PATH];
+ snprintf(buf, sizeof(buf), *p, libname);
+ if (tcc_add_dll(s, buf, 0) == 0)
+ return 0;
+ } while (*++p);
+ return -1;
+}
+
+/* ------------------------------------------------------------- */
+#ifdef TCC_TARGET_X86_64
+ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
+{
+ static const char uw_info[] = {
+ 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
+ 0x04, // UBYTE Size of prolog
+ 0x02, // UBYTE Count of unwind codes
+ 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled)
+ // USHORT * n Unwind codes array
+ // 0x0b, 0x01, 0xff, 0xff, // stack size
+ 0x04, 0x03, // set frame ptr (mov rsp -> rbp)
+ 0x01, 0x50 // push reg (rbp)
+ };
+
+ struct pe_uw *pe_uw = &tcc_state->pe_unwind;
+
+ Section *uw, *pd;
+ WORD *p1;
+ DWORD *p2;
+ unsigned o2;
+
+ uw = data_section;
+ pd = pe_uw->pdata;
+ if (NULL == pd)
+ {
+ pe_uw->pdata = pd = find_section(tcc_state, ".pdata");
+ pe_uw->pdata->sh_addralign = 4;
+ section_ptr_add(uw, -uw->data_offset & 3);
+ pe_uw->offs_1 = uw->data_offset;
+ p1 = section_ptr_add(uw, sizeof uw_info);
+ /* use one common entry for all functions */
+ memcpy(p1, uw_info, sizeof uw_info);
+ pe_uw->sym_1 = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
+ pe_uw->sym_2 = put_elf_sym(symtab_section, 0, 0, 0, 0, uw->sh_num, NULL);
+ }
+
+ o2 = pd->data_offset;
+ p2 = section_ptr_add(pd, 3 * sizeof (DWORD));
+ /* record this function */
+ p2[0] = start;
+ p2[1] = end;
+ p2[2] = pe_uw->offs_1;
+ /* put relocations on it */
+ put_elf_reloc(symtab_section, pd, o2, R_X86_64_RELATIVE, pe_uw->sym_1);
+ put_elf_reloc(symtab_section, pd, o2+4, R_X86_64_RELATIVE, pe_uw->sym_1);
+ put_elf_reloc(symtab_section, pd, o2+8, R_X86_64_RELATIVE, pe_uw->sym_2);
+}
+#endif
+
/* ------------------------------------------------------------- */
+#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)
+static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
unsigned long addr = 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;
else
if (TCC_OUTPUT_DLL == s1->output_type) {
@@ -1460,57 +1761,61 @@ ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
/* need this for 'tccelf.c:relocate_section()' */
s1->output_type = TCC_OUTPUT_EXE;
}
+ else
+ pe_type = PE_EXE;
start_symbol =
TCC_OUTPUT_MEMORY == s1->output_type
- ? PE_GUI == pe_type ? "_runwinmain" : NULL
- : PE_DLL == pe_type ? "__dllstart@12"
- : PE_GUI == pe_type ? "_winstart" : "_start"
+ ? PE_GUI == pe_type ? "__runwinmain" : "_main"
+ : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
+ : PE_GUI == pe_type ? "__winstart" : "__start"
;
+ if (!s1->leading_underscore || strchr(start_symbol, '@')) {
+ ++start_symbol;
+ if (start_symbol[0] != '_')
+ start_symbol = NULL;
+ }
+
/* grab the startup code from libtcc1 */
if (start_symbol)
add_elf_sym(symtab_section,
0, 0,
- ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
+ ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
if (0 == s1->nostdlib) {
- tcc_add_library(s1, "tcc1");
-#ifdef __CYGWIN__
- tcc_add_library(s1, "cygwin1");
-#else
- tcc_add_library(s1, "msvcrt");
-#endif
- tcc_add_library(s1, "kernel32");
- if (PE_DLL == pe_type || PE_GUI == pe_type) {
- tcc_add_library(s1, "user32");
- tcc_add_library(s1, "gdi32");
+ static const char *libs[] = {
+ "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
+ };
+ const char **pp, *p;
+ for (pp = libs; 0 != (p = *pp); ++pp) {
+ if (0 == *p) {
+ if (PE_DLL != pe_type && PE_GUI != pe_type)
+ break;
+ } else if (tcc_add_library(s1, p) < 0)
+ error_noabort("cannot find library: %s", p);
}
}
+ if (TCC_OUTPUT_MEMORY == s1->output_type)
+ pe_type = PE_RUN;
+
if (start_symbol) {
- addr = (unsigned long)tcc_get_symbol_err(s1, start_symbol);
- if (s1->output_type == TCC_OUTPUT_MEMORY && addr)
+ addr = (uplong)tcc_get_symbol_err(s1, start_symbol);
+ if (PE_RUN == pe_type && addr)
/* for -run GUI's, put '_runwinmain' instead of 'main' */
add_elf_sym(symtab_section,
addr, 0,
- ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
+ ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
text_section->sh_num, "main");
}
- if (pe) {
- pe->type = pe_type;
- pe->start_addr = addr;
- }
-}
-
-PUB_FN void pe_add_runtime(TCCState *s1)
-{
- pe_add_runtime_ex(s1, NULL);
+ pe->type = pe_type;
+ pe->start_addr = addr;
}
-PUB_FN int pe_output_file(TCCState * s1, const char *filename)
+ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
{
int ret;
struct pe_info pe;
@@ -1520,18 +1825,56 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
+ tcc_add_bcheck(s1);
pe_add_runtime_ex(s1, &pe);
relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1);
ret = pe_check_symbols(&pe);
- if (0 == ret) {
+ if (ret)
+ ;
+ else if (filename) {
if (PE_DLL == pe.type) {
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
+ /* XXX: check if is correct for arm-pe target */
pe.imagebase = 0x10000000;
} else {
+#if defined(TCC_TARGET_ARM)
+ pe.imagebase = 0x00010000;
+#else
pe.imagebase = 0x00400000;
+#endif
}
+
+ /* if no subsystem specified, we use "console" subsystem by default */
+ if (s1->pe_subsystem != 0)
+ pe.subsystem = s1->pe_subsystem;
+ else
+#if defined(TCC_TARGET_ARM)
+ pe.subsystem = 9;
+#else
+ pe.subsystem = 3;
+#endif
+ /* set default file/section alignment */
+ if (pe.subsystem == 1) {
+ pe.section_align = 0x20;
+ pe.file_align = 0x20;
+ } else {
+ pe.section_align = 0x1000;
+ pe.file_align = 0x200;
+ }
+
+ if (s1->section_align != 0)
+ pe.section_align = s1->section_align;
+ if (s1->pe_file_align != 0)
+ pe.file_align = s1->pe_file_align;
+
+ if ((pe.subsystem >= 10) && (pe.subsystem <= 12))
+ pe.imagebase = 0;
+
+ if (s1->has_text_addr)
+ pe.imagebase = s1->text_addr;
+
pe_assign_addresses(&pe);
relocate_syms(s1, 0);
for (i = 1; i < s1->nb_sections; ++i) {
@@ -1542,10 +1885,16 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename)
}
}
if (s1->nb_errors)
- ret = 1;
+ ret = -1;
else
ret = pe_write(&pe);
tcc_free(pe.sec_info);
+ } else {
+#ifndef TCC_IS_NATIVE
+ error_noabort("-run supported only on native platform");
+#endif
+ pe.thunk = data_section;
+ pe_build_imports(&pe);
}
#ifdef PE_PRINT_SECTIONS
@@ -1555,5 +1904,3 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename)
}
/* ------------------------------------------------------------- */
-#endif /* def TCC_TARGET_PE */
-/* ------------------------------------------------------------- */