aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2005-04-10 21:46:58 +0000
committerbellard <bellard>2005-04-10 21:46:58 +0000
commit2c538d7a2b0fb9e72c0fbb9af5d351302584aca0 (patch)
tree0f89e8ac6f2fa62a0beb3915b13a4767968b772f
parentbdd09709d7b412c2cd7380172264d985fabafa6d (diff)
downloadtinycc-2c538d7a2b0fb9e72c0fbb9af5d351302584aca0.tar.gz
tinycc-2c538d7a2b0fb9e72c0fbb9af5d351302584aca0.tar.bz2
initial PE format support
-rw-r--r--Makefile5
-rw-r--r--tcc.c100
-rw-r--r--tccelf.c7
-rw-r--r--tccpe.c1220
-rw-r--r--tcctok.h1
5 files changed, 1314 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index 8b681e5..575a6d5 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ endif
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 @@ c67-tcc$(EXESUF): tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h tcccoff.c
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 $@ $<
diff --git a/tcc.c b/tcc.c
index 0803795..4410789 100644
--- a/tcc.c
+++ b/tcc.c
@@ -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 @@ typedef struct AttributeDef {
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 @@ extern long double strtold (const char *__nptr, char **__endptr);
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 @@ static int tcc_add_file_internal(TCCState *s, const char *filename, int flags);
/* 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 @@ static TCCSyms tcc_syms[] = {
{ 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 @@ void *dlsym(void *handle, const char *symbol)
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 @@ static void parse_attribute(AttributeDef *ad)
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 @@ static void asm_global_instr(void)
#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 @@ int tcc_relocate(TCCState *s1)
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 @@ TCCState *tcc_new(void)
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 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
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 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
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 @@ int tcc_add_library(TCCState *s, const char *libraryname)
/* 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_add_symbol(TCCState *s, const char *name, unsigned long val)
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 @@ int tcc_set_output_type(TCCState *s, int output_type)
}
/* 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 @@ static int64_t getclock_us(void)
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 @@ int main(int argc, char **argv)
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 @@ int main(int argc, char **argv)
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 */
diff --git a/tccelf.c b/tccelf.c
index 6ba3bf2..f835f31 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -385,11 +385,6 @@ static void relocate_common_syms(void)
}
}
-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 @@ static void relocate_syms(TCCState *s1, int do_resolve)
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;
diff --git a/tccpe.c b/tccpe.c
new file mode 100644
index 0000000..8ac4b50
--- /dev/null
+++ b/tccpe.c
@@ -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;
+}
+
+/*----------------------------------------------------------------------------*/
diff --git a/tcctok.h b/tcctok.h
index fce32a9..0414541 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -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")