changeset 350:4ebba89e2599

[project @ 2005-04-10 21:46:58 by bellard] initial PE format support
author bellard
date Sun, 10 Apr 2005 21:46:58 +0000
parents b6b265068016
children e2578fa968b7
files Makefile tcc.c tccelf.c tccpe.c tcctok.h
diffstat 5 files changed, 1314 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sun Apr 10 21:43:10 2005 +0000
+++ b/Makefile	Sun Apr 10 21:46:58 2005 +0000
@@ -20,7 +20,7 @@
 
 DISAS=objdump -d
 INSTALL=install
-PROGS=tcc$(EXESUF) c67-tcc$(EXESUF) arm-tcc$(EXESUF)
+PROGS=tcc$(EXESUF) c67-tcc$(EXESUF) arm-tcc$(EXESUF) i386-win32-tcc$(EXESUF)
 # run local version of tcc with local libraries and includes
 TCC=./tcc -B. -I.
 
@@ -125,6 +125,9 @@
 arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h Makefile
 	$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
 
+i386-win32-tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h tccpe.c Makefile
+	$(CC) $(CFLAGS) -DTCC_TARGET_PE -o $@ $< $(LIBS)
+
 # TinyCC runtime libraries
 libtcc1.o: libtcc1.c
 	$(CC) -O2 -Wall -c -o $@ $<
--- a/tcc.c	Sun Apr 10 21:43:10 2005 +0000
+++ b/tcc.c	Sun Apr 10 21:46:58 2005 +0000
@@ -35,13 +35,11 @@
 #include <math.h>
 #include <unistd.h>
 #include <signal.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include <setjmp.h>
 #include <time.h>
 #ifdef WIN32
 #include <sys/timeb.h>
-#define CONFIG_TCC_STATIC
 #endif
 #ifndef WIN32
 #include <sys/time.h>
@@ -52,9 +50,7 @@
 
 #include "elf.h"
 #include "stab.h"
-#ifndef CONFIG_TCC_STATIC
-#include <dlfcn.h>
-#endif
+
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
@@ -218,6 +214,7 @@
     int packed; 
     Section *section;
     unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */
+    unsigned char dllexport; 
 } AttributeDef;
 
 #define SYM_STRUCT     0x40000000 /* struct/union/enum symbol space */
@@ -719,6 +716,7 @@
 
 static char *pstrcpy(char *buf, int buf_size, const char *s);
 static char *pstrcat(char *buf, int buf_size, const char *s);
+static const char *tcc_basename(const char *name);
 
 static void next(void);
 static void next_nomacro(void);
@@ -809,6 +807,13 @@
 /* tcccoff.c */
 int tcc_output_coff(TCCState *s1, FILE *f);
 
+/* tccpe.c */
+void *resolve_sym(TCCState *s1, const char *sym, int type);
+int pe_load_def_file(struct TCCState *s1, FILE *fp);
+void pe_setup_paths(struct TCCState *s1, int *p_output_type, const char **p_outfile, char *first_file);
+unsigned long pe_add_runtime(struct TCCState *s1);
+int tcc_output_pe(struct TCCState *s1, const char *filename);
+
 /* tccasm.c */
 
 #ifdef CONFIG_TCC_ASM
@@ -902,7 +907,7 @@
     { NULL, NULL },
 };
 
-void *dlsym(void *handle, const char *symbol)
+void *resolve_sym(TCCState *s1, const char *symbol, int type)
 {
     TCCSyms *p;
     p = tcc_syms;
@@ -914,6 +919,15 @@
     return NULL;
 }
 
+#elif !defined(WIN32)
+
+#include <dlfcn.h>
+
+void *resolve_sym(TCCState *s1, const char *sym, int type)
+{
+    return dlsym(RTLD_DEFAULT, sym);
+}
+
 #endif
 
 /********************************************************/
@@ -6290,6 +6304,9 @@
             skip(')');
             break;
 #endif
+        case TOK_DLLEXPORT:
+            ad->dllexport = 1;
+            break;
         default:
             if (tcc_state->warn_unsupported)
                 warning("'%s' attribute ignored", get_tok_str(t, NULL));
@@ -9195,6 +9212,10 @@
 #include "tcccoff.c"
 #endif
 
+#ifdef TCC_TARGET_PE
+#include "tccpe.c"
+#endif
+
 /* print the position in the source file of PC value 'pc' by reading
    the stabs debug information */
 static void rt_printline(unsigned long wanted_pc)
@@ -9442,7 +9463,11 @@
 
     s1->nb_errors = 0;
     
+#ifdef TCC_TARGET_PE
+    pe_add_runtime(s1);
+#else
     tcc_add_runtime(s1);
+#endif
 
     relocate_common_syms();
 
@@ -9588,9 +9613,17 @@
     tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
     
     /* default library paths */
+#ifdef TCC_TARGET_PE
+    {
+        char buf[1024];
+        snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path);
+        tcc_add_library_path(s, buf);
+    }
+#else
     tcc_add_library_path(s, "/usr/local/lib");
     tcc_add_library_path(s, "/usr/lib");
     tcc_add_library_path(s, "/lib");
+#endif
 
     /* no section zero */
     dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
@@ -9728,6 +9761,11 @@
         ret = tcc_assemble(s1, 0);
     } else 
 #endif
+#ifdef TCC_TARGET_PE
+    if (!strcmp(ext, "def")) {
+        ret = pe_load_def_file(s1, fdopen(file->fd, "rb"));
+    } else
+#endif
     {
         fd = file->fd;
         /* assume executable format: auto guess file type */
@@ -9749,12 +9787,16 @@
                 ret = tcc_load_object_file(s1, fd, 0);
             } else if (ehdr.e_type == ET_DYN) {
                 if (s1->output_type == TCC_OUTPUT_MEMORY) {
+#ifdef TCC_TARGET_PE
+                    ret = -1;
+#else
                     void *h;
                     h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
                     if (h)
                         ret = 0;
                     else
                         ret = -1;
+#endif
                 } else {
                     ret = tcc_load_dll(s1, fd, filename, 
                                        (flags & AFF_REFERENCED_DLL) != 0);
@@ -9830,7 +9872,11 @@
     
     /* first we look for the dynamic library if not static linking */
     if (!s->static_link) {
+#ifdef TCC_TARGET_PE
+        snprintf(buf, sizeof(buf), "%s.def", libraryname);
+#else
         snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
+#endif
         if (tcc_add_dll(s, buf, 0) == 0)
             return 0;
     }
@@ -9855,17 +9901,23 @@
 
 int tcc_set_output_type(TCCState *s, int output_type)
 {
-    char buf[1024];
-
     s->output_type = output_type;
 
     if (!s->nostdinc) {
+        char buf[1024];
+
         /* default include paths */
         /* XXX: reverse order needed if -isystem support */
+#ifndef TCC_TARGET_PE
         tcc_add_sysinclude_path(s, "/usr/local/include");
         tcc_add_sysinclude_path(s, "/usr/include");
+#endif
         snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path);
         tcc_add_sysinclude_path(s, buf);
+#ifdef TCC_TARGET_PE
+        snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path);
+        tcc_add_sysinclude_path(s, buf);
+#endif
     }
 
     /* if bound checking, then add corresponding sections */
@@ -9898,12 +9950,14 @@
     }
 
     /* add libc crt1/crti objects */
+#ifndef TCC_TARGET_PE
     if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
         !s->nostdlib) {
         if (output_type != TCC_OUTPUT_DLL)
             tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
         tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
     }
+#endif
     return 0;
 }
 
@@ -10013,7 +10067,7 @@
 
 void help(void)
 {
-    printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2004 Fabrice Bellard\n"
+    printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n"
            "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
            "           [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n"
            "           [infile1 infile2...] [-run infile args...]\n"
@@ -10370,6 +10424,22 @@
     char objfilename[1024];
     int64_t start_time = 0;
 
+#ifdef WIN32
+    /* on win32, we suppose the lib and includes are at the location
+       of 'tcc.exe' */
+    {
+        static char path[1024];
+
+        GetModuleFileNameA(NULL, path, sizeof path);
+        p = d = strlwr(path);
+        while (*d)
+            if (*d++ == '\\')
+                (p = d)[-1] = '/';
+        *p = '\0';
+        tcc_lib_path = path;
+    }
+#endif
+
     s = tcc_new();
     output_type = TCC_OUTPUT_EXE;
     outfile = NULL;
@@ -10461,11 +10531,17 @@
                total_bytes / total_time / 1000000.0); 
     }
 
-    if (s->output_type != TCC_OUTPUT_MEMORY) {
+    if (s->output_type == TCC_OUTPUT_MEMORY) {
+        ret = tcc_run(s, argc - optind, argv + optind);
+    } else
+#ifdef TCC_TARGET_PE
+    if (s->output_type != TCC_OUTPUT_OBJ) {
+        ret = tcc_output_pe(s, outfile);
+    } else
+#endif
+    {
         tcc_output_file(s, outfile);
         ret = 0;
-    } else {
-        ret = tcc_run(s, argc - optind, argv + optind);
     }
  the_end:
     /* XXX: cannot do it with bound checking because of the malloc hooks */
--- a/tccelf.c	Sun Apr 10 21:43:10 2005 +0000
+++ b/tccelf.c	Sun Apr 10 21:46:58 2005 +0000
@@ -385,11 +385,6 @@
     }
 }
 
-static void *resolve_sym(const char *sym)
-{
-    return dlsym(RTLD_DEFAULT, sym);
-}
-
 /* relocate symbol table, resolve undefined symbols if do_resolve is
    true and output error if undefined symbol. */
 static void relocate_syms(TCCState *s1, int do_resolve)
@@ -408,7 +403,7 @@
             name = strtab_section->data + sym->st_name;
             if (do_resolve) {
                 name = symtab_section->link->data + sym->st_name;
-                addr = (unsigned long)resolve_sym(name);
+                addr = (unsigned long)resolve_sym(s1, name, ELF32_ST_TYPE(sym->st_info));
                 if (addr) {
                     sym->st_value = addr;
                     goto found;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tccpe.c	Sun Apr 10 21:46:58 2005 +0000
@@ -0,0 +1,1220 @@
+/*
+ *  TCCPE.C - PE file output for the TinyC Compiler
+ * 
+ *  Copyright (c) 2005 grischka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+#define ST static
+
+/* XXX: move that to TCC ? */
+int verbose = 0;
+
+/* definitions below are from winnt.h */
+
+typedef struct _IMAGE_DOS_HEADER {	/* DOS .EXE header */
+    WORD e_magic;		/* Magic number */
+    WORD e_cblp;		/* Bytes on last page of file */
+    WORD e_cp;			/* Pages in file */
+    WORD e_crlc;		/* Relocations */
+    WORD e_cparhdr;		/* Size of header in paragraphs */
+    WORD e_minalloc;		/* Minimum extra paragraphs needed */
+    WORD e_maxalloc;		/* Maximum extra paragraphs needed */
+    WORD e_ss;			/* Initial (relative) SS value */
+    WORD e_sp;			/* Initial SP value */
+    WORD e_csum;		/* Checksum */
+    WORD e_ip;			/* Initial IP value */
+    WORD e_cs;			/* Initial (relative) CS value */
+    WORD e_lfarlc;		/* File address of relocation table */
+    WORD e_ovno;		/* Overlay number */
+    WORD e_res[4];		/* Reserved words */
+    WORD e_oemid;		/* OEM identifier (for e_oeminfo) */
+    WORD e_oeminfo;		/* OEM information; e_oemid specific */
+    WORD e_res2[10];		/* Reserved words */
+    DWORD e_lfanew;		/* File address of new exe header */
+    BYTE e_code[0x40];
+
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_NT_SIGNATURE  0x00004550	/* PE00 */
+#define SIZE_OF_NT_SIGNATURE 4
+
+typedef struct _IMAGE_FILE_HEADER {
+    WORD Machine;
+    WORD NumberOfSections;
+    DWORD TimeDateStamp;
+    DWORD PointerToSymbolTable;
+    DWORD NumberOfSymbols;
+    WORD SizeOfOptionalHeader;
+    WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+
+#define IMAGE_SIZEOF_FILE_HEADER 20
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+    DWORD VirtualAddress;
+    DWORD Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+    /* Standard fields. */
+    WORD Magic;
+    BYTE MajorLinkerVersion;
+    BYTE MinorLinkerVersion;
+    DWORD SizeOfCode;
+    DWORD SizeOfInitializedData;
+    DWORD SizeOfUninitializedData;
+    DWORD AddressOfEntryPoint;
+    DWORD BaseOfCode;
+    DWORD BaseOfData;
+
+    /* NT additional fields. */
+    DWORD ImageBase;
+    DWORD SectionAlignment;
+    DWORD FileAlignment;
+    WORD MajorOperatingSystemVersion;
+    WORD MinorOperatingSystemVersion;
+    WORD MajorImageVersion;
+    WORD MinorImageVersion;
+    WORD MajorSubsystemVersion;
+    WORD MinorSubsystemVersion;
+    DWORD Win32VersionValue;
+    DWORD SizeOfImage;
+    DWORD SizeOfHeaders;
+    DWORD CheckSum;
+    WORD Subsystem;
+    WORD DllCharacteristics;
+    DWORD SizeOfStackReserve;
+    DWORD SizeOfStackCommit;
+    DWORD SizeOfHeapReserve;
+    DWORD SizeOfHeapCommit;
+    DWORD LoaderFlags;
+    DWORD NumberOfRvaAndSizes;
+    IMAGE_DATA_DIRECTORY DataDirectory[16];
+
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+
+#define IMAGE_DIRECTORY_ENTRY_EXPORT          0	/* Export Directory */
+#define IMAGE_DIRECTORY_ENTRY_IMPORT          1	/* Import Directory */
+#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2	/* Resource Directory */
+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3	/* Exception Directory */
+#define IMAGE_DIRECTORY_ENTRY_SECURITY        4	/* Security Directory */
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5	/* Base Relocation Table */
+#define IMAGE_DIRECTORY_ENTRY_DEBUG           6	/* Debug Directory */
+/*      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7      (X86 usage) */
+#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7	/* Architecture Specific Data */
+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8	/* RVA of GP */
+#define IMAGE_DIRECTORY_ENTRY_TLS             9	/* TLS Directory */
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10	/* Load Configuration Directory */
+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11	/* Bound Import Directory in headers */
+#define IMAGE_DIRECTORY_ENTRY_IAT            12	/* Import Address Table */
+#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13	/* Delay Load Import Descriptors */
+#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14	/* COM Runtime descriptor */
+
+/* Section header format. */
+#define IMAGE_SIZEOF_SHORT_NAME              8
+
+typedef struct _IMAGE_SECTION_HEADER {
+    BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+    union {
+	DWORD PhysicalAddress;
+	DWORD VirtualSize;
+    } Misc;
+    DWORD VirtualAddress;
+    DWORD SizeOfRawData;
+    DWORD PointerToRawData;
+    DWORD PointerToRelocations;
+    DWORD PointerToLinenumbers;
+    WORD NumberOfRelocations;
+    WORD NumberOfLinenumbers;
+    DWORD Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_SIZEOF_SECTION_HEADER          40
+
+/* ----------------------------------------------------------- */
+typedef struct _IMAGE_BASE_RELOCATION {
+    DWORD VirtualAddress;
+    DWORD SizeOfBlock;
+//  WORD    TypeOffset[1];
+} IMAGE_BASE_RELOCATION;
+
+#define IMAGE_SIZEOF_BASE_RELOCATION         8
+
+#define IMAGE_REL_BASED_ABSOLUTE              0
+#define IMAGE_REL_BASED_HIGH                  1
+#define IMAGE_REL_BASED_LOW                   2
+#define IMAGE_REL_BASED_HIGHLOW               3
+#define IMAGE_REL_BASED_HIGHADJ               4
+#define IMAGE_REL_BASED_MIPS_JMPADDR          5
+#define IMAGE_REL_BASED_SECTION               6
+#define IMAGE_REL_BASED_REL32                 7
+
+/* ----------------------------------------------------------- */
+
+/* ----------------------------------------------------------- */
+IMAGE_DOS_HEADER pe_dos_hdr = {
+    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 */
+    {				/* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
+     /*0040 */ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8,
+     0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
+     /*0050 */ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d,
+     0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
+     /*0060 */ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69,
+     0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+     /*0070 */ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     /*0080 */
+     }
+};
+
+DWORD pe_magic = IMAGE_NT_SIGNATURE;
+
+IMAGE_FILE_HEADER pe_file_hdr = {
+    0x014C,			/*WORD    Machine; */
+    0x0003,			/*WORD    NumberOfSections; */
+    0x00000000,			/*DWORD   TimeDateStamp; */
+    0x00000000,			/*DWORD   PointerToSymbolTable; */
+    0x00000000,			/*DWORD   NumberOfSymbols; */
+    0x00E0,			/*WORD    SizeOfOptionalHeader; */
+    0x030F			/*WORD    Characteristics; */
+};
+
+IMAGE_OPTIONAL_HEADER32 pe_opt_hdr = {
+    /* 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}}
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+
+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;
+};
+
+struct pe_reloc_header {
+    DWORD offset;
+    DWORD size;
+};
+
+/* ------------------------------------------------------------- */
+/* internal temporary structures */
+
+ST const char *pe_sec_names[] = {
+    ".text",
+    ".data",
+    ".bss",
+    ".rsrc",
+    ".reloc",
+    ".stab",
+    ".stabstr"
+};
+
+enum {
+    sec_text = 0,
+    sec_data,
+    sec_bss,
+    sec_rsrc,
+    sec_reloc,
+    sec_stab,
+    sec_stabstr,
+    pe_sec_number
+};
+
+ST DWORD pe_flags[] = {
+    0x60000020,			/* ".text", */
+    0xC0000040,			/* ".data", */
+    0xC0000080,			/* ".bss", */
+    0x40000040,			/* ".rsrc", */
+    0x42000040,			/* ".reloc", */
+    0x42000802,			/* ".stab", */
+    0x42000802			/* ".stabstr", */
+};
+
+struct section_info {
+    struct section_info *next;
+    int id;
+    DWORD sh_addr;
+    DWORD sh_size;
+    unsigned char *data;
+    DWORD data_size;
+};
+
+struct import_symbol {
+    int sym_index;
+    int offset;
+};
+
+struct pe_import_info {
+    int dll_index;
+    int sym_count;
+    struct import_symbol **symbols;
+};
+
+struct pe_info {
+    const char *filename;
+    DWORD sizeofheaders;
+    DWORD imagebase;
+    DWORD start_addr;
+    DWORD imp_offs;
+    DWORD imp_size;
+    DWORD iat_offs;
+    DWORD iat_size;
+    DWORD exp_offs;
+    DWORD exp_size;
+    struct section_info sh_info[pe_sec_number];
+    int sec_count;
+    struct pe_import_info **imp_info;
+    int imp_count;
+    Section *reloc;
+    Section *thunk;
+    TCCState *s1;
+};
+
+/* ------------------------------------------------------------- */
+#define PE_MERGE_DATA
+// #define PE_PRINT_SECTIONS
+
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+
+void error_noabort(const char *, ...);
+
+ST char pe_type;
+
+#define PE_NUL 0
+#define PE_DLL 1
+#define PE_GUI 2
+#define PE_EXE 3
+
+#ifdef WIN32
+int __stdcall GetModuleFileNameA(void *, char *, int);
+void *__stdcall GetProcAddress(void *, const char *);
+void *__stdcall GetModuleHandleA(const char *);
+void *__stdcall LoadLibraryA(const char *);
+int __stdcall FreeConsole(void);
+#endif
+
+ST int pe_find_import(TCCState * s1, const char *symbol, char *ret)
+{
+    int sym_index = find_elf_sym(s1->dynsymtab_section, symbol);
+    if (0 == sym_index) {
+	/* Hm, maybe it's '_symbol' instead of 'symbol' or '__imp__symbol' */
+	char buffer[100];
+	if (0 == memcmp(symbol, "__imp__", 7))
+	    symbol += 6;
+	else
+	    buffer[0] = '_', strcpy(buffer + 1, symbol), symbol = buffer;
+	sym_index = find_elf_sym(s1->dynsymtab_section, symbol);
+    }
+    if (ret)
+	strcpy(ret, symbol);
+    return sym_index;
+}
+
+#ifdef WIN32
+ST void **pe_imp;
+ST int nb_pe_imp;
+
+void *resolve_sym(struct TCCState *s1, const char *symbol, int type)
+{
+    char buffer[100], *p = buffer;
+    void *a = NULL;
+    int sym_index = pe_find_import(s1, symbol, p);
+    if (sym_index) {
+	int dll_index =
+	    ((Elf32_Sym *) s1->dynsymtab_section->data)[sym_index].
+	    st_other;
+	if (dll_index) {
+	    const char *dll_name = s1->loaded_dlls[dll_index - 1]->name;
+	    void *hm = GetModuleHandleA(dll_name);
+	    if (NULL == hm)
+		hm = LoadLibraryA(dll_name);
+	    if (hm) {
+		a = GetProcAddress(hm, buffer);
+		if (a && STT_OBJECT == type) {
+		    // need to return a pointer to the address for data objects
+		    dynarray_add(&pe_imp, &nb_pe_imp, a);
+		    a = &pe_imp[nb_pe_imp - 1];
+		}
+	    }
+	}
+    }
+    return a;
+}
+#endif
+
+#define for_sym_in_symtab(sym) \
+for (sym = (Elf32_Sym *)symtab_section->data + 1; \
+	 sym < (Elf32_Sym *)(symtab_section->data + \
+		symtab_section->data_offset); \
+	 ++sym)
+
+#define pe_set_datadir(dir,addr,size) \
+	pe_opt_hdr.DataDirectory[dir].VirtualAddress = addr, \
+	pe_opt_hdr.DataDirectory[dir].Size = size
+
+/*----------------------------------------------------------------------------*/
+ST void dynarray_reset(void ***pp, int *n)
+{
+    int i;
+    for (i = 0; i < *n; ++i)
+	tcc_free((*pp)[i]);
+    tcc_free(*pp);
+    *pp = NULL;
+    *n = 0;
+}
+
+ST int dynarray_assoc(void **pp, int n, int key)
+{
+    int i;
+    for (i = 0; i < n; ++i, ++pp)
+	if (key == **(int **) pp)
+	    return i;
+    return -1;
+}
+
+#if 0
+ST DWORD umin(DWORD a, DWORD b)
+{
+    return a < b ? a : b;
+}
+#endif
+
+ST DWORD umax(DWORD a, DWORD b)
+{
+    return a < b ? b : a;
+}
+
+ST void pe_fpad(FILE * fp, DWORD new_pos)
+{
+    DWORD pos = ftell(fp);
+    while (++pos <= new_pos)
+	fputc(0, fp);
+}
+
+ST DWORD pe_file_align(DWORD n)
+{
+    return (n + (0x200 - 1)) & ~(0x200 - 1);
+}
+
+ST DWORD pe_virtual_align(DWORD n)
+{
+    return (n + (0x1000 - 1)) & ~(0x1000 - 1);
+}
+
+ST void pe_align_section(Section * s, int a)
+{
+    int i = s->data_offset & (a - 1);
+    if (i)
+	section_ptr_add(s, a - i);
+}
+
+
+/*----------------------------------------------------------------------------*/
+ST int pe_write_pe(struct pe_info *pe)
+{
+    int i;
+    FILE *op;
+    DWORD file_offset;
+    IMAGE_SECTION_HEADER ish[pe_sec_number], *psh;
+    int sec_index = 0;
+
+    op = fopen(pe->filename, "wb");
+    if (NULL == op) {
+	error_noabort("could not create file: %s", pe->filename);
+	return 1;
+    }
+
+    memset(&ish, 0, sizeof ish);
+
+    pe->sizeofheaders = pe_file_align(sizeof pe_dos_hdr
+				      + sizeof pe_magic
+				      + sizeof pe_file_hdr
+				      + sizeof pe_opt_hdr
+				      +
+				      pe->sec_count *
+				      sizeof(IMAGE_SECTION_HEADER)
+	);
+
+    file_offset = pe->sizeofheaders;
+    pe_fpad(op, file_offset);
+
+    if (2 == verbose)
+	printf("-------------------------------"
+	       "\n  virt   file   size  section" "\n");
+
+    for (i = 0; i < pe->sec_count; ++i) {
+	struct section_info *si = pe->sh_info + i;
+	const char *sh_name = pe_sec_names[si->id];
+	unsigned long addr = si->sh_addr - pe->imagebase;
+	unsigned long size = si->sh_size;
+
+	if (2 == verbose)
+	    printf("%6lx %6lx %6lx  %s\n",
+		   addr, file_offset, size, sh_name);
+
+	switch (si->id) {
+	case sec_text:
+	    pe_opt_hdr.BaseOfCode = addr;
+	    pe_opt_hdr.AddressOfEntryPoint = addr + pe->start_addr;
+	    break;
+
+	case sec_data:
+	    pe_opt_hdr.BaseOfData = addr;
+	    if (pe->imp_size) {
+		pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT,
+			       pe->imp_offs + addr, pe->imp_size);
+		pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT,
+			       pe->iat_offs + addr, pe->iat_size);
+	    }
+	    if (pe->exp_size) {
+		pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT,
+			       pe->exp_offs + addr, pe->exp_size);
+	    }
+	    break;
+
+	case sec_bss:
+	    break;
+
+	case sec_reloc:
+	    pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
+	    break;
+
+	case sec_rsrc:
+	    pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
+	    break;
+
+	case sec_stab:
+	    break;
+
+	case sec_stabstr:
+	    break;
+	}
+
+	psh = &ish[sec_index++];
+	strcpy((char *) psh->Name, sh_name);
+
+	psh->Characteristics = pe_flags[si->id];
+	psh->VirtualAddress = addr;
+	psh->Misc.VirtualSize = size;
+	pe_opt_hdr.SizeOfImage =
+	    umax(psh->VirtualAddress + psh->Misc.VirtualSize,
+		 pe_opt_hdr.SizeOfImage);
+
+	if (si->data_size) {
+	    psh->PointerToRawData = file_offset;
+	    fwrite(si->data, 1, si->data_size, op);
+	    file_offset = pe_file_align(file_offset + si->data_size);
+	    psh->SizeOfRawData = file_offset - psh->PointerToRawData;
+	    pe_fpad(op, file_offset);
+	}
+    }
+
+	/*----------------------------------------------------- */
+
+    pe_file_hdr.NumberOfSections = sec_index;
+    pe_opt_hdr.SizeOfHeaders = pe->sizeofheaders;
+    pe_opt_hdr.ImageBase = pe->imagebase;
+    if (PE_DLL == pe_type)
+	pe_file_hdr.Characteristics = 0x230E;
+    else if (PE_GUI != pe_type)
+	pe_opt_hdr.Subsystem = 3;
+
+    fseek(op, SEEK_SET, 0);
+    fwrite(&pe_dos_hdr, 1, sizeof pe_dos_hdr, op);
+    fwrite(&pe_magic, 1, sizeof pe_magic, op);
+    fwrite(&pe_file_hdr, 1, sizeof pe_file_hdr, op);
+    fwrite(&pe_opt_hdr, 1, sizeof pe_opt_hdr, op);
+    for (i = 0; i < sec_index; ++i)
+	fwrite(&ish[i], 1, sizeof(IMAGE_SECTION_HEADER), op);
+    fclose(op);
+
+    if (2 == verbose)
+	printf("-------------------------------\n");
+    if (verbose)
+	printf("<-- %s (%lu bytes)\n", pe->filename, file_offset);
+
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+ST int pe_add_import(struct pe_info *pe, int sym_index, DWORD offset)
+{
+    int i;
+    int dll_index;
+    struct pe_import_info *p;
+    struct import_symbol *s;
+
+    dll_index =
+	((Elf32_Sym *) pe->s1->dynsymtab_section->data)[sym_index].
+	st_other;
+    if (0 == dll_index)
+	return 0;
+
+    i = dynarray_assoc((void **) pe->imp_info, pe->imp_count, dll_index);
+    if (-1 != i) {
+	p = pe->imp_info[i];
+	goto found_dll;
+    }
+    p = tcc_mallocz(sizeof *p);
+    p->dll_index = dll_index;
+    dynarray_add((void ***) &pe->imp_info, &pe->imp_count, p);
+
+  found_dll:
+    i = dynarray_assoc((void **) p->symbols, p->sym_count, sym_index);
+    if (-1 != i)
+	goto found_sym;
+    s = tcc_mallocz(sizeof *s);
+    s->sym_index = sym_index;
+    s->offset = offset;
+    dynarray_add((void ***) &p->symbols, &p->sym_count, s);
+
+  found_sym:
+    return 1;
+}
+
+/*----------------------------------------------------------------------------*/
+ST void pe_build_imports(struct pe_info *pe)
+{
+    int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
+    DWORD voffset = pe->thunk->sh_addr - pe->imagebase;
+    int ndlls = pe->imp_count;
+
+    for (sym_cnt = i = 0; i < ndlls; ++i)
+	sym_cnt += pe->imp_info[i]->sym_count;
+
+    if (0 == sym_cnt)
+	return;
+
+    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->iat_offs = dll_ptr + pe->imp_size;
+    pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD);
+    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;
+	struct pe_import_info *p = pe->imp_info[i];
+	const char *name = pe->s1->loaded_dlls[p->dll_index - 1]->name;
+
+	/* put the dll name into the import header */
+	if (0 == strncmp(name, "lib", 3))
+	    name += 3;
+	v = put_elf_str(pe->thunk, name);
+
+	hdr = (struct pe_import_header *) (pe->thunk->data + dll_ptr);
+	hdr->first_thunk = thk_ptr + voffset;
+	hdr->first_entry = ent_ptr + voffset;
+	hdr->lib_name_offset = v + voffset;
+
+	for (k = 0, n = p->sym_count; k <= n; ++k) {
+	    if (k < n) {
+		DWORD offset = p->symbols[k]->offset;
+		int sym_index = p->symbols[k]->sym_index;
+		Elf32_Sym *sym =
+		    (Elf32_Sym *) pe->s1->dynsymtab_section->data +
+		    sym_index;
+		const char *name =
+		    pe->s1->dynsymtab_section->link->data + sym->st_name;
+
+		if (offset & 0x80000000) {	/* ref to data */
+		    Elf32_Sym *sym =
+			&((Elf32_Sym *) symtab_section->
+			  data)[offset & 0x7FFFFFFF];
+		    sym->st_value = thk_ptr;
+		    sym->st_shndx = pe->thunk->sh_num;
+		} else {	/* ref to function */
+
+		    char buffer[100];
+		    sprintf(buffer, "IAT.%s", name);
+		    sym_index =
+			put_elf_sym(symtab_section, thk_ptr, sizeof(DWORD),
+				    ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
+				    0, pe->thunk->sh_num, buffer);
+
+		    put_elf_reloc(symtab_section, text_section, offset, R_386_32,	/*R_JMP_SLOT, */
+				  sym_index);
+		}
+		v = pe->thunk->data_offset + voffset;
+		section_ptr_add(pe->thunk, sizeof(WORD));	/* hint, not used */
+		put_elf_str(pe->thunk, name);
+	    } 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);
+	}
+	dll_ptr += sizeof(struct pe_import_header);
+	dynarray_reset((void ***) &p->symbols, &p->sym_count);
+    }
+    dynarray_reset((void ***) &pe->imp_info, &pe->imp_count);
+}
+
+/* ------------------------------------------------------------- */
+ST void pe_build_exports(struct pe_info *pe)
+{
+    Elf32_Sym *sym;
+    DWORD func_offset;
+    DWORD voffset = pe->thunk->sh_addr - pe->imagebase;
+    struct pe_export_header *hdr;
+    int sym_count = 0, ordinal = 0;
+
+    // for simplicity only functions are exported
+    for_sym_in_symtab(sym)
+	if (sym->st_shndx != text_section->sh_num)
+	sym->st_other &= ~1;
+    else if (sym->st_other & 1)
+	++sym_count;
+
+    if (0 == sym_count)
+	return;
+
+    pe_align_section(pe->thunk, 16);
+
+    pe->exp_offs = pe->thunk->data_offset;
+    hdr = section_ptr_add(pe->thunk,
+			  sizeof(struct pe_export_header) +
+			  sym_count * (2 * sizeof(DWORD) + sizeof(WORD)));
+
+    func_offset = pe->exp_offs + sizeof(struct pe_export_header);
+
+    hdr->Characteristics = 0;
+    hdr->Base = 1;
+    hdr->NumberOfFunctions = sym_count;
+    hdr->NumberOfNames = sym_count;
+    hdr->AddressOfFunctions = func_offset + voffset;
+    hdr->AddressOfNames =
+	hdr->AddressOfFunctions + sym_count * sizeof(DWORD);
+    hdr->AddressOfNameOrdinals =
+	hdr->AddressOfNames + sym_count * sizeof(DWORD);
+    hdr->Name = pe->thunk->data_offset + voffset;
+    put_elf_str(pe->thunk, tcc_basename(pe->filename));
+
+    for_sym_in_symtab(sym)
+	if (sym->st_other & 1) {
+	char *name = symtab_section->link->data + sym->st_name;
+	DWORD *p = (DWORD *) (pe->thunk->data + func_offset);
+	DWORD *pfunc = p + ordinal;
+	DWORD *pname = p + sym_count + ordinal;
+	WORD *pord = (WORD *) (p + 2 * sym_count) + ordinal;
+	*pfunc =
+	    sym->st_value + pe->s1->sections[sym->st_shndx]->sh_addr -
+	    pe->imagebase;
+	*pname = pe->thunk->data_offset + voffset;
+	*pord = ordinal;
+	put_elf_str(pe->thunk, name);
+	/* printf("export: %s\n", name); */
+	++ordinal;
+    }
+    pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
+}
+
+/* ------------------------------------------------------------- */
+ST void pe_build_reloc(struct pe_info *pe, int *section_order,
+		       int section_count)
+{
+    DWORD offset, block_ptr, addr;
+    int count, i;
+    Elf32_Rel *rel, *rel_end;
+    Section *s = NULL, *sr;
+    offset = addr = block_ptr = count = i = 0;
+    rel = rel_end = NULL;
+    for (;;) {
+	if (rel < rel_end) {
+	    int type = ELF32_R_TYPE(rel->r_info);
+	    addr = rel->r_offset + s->sh_addr;
+	    ++rel;
+	    if (type != R_386_32)
+		continue;
+	    if (count == 0) {	/* new block */
+		block_ptr = pe->reloc->data_offset;
+		section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header));
+		offset = addr & 0xFFFFFFFF << 12;
+	    }
+	    if ((addr -= offset) < (1 << 12)) {	/* one block spans 4k addresses */
+		WORD *wp = section_ptr_add(pe->reloc, sizeof(WORD));
+		*wp = addr | IMAGE_REL_BASED_HIGHLOW << 12;
+		++count;
+		continue;
+	    }
+	    --rel;
+	} else if (i < section_count) {
+	    sr = (s = pe->s1->sections[section_order[i++]])->reloc;
+	    if (sr) {
+		rel = (Elf32_Rel *) sr->data;
+		rel_end = (Elf32_Rel *) (sr->data + sr->data_offset);
+	    }
+	    continue;
+	}
+
+	if (count) {		/* store the last block and ready for a new one */
+	    struct pe_reloc_header *hdr;
+	    if (count & 1)
+		section_ptr_add(pe->reloc, 2), ++count;
+	    hdr = (struct pe_reloc_header *) (pe->reloc->data + block_ptr);
+	    hdr->offset = offset - pe->imagebase;
+	    hdr->size =
+		count * sizeof(WORD) + sizeof(struct pe_reloc_header);
+	    count = 0;
+	}
+	if (rel >= rel_end)
+	    break;
+    }
+}
+
+/* ------------------------------------------------------------- */
+ST int pe_assign_addresses(struct pe_info *pe)
+{
+    int i, k, n;
+    DWORD addr;
+    int section_order[pe_sec_number];
+    struct section_info *si_data = NULL;
+
+    pe->imagebase = PE_DLL == pe_type ? 0x10000000 : 0x00400000;
+    addr = pe->imagebase + 1;
+
+    if (PE_DLL == pe_type)
+	pe->reloc = new_section(pe->s1, ".reloc", SHT_DYNAMIC, SHF_ALLOC);
+
+    for (n = k = 0; n < pe_sec_number; ++n) {
+	for (i = 1; i < pe->s1->nb_sections; ++i) {
+	    Section *s = pe->s1->sections[i];
+	    if (0 == strcmp(s->name, pe_sec_names[n])) {
+		struct section_info *si = &pe->sh_info[pe->sec_count];
+#ifdef PE_MERGE_DATA
+		if (n == sec_bss && si_data) {
+		    /* append .bss to .data */
+		    s->sh_addr = addr = ((addr - 1) | 15) + 1;
+		    addr += s->data_offset;
+		    si_data->sh_size = addr - si_data->sh_addr;
+		} else
+#endif
+		{
+		    si->sh_addr = s->sh_addr = addr =
+			pe_virtual_align(addr);
+		    si->id = n;
+
+		    if (n == sec_data) {
+			pe->thunk = s;
+			si_data = si;
+			pe_build_imports(pe);
+			pe_build_exports(pe);
+		    } else if (n == sec_reloc) {
+			pe_build_reloc(pe, section_order, k);
+		    }
+
+		    if (s->data_offset) {
+			if (n != sec_bss) {
+			    si->data = s->data;
+			    si->data_size = s->data_offset;
+			}
+
+			addr += s->data_offset;
+			si->sh_size = s->data_offset;
+			++pe->sec_count;
+		    }
+		    //printf("Section %08X %04X %s\n", si->sh_addr, si->data_size, s->name);
+		}
+		section_order[k] = i, ++k;
+	    }
+	}
+    }
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+ST int pe_check_symbols(struct pe_info *pe)
+{
+    Elf32_Sym *sym;
+    int ret = 0;
+
+    pe_align_section(text_section, 8);
+
+    for_sym_in_symtab(sym) {
+	if (sym->st_shndx == SHN_UNDEF) {
+	    const char *symbol = symtab_section->link->data + sym->st_name;
+	    unsigned type = ELF32_ST_TYPE(sym->st_info);
+	    int sym_index = pe_find_import(pe->s1, symbol, NULL);
+	    if (sym_index) {
+		if (type == STT_FUNC) {
+		    unsigned long offset = text_section->data_offset;
+		    if (pe_add_import(pe, sym_index, offset + 2)) {
+			/* add the 'jmp IAT[x]' instruction */
+			*(WORD *) section_ptr_add(text_section, 8) =
+			    0x25FF;
+			/* patch the symbol */
+			sym->st_shndx = text_section->sh_num;
+			sym->st_value = offset;
+			continue;
+		    }
+		} else if (type == STT_OBJECT) {	/* data, ptr to that should be */
+		    if (pe_add_import(pe, sym_index,
+				      (sym -
+				      (Elf32_Sym *) symtab_section->data) | 
+                                      0x80000000))
+			continue;
+		}
+	    }
+	    error_noabort("undefined symbol '%s'", symbol);
+	    ret = 1;
+	} else
+	    if (pe->s1->rdynamic
+		&& ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
+	    /* if -rdynamic option, then export all non local symbols */
+	    sym->st_other |= 1;
+	}
+    }
+    return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+#ifdef PE_PRINT_SECTIONS
+ST void pe_print_section(FILE * f, Section * s)
+{				/* just if you'r curious */
+    BYTE *p, *e, b;
+    int i, n, l, m;
+    p = s->data;
+    e = s->data + s->data_offset;
+    l = e - p;
+
+    fprintf(f, "section  \"%s\"", s->name);
+    if (s->link)
+	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, "\n\n");
+
+    if (s->sh_type == SHT_NOBITS)
+	return;
+
+    if (s->sh_type == SHT_SYMTAB)
+	m = sizeof(Elf32_Sym);
+    if (s->sh_type == SHT_REL)
+	m = sizeof(Elf32_Rel);
+    else
+	m = 16;
+
+    for (i = 0; i < l;) {
+	fprintf(f, "%08X", i);
+	for (n = 0; n < m; ++n) {
+	    if (n + i < l)
+		fprintf(f, " %02X", p[i + n]);
+	    else
+		fprintf(f, "   ");
+	}
+
+	if (s->sh_type == SHT_SYMTAB) {
+	    Elf32_Sym *sym = (Elf32_Sym *) (p + i);
+	    const char *name = s->link->data + sym->st_name;
+	    fprintf(f,
+		    "  name:%04X"
+		    "  value:%04X"
+		    "  size:%04X"
+		    "  bind:%02X"
+		    "  type:%02X"
+		    "  other:%02X"
+		    "  shndx:%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);
+	    const char *name = s->link->link->data + sym->st_name;
+	    fprintf(f,
+		    "  offset:%04X"
+		    "  type:%02X"
+		    "  symbol:%04X"
+		    "  \"%s\"",
+		    rel->r_offset,
+		    ELF32_R_TYPE(rel->r_info),
+		    ELF32_R_SYM(rel->r_info), name);
+	} else {
+	    fprintf(f, "   ");
+	    for (n = 0; n < m; ++n) {
+		if (n + i < l) {
+		    b = p[i + n];
+		    if (b < 32 || b >= 127)
+			b = '.';
+		    fprintf(f, "%c", b);
+		}
+	    }
+	}
+	i += m;
+	fprintf(f, "\n");
+    }
+    fprintf(f, "\n\n");
+}
+#endif
+
+static int pe_test_cmd(const char **pp, const char *cmd)
+{
+    const char *p;
+    char *q, buf[16];
+    int ret;
+
+    p = *pp;
+    q = buf;
+    while (*p != '\0' && !is_space(*p)) {
+        if ((q - buf) < sizeof(buf) - 1)
+            *q++ = toup(*p);
+        p++;
+    }
+    *q = '\0';
+    ret = !strcmp(buf, cmd);
+    *pp = p;
+    return ret;
+}
+
+/* ------------------------------------------------------------- */
+int pe_load_def_file(TCCState * s1, FILE * fp)
+{
+    DLLReference *dllref;
+    int f = 0, sym_index;
+    char *p, *p_other, line[120], dllname[40];
+    while (fgets(line, sizeof line, fp)) {
+	p = strchr(line, 0);
+	while (p > line && p[-1] <= ' ')
+	    --p;
+	*p = 0;
+	p = line;
+	while (*p && *p <= ' ')
+	    ++p;
+
+	if (*p && ';' != *p)
+	    switch (f) {
+	    case 0:
+                if (!pe_test_cmd((const char **)&p, "LIBRARY"))
+		    return -1;
+                while (is_space(*p))
+                    p++;
+		pstrcpy(dllname, sizeof(dllname), p);
+		++f;
+		continue;
+
+	    case 1:
+                if (!pe_test_cmd((const char **)&p, "EXPORTS"))
+		    return -1;
+		++f;
+		continue;
+
+	    case 2:
+		dllref =
+		    tcc_malloc(sizeof(DLLReference) + strlen(dllname));
+		strcpy(dllref->name, dllname);
+		dllref->level = 0;
+		dynarray_add((void ***) &s1->loaded_dlls,
+			     &s1->nb_loaded_dlls, dllref);
+		++f;
+
+	    default:
+		sym_index = add_elf_sym(s1->dynsymtab_section,
+					0, 0, ELF32_ST_INFO(STB_GLOBAL,
+							    STT_FUNC),
+					text_section->sh_num, p);
+		/*gr: tccpe needs to know from what dll it should import the sym */
+		p_other =
+		    &((Elf32_Sym *) s1->dynsymtab_section->
+		      data)[sym_index].st_other;
+		if (0 == *p_other)
+		    *p_other = s1->nb_loaded_dlls;
+		continue;
+	    }
+    }
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+unsigned long pe_add_runtime(TCCState * s1)
+{
+    const char *start_symbol;
+    unsigned long addr;
+
+    if (find_elf_sym(symtab_section, "WinMain"))
+	pe_type = PE_GUI;
+
+    start_symbol =
+	TCC_OUTPUT_MEMORY == s1->output_type
+	? PE_GUI == pe_type ? "_runwinmain" : NULL
+	: PE_DLL == pe_type ? "_dllstart"
+	: PE_GUI == pe_type ? "_winstart" : "_start";
+
+    /* grab the startup code from libtcc1 */
+    if (start_symbol)
+	add_elf_sym(symtab_section,
+		    0, 0,
+		    ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+		    SHN_UNDEF, start_symbol);
+
+    if (0 == s1->nostdlib) {
+	tcc_add_library(s1, "tcc1");
+	tcc_add_library(s1, "msvcrt");
+	if (PE_DLL == pe_type || PE_GUI == pe_type) {
+	    tcc_add_library(s1, "kernel32");
+	    tcc_add_library(s1, "user32");
+	    tcc_add_library(s1, "gdi32");
+	}
+    }
+
+    addr = start_symbol ?
+	(unsigned long) tcc_get_symbol_err(s1, start_symbol) : 0;
+
+    if (s1->output_type == TCC_OUTPUT_MEMORY && addr) {
+	/* for -run GUI's, put '_runwinmain' instead of 'main' */
+	add_elf_sym(symtab_section,
+		    addr, 0,
+		    ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+		    text_section->sh_num, "main");
+
+	/* FreeConsole(); */
+    }
+    return addr;
+}
+
+int tcc_output_pe(TCCState * s1, const char *filename)
+{
+    int ret;
+    struct pe_info pe;
+    int i;
+    memset(&pe, 0, sizeof pe);
+    pe.filename = filename;
+    pe.s1 = s1;
+    pe.start_addr = pe_add_runtime(s1);
+
+    relocate_common_syms();	/* assign bss adresses */
+    ret = pe_check_symbols(&pe);
+    if (0 == ret) {
+	pe_assign_addresses(&pe);
+	relocate_syms(s1, 0);
+	for (i = 1; i < s1->nb_sections; ++i) {
+	    Section *s = s1->sections[i];
+	    if (s->reloc)
+		relocate_section(s1, s);
+	}
+	ret = pe_write_pe(&pe);
+    }
+#ifdef PE_PRINT_SECTIONS
+    {
+	Section *s;
+	FILE *f;
+	f = fopen("tccpe.log", "wb");
+	for (i = 1; i < s1->nb_sections; ++i) {
+	    s = s1->sections[i];
+	    pe_print_section(f, s);
+	}
+	pe_print_section(f, s1->dynsymtab_section);
+	fclose(f);
+    }
+#endif
+    return ret;
+}
+
+/*----------------------------------------------------------------------------*/
--- a/tcctok.h	Sun Apr 10 21:43:10 2005 +0000
+++ b/tcctok.h	Sun Apr 10 21:46:58 2005 +0000
@@ -100,6 +100,7 @@
      DEF(TOK_STDCALL1, "stdcall")
      DEF(TOK_STDCALL2, "__stdcall")
      DEF(TOK_STDCALL3, "__stdcall__")
+     DEF(TOK_DLLEXPORT, "dllexport")
      DEF(TOK_NORETURN1, "noreturn")
      DEF(TOK_NORETURN2, "__noreturn__")
      DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")