aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2009-07-18 22:07:25 +0200
committergrischka <grischka>2009-07-18 22:07:25 +0200
commit1df662c1b094d250db0501cf31db83dc5f9060e4 (patch)
tree61de457b79e72b5ef5eb5f0b918935e572f49dbc
parent9fda4f4248f24ee3e9feb9204bd1ef035c4859da (diff)
downloadtinycc-1df662c1b094d250db0501cf31db83dc5f9060e4.tar.gz
tinycc-1df662c1b094d250db0501cf31db83dc5f9060e4.tar.bz2
tccpe: load dll on the fly
-rw-r--r--libtcc.c213
-rw-r--r--tcc.h1
-rw-r--r--tccelf.c2
-rw-r--r--tccpe.c141
-rw-r--r--win32/tools/tiny_impdef.c183
5 files changed, 313 insertions, 227 deletions
diff --git a/libtcc.c b/libtcc.c
index bfa6839..3494ee2 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -212,9 +212,7 @@ static int tcc_add_file_internal(TCCState *s, const char *filename, int flags);
int tcc_output_coff(TCCState *s1, FILE *f);
/* tccpe.c */
-int pe_load_def_file(struct TCCState *s1, int fd);
-int pe_test_res_file(void *v, int size);
-int pe_load_res_file(struct TCCState *s1, int fd);
+int pe_load_file(struct TCCState *s1, const char *filename, int fd);
int pe_output_file(struct TCCState *s1, const char *filename);
/* tccasm.c */
@@ -277,6 +275,7 @@ static int tcc_compile(TCCState *s1);
void expect(const char *msg);
void skip(int c);
static void test_lvalue(void);
+void *resolve_sym(TCCState *s1, const char *sym);
static inline int isid(int c)
{
@@ -303,8 +302,6 @@ static inline int toup(int c)
return c;
}
-void *resolve_sym(TCCState *s1, const char *sym);
-
/********************************************************/
#ifdef TCC_TARGET_I386
@@ -353,6 +350,43 @@ static void asm_global_instr(void)
#endif
/********************************************************/
+#ifdef _WIN32
+char *normalize_slashes(char *path)
+{
+ char *p;
+ for (p = path; *p; ++p)
+ if (*p == '\\')
+ *p = '/';
+ return path;
+}
+
+HMODULE tcc_module;
+
+/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
+void tcc_set_lib_path_w32(TCCState *s)
+{
+ char path[1024], *p;
+ GetModuleFileNameA(tcc_module, path, sizeof path);
+ p = tcc_basename(normalize_slashes(strlwr(path)));
+ if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
+ p -= 5;
+ else if (p > path)
+ p--;
+ *p = 0;
+ tcc_set_lib_path(s, path);
+}
+
+#ifdef LIBTCC_AS_DLL
+BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+ if (DLL_PROCESS_ATTACH == dwReason)
+ tcc_module = hDll;
+ return TRUE;
+}
+#endif
+#endif
+
+/********************************************************/
#ifdef CONFIG_TCC_STATIC
#define RTLD_LAZY 0x001
@@ -393,7 +427,7 @@ static TCCSyms tcc_syms[] = {
{ NULL, NULL },
};
-void *resolve_sym(TCCState *s1, const char *symbol, int type)
+void *resolve_sym(TCCState *s1, const char *symbol)
{
TCCSyms *p;
p = tcc_syms;
@@ -405,8 +439,10 @@ void *resolve_sym(TCCState *s1, const char *symbol, int type)
return NULL;
}
-#elif !defined(_WIN32)
+#elif defined(_WIN32)
+#define dlclose FreeLibrary
+#else
#include <dlfcn.h>
void *resolve_sym(TCCState *s1, const char *sym)
@@ -1982,9 +2018,11 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{
const char *ext;
ElfW(Ehdr) ehdr;
- int fd, ret;
+ int fd, ret, size;
BufferedFile *saved_file;
+ ret = -1;
+
/* find source file type with extension */
ext = tcc_fileextension(filename);
if (ext[0])
@@ -1994,104 +2032,103 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
saved_file = file;
file = tcc_open(s1, filename);
if (!file) {
- if (flags & AFF_PRINT_ERROR) {
+ if (flags & AFF_PRINT_ERROR)
error_noabort("file '%s' not found", filename);
- }
- ret = -1;
- goto fail1;
+ goto the_end;
}
if (flags & AFF_PREPROCESS) {
ret = tcc_preprocess(s1);
- } else if (!ext[0] || !PATHCMP(ext, "c")) {
+ goto the_end;
+ }
+
+ if (!ext[0] || !PATHCMP(ext, "c")) {
/* C file assumed */
ret = tcc_compile(s1);
- } else
+ goto the_end;
+ }
+
#ifdef CONFIG_TCC_ASM
if (!strcmp(ext, "S")) {
/* preprocessed assembler */
ret = tcc_assemble(s1, 1);
- } else if (!strcmp(ext, "s")) {
+ goto the_end;
+ }
+
+ if (!strcmp(ext, "s")) {
/* non preprocessed assembler */
ret = tcc_assemble(s1, 0);
- } else
-#endif
-#ifdef TCC_TARGET_PE
- if (!PATHCMP(ext, "def")) {
- ret = pe_load_def_file(s1, file->fd);
- } else
+ goto the_end;
+ }
#endif
- {
- fd = file->fd;
- /* assume executable format: auto guess file type */
- ret = read(fd, &ehdr, sizeof(ehdr));
- lseek(fd, 0, SEEK_SET);
- if (ret <= 0) {
- error_noabort("could not read header");
- goto fail;
- } else if (ret != sizeof(ehdr)) {
- goto try_load_script;
- }
- if (ehdr.e_ident[0] == ELFMAG0 &&
- ehdr.e_ident[1] == ELFMAG1 &&
- ehdr.e_ident[2] == ELFMAG2 &&
- ehdr.e_ident[3] == ELFMAG3) {
- file->line_num = 0; /* do not display line number if error */
- if (ehdr.e_type == ET_REL) {
- 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);
- }
+ fd = file->fd;
+ /* assume executable format: auto guess file type */
+ size = read(fd, &ehdr, sizeof(ehdr));
+ lseek(fd, 0, SEEK_SET);
+ if (size <= 0) {
+ error_noabort("could not read header");
+ goto the_end;
+ }
+
+ if (size == sizeof(ehdr) &&
+ ehdr.e_ident[0] == ELFMAG0 &&
+ ehdr.e_ident[1] == ELFMAG1 &&
+ ehdr.e_ident[2] == ELFMAG2 &&
+ ehdr.e_ident[3] == ELFMAG3) {
+
+ /* do not display line number if error */
+ file->line_num = 0;
+ if (ehdr.e_type == ET_REL) {
+ ret = tcc_load_object_file(s1, fd, 0);
+ goto the_end;
+
+ }
+#ifndef TCC_TARGET_PE
+ if (ehdr.e_type == ET_DYN) {
+ if (s1->output_type == TCC_OUTPUT_MEMORY) {
+ void *h;
+ h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
+ if (h)
+ ret = 0;
} else {
- error_noabort("unrecognized ELF file");
- goto fail;
+ ret = tcc_load_dll(s1, fd, filename,
+ (flags & AFF_REFERENCED_DLL) != 0);
}
- } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
- file->line_num = 0; /* do not display line number if error */
- ret = tcc_load_archive(s1, fd);
- } else
+ goto the_end;
+ }
+#endif
+ error_noabort("unrecognized ELF file");
+ goto the_end;
+ }
+
+ if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
+ file->line_num = 0; /* do not display line number if error */
+ ret = tcc_load_archive(s1, fd);
+ goto the_end;
+ }
+
#ifdef TCC_TARGET_COFF
- if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
- ret = tcc_load_coff(s1, fd);
- } else
+ if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
+ ret = tcc_load_coff(s1, fd);
+ goto the_end;
+ }
#endif
+
#ifdef TCC_TARGET_PE
- if (pe_test_res_file(&ehdr, ret)) {
- ret = pe_load_res_file(s1, fd);
- } else
+ ret = pe_load_file(s1, filename, fd);
+#else
+ /* as GNU ld, consider it is an ld script if not recognized */
+ ret = tcc_load_ldscript(s1);
#endif
- {
- /* as GNU ld, consider it is an ld script if not recognized */
- try_load_script:
- ret = tcc_load_ldscript(s1);
- if (ret < 0) {
- error_noabort("unrecognized file type");
- goto fail;
- }
- }
- }
- the_end:
- tcc_close(file);
- fail1:
+ if (ret < 0)
+ error_noabort("unrecognized file type");
+
+the_end:
+ if (file)
+ tcc_close(file);
file = saved_file;
return ret;
- fail:
- ret = -1;
- goto the_end;
}
int tcc_add_file(TCCState *s, const char *filename)
@@ -2136,14 +2173,14 @@ 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);
+ if (pe_add_dll(s, libraryname) == 0)
+ return 0;
#else
snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
-#endif
if (tcc_add_dll(s, buf, 0) == 0)
return 0;
+#endif
}
-
/* then we look for the static library */
for(i = 0; i < s->nb_library_paths; i++) {
snprintf(buf, sizeof(buf), "%s/lib%s.a",
@@ -2225,6 +2262,10 @@ int tcc_set_output_type(TCCState *s, int output_type)
#ifdef TCC_TARGET_PE
snprintf(buf, sizeof(buf), "%s/lib", s->tcc_lib_path);
tcc_add_library_path(s, buf);
+#ifdef _WIN32
+ if (GetSystemDirectory(buf, sizeof buf))
+ tcc_add_library_path(s, buf);
+#endif
#endif
return 0;
diff --git a/tcc.h b/tcc.h
index 459e64d..50bbd56 100644
--- a/tcc.h
+++ b/tcc.h
@@ -46,7 +46,6 @@
#include <direct.h> /* getcwd */
#define inline __inline
#define inp next_inp
-#define dlclose FreeLibrary
#ifdef _MSC_VER
#define __aligned(n) __declspec(align(n))
#endif
diff --git a/tccelf.c b/tccelf.c
index 69f94c4..826e8e0 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -2424,6 +2424,7 @@ static int tcc_load_archive(TCCState *s1, int fd)
return 0;
}
+#ifndef TCC_TARGET_PE
/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
is referenced by the user (so it should be added as DT_NEEDED in
the generated ELF file) */
@@ -2740,3 +2741,4 @@ static int tcc_load_ldscript(TCCState *s1)
}
return 0;
}
+#endif
diff --git a/tccpe.c b/tccpe.c
index 89ff3bd..fe87919 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -46,6 +46,19 @@
#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
/* ----------------------------------------------------------- */
@@ -442,29 +455,12 @@ struct pe_info {
int imp_count;
};
-/* ------------------------------------------------------------- */
-
#define PE_NUL 0
#define PE_DLL 1
#define PE_GUI 2
#define PE_EXE 3
#define PE_RUN 4
-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
-
/* --------------------------------------------*/
ST_FN const char* get_alt_symbol(char *buffer, const char *symbol)
@@ -1355,62 +1351,55 @@ 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 ...'.
- */
+/* ------------------------------------------------------------- */
-PUB_FN int pe_test_res_file(void *v, int size)
+ST_FN int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
{
- 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")
- ;
+ fseek(fp, offset, 0);
+ return len == fread(buffer, 1, len, fp);
}
-ST_FN int read_n(int fd, void *ptr, unsigned size)
-{
- return size == read(fd, ptr, size);
-}
+/* -------------------------------------------------------------
+ * This is for compiled windows resources in 'coff' format
+ * as generated by 'windres.exe -O coff ...'.
+ */
-PUB_FN int pe_load_res_file(TCCState *s1, int fd)
+ST_FN 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_XXX_RELATIVE, 0);
+ offs += sizeof rel;
}
ret = 0;
quit:
- if (ret)
- error_noabort("unrecognized resource file format");
return ret;
}
@@ -1439,15 +1428,11 @@ ST_FN char *get_line(char *line, int size, FILE *fp)
}
/* ------------------------------------------------------------- */
-PUB_FN int pe_load_def_file(TCCState *s1, int fd)
+ST_FN int pe_load_def(TCCState *s1, FILE *fp)
{
DLLReference *dllref;
int state = 0, ret = -1;
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);
@@ -1485,13 +1470,65 @@ PUB_FN int pe_load_def_file(TCCState *s1, int fd)
}
ret = 0;
quit:
- if (fp)
+ return ret;
+}
+
+/* ------------------------------------------------------------- */
+#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
+#include "win32/tools/tiny_impdef.c"
+
+ST_FN int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp)
+{
+ int i = 0;
+ char *p, *q;
+ p = get_export_names(fp);
+ if (p) {
+ DLLReference *dllref;
+ dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
+ strcpy(dllref->name, dllname);
+ dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+ for (q = p, i = 0; *q; ++i) {
+ add_elf_sym(s1->dynsymtab_section,
+ s1->nb_loaded_dlls, 0,
+ ELFW_ST_INFO(STB_GLOBAL, STT_FUNC), 0,
+ text_section->sh_num, q);
+ q += 1 + strlen(q);
+ }
+ tcc_free(p);
+ }
+ return i ? 0 : -1;
+}
+
+/* ------------------------------------------------------------- */
+PUB_FN 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, filename, fp);
fclose(fp);
- if (ret)
- error_noabort("unrecognized export definition file format");
+ }
return ret;
}
+int pe_add_dll(struct TCCState *s, const char *libraryname)
+{
+ char buf[MAX_PATH];
+ snprintf(buf, sizeof(buf), "%s.def", libraryname);
+ if (tcc_add_dll(s, buf, 0) == 0)
+ return 0;
+ snprintf(buf, sizeof(buf), "%s.dll", libraryname);
+ if (tcc_add_dll(s, buf, 0) == 0)
+ return 0;
+ return -1;
+}
+
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
diff --git a/win32/tools/tiny_impdef.c b/win32/tools/tiny_impdef.c
index 53fb255..b024a90 100644
--- a/win32/tools/tiny_impdef.c
+++ b/win32/tools/tiny_impdef.c
@@ -20,100 +20,19 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifndef TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
+
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "../../config.h"
-int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
-{
- fseek(fp, offset, 0);
- return len == fread(buffer, 1, len, fp);
-}
-
-char *get_export_names(FILE *fp)
-{
- int l, i, n, n0;
- char *p;
-
- IMAGE_SECTION_HEADER ish;
- IMAGE_EXPORT_DIRECTORY ied;
- IMAGE_DOS_HEADER dh;
- IMAGE_FILE_HEADER ih;
- DWORD sig, ref, addr, ptr, namep;
-#ifdef TCC_TARGET_X86_64
- IMAGE_OPTIONAL_HEADER64 oh;
- const int MACHINE = 0x8664;
-#else
- IMAGE_OPTIONAL_HEADER32 oh;
- const int MACHINE = 0x014C;
-#endif
- int pef_hdroffset, opt_hdroffset, sec_hdroffset;
-
- n = n0 = 0;
- p = NULL;
-
- if (!read_mem(fp, 0, &dh, sizeof dh))
- goto the_end;
- if (!read_mem(fp, dh.e_lfanew, &sig, sizeof sig))
- goto the_end;
- if (sig != 0x00004550)
- goto the_end;
- pef_hdroffset = dh.e_lfanew + sizeof sig;
- if (!read_mem(fp, pef_hdroffset, &ih, sizeof ih))
- goto the_end;
- if (MACHINE != ih.Machine)
- goto the_end;
- opt_hdroffset = pef_hdroffset + sizeof ih;
- sec_hdroffset = opt_hdroffset + sizeof oh;
- if (!read_mem(fp, opt_hdroffset, &oh, sizeof oh))
- goto the_end;
-
- if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
- goto the_end;
-
- addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- //printf("addr: %08x\n", addr);
- for (i = 0; i < ih.NumberOfSections; ++i) {
- if (!read_mem(fp, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
- goto the_end;
- //printf("vaddr: %08x\n", ish.VirtualAddress);
- if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
- goto found;
- }
- goto the_end;
-
-found:
- ref = ish.VirtualAddress - ish.PointerToRawData;
- if (!read_mem(fp, addr - ref, &ied, sizeof ied))
- goto the_end;
-
- namep = ied.AddressOfNames - ref;
- for (i = 0; i < ied.NumberOfNames; ++i) {
- if (!read_mem(fp, namep, &ptr, sizeof ptr))
- goto the_end;
- namep += sizeof ptr;
- for (l = 0;;) {
- if (n+1 >= n0)
- p = realloc(p, n0 = n0 ? n0 * 2 : 256);
- if (!read_mem(fp, ptr - ref + l, p + n, 1) || ++l >= 80) {
- free(p), p = NULL;
- goto the_end;
- }
- if (p[n++] == 0)
- break;
- }
- }
- if (p)
- p[n] = 0;
-the_end:
- return p;
-}
+char *get_export_names(FILE *fp);
+#define tcc_free free
+#define tcc_realloc realloc
-/* -------------------------------------------------------------- */
/* extract the basename of a file */
-
static char *file_basename(const char *name)
{
const char *p = strchr(name, 0);
@@ -125,8 +44,6 @@ static char *file_basename(const char *name)
return (char*)p;
}
-/* -------------------------------------------------------------- */
-
int main(int argc, char **argv)
{
int ret, v, i;
@@ -232,3 +149,93 @@ the_end:
}
/* -------------------------------------------------------------- */
+
+int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len)
+{
+ fseek(fp, offset, 0);
+ return len == fread(buffer, 1, len, fp);
+}
+
+/* -------------------------------------------------------------- */
+#endif
+
+char *get_export_names(FILE *fp)
+{
+ int l, i, n, n0;
+ char *p;
+
+ IMAGE_SECTION_HEADER ish;
+ IMAGE_EXPORT_DIRECTORY ied;
+ IMAGE_DOS_HEADER dh;
+ IMAGE_FILE_HEADER ih;
+ DWORD sig, ref, addr, ptr, namep;
+#ifdef TCC_TARGET_X86_64
+ IMAGE_OPTIONAL_HEADER64 oh;
+ const int MACHINE = 0x8664;
+#else
+ IMAGE_OPTIONAL_HEADER32 oh;
+ const int MACHINE = 0x014C;
+#endif
+ int pef_hdroffset, opt_hdroffset, sec_hdroffset;
+
+ n = n0 = 0;
+ p = NULL;
+
+ if (!read_mem(fp, 0, &dh, sizeof dh))
+ goto the_end;
+ if (!read_mem(fp, dh.e_lfanew, &sig, sizeof sig))
+ goto the_end;
+ if (sig != 0x00004550)
+ goto the_end;
+ pef_hdroffset = dh.e_lfanew + sizeof sig;
+ if (!read_mem(fp, pef_hdroffset, &ih, sizeof ih))
+ goto the_end;
+ if (MACHINE != ih.Machine)
+ goto the_end;
+ opt_hdroffset = pef_hdroffset + sizeof ih;
+ sec_hdroffset = opt_hdroffset + sizeof oh;
+ if (!read_mem(fp, opt_hdroffset, &oh, sizeof oh))
+ goto the_end;
+
+ if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
+ goto the_end;
+
+ addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ //printf("addr: %08x\n", addr);
+ for (i = 0; i < ih.NumberOfSections; ++i) {
+ if (!read_mem(fp, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
+ goto the_end;
+ //printf("vaddr: %08x\n", ish.VirtualAddress);
+ if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
+ goto found;
+ }
+ goto the_end;
+
+found:
+ ref = ish.VirtualAddress - ish.PointerToRawData;
+ if (!read_mem(fp, addr - ref, &ied, sizeof ied))
+ goto the_end;
+
+ namep = ied.AddressOfNames - ref;
+ for (i = 0; i < ied.NumberOfNames; ++i) {
+ if (!read_mem(fp, namep, &ptr, sizeof ptr))
+ goto the_end;
+ namep += sizeof ptr;
+ for (l = 0;;) {
+ if (n+1 >= n0)
+ p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256);
+ if (!read_mem(fp, ptr - ref + l, p + n, 1) || ++l >= 80) {
+ tcc_free(p), p = NULL;
+ goto the_end;
+ }
+ if (p[n++] == 0)
+ break;
+ }
+ }
+ if (p)
+ p[n] = 0;
+the_end:
+ return p;
+}
+
+/* -------------------------------------------------------------- */