diff --git a/tccelf.c b/tccelf.c index 8644005..0065759 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1496,13 +1496,92 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1) #endif } +#ifdef TCC_TARGET_PE +static void move_init_exit_data (TCCState *s1, Section *s) +{ + int i; + char buf[256]; + unsigned char *ptr; + unsigned char *rptr; + Section *r; + Section *rt; + ElfW_Rel *rel; + + /* copy data from .init/.fini array in text section */ + ptr = section_ptr_add(text_section, s->data_offset); + memcpy (ptr, s->data, s->data_offset); + /* copy relocation data from .init.rel/.fini.rel in text section .rel */ + snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); + r = find_section_create (s1, buf, 0); + if (r) { + snprintf(buf, sizeof(buf), REL_SECTION_FMT, text_section->name); + rt = find_section_create (s1, buf, 0); + if (rt) { + for (i = 0; i < r->data_offset; i += sizeof (ElfW_Rel)) { + rptr = section_ptr_add(rt, sizeof (ElfW_Rel)); + memcpy (rptr, &r->data[i], sizeof (ElfW_Rel)); + rel = (ElfW_Rel *) rptr; + rel->r_offset = (ptr - text_section->data) + (i / sizeof (ElfW_Rel)) * PTR_SIZE; + } + } + /* data from .init.rel/.fini.rel copied so section empty */ + r->data_offset = 0; + } + /* data from .init/.fini array copied so section empty */ + s->data_offset = 0; +} + +static void create_init_sym (int file_type, const char *exe, const char *dll) +{ + /* hidden symbol for dll, default for exe */ + set_elf_sym(symtab_section, + text_section->data_offset, file_type == TCC_OUTPUT_DLL ? STV_HIDDEN : STV_DEFAULT, + ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, + text_section->sh_num, file_type == TCC_OUTPUT_DLL ? dll : exe); + /* dummy hidden dll symbol for exe */ + if (file_type != TCC_OUTPUT_DLL) { + set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), STV_HIDDEN, + text_section->sh_num, dll); + } +} + +static void create_constructor_destructor (TCCState *s1) +{ + Section *s; + unsigned char *ptr; + int file_type = s1->output_type; + + /* align text section */ + while ((text_section->data_offset & (PTR_SIZE -1)) != 0) { + ptr = section_ptr_add(text_section, 1); + *ptr = 0; + } + create_init_sym (file_type, "__exe_constructor_start", "__dll_constructor_start"); + s = find_section_create (s1, ".init_array", 0); + if (s && s->data_offset) { + move_init_exit_data (s1, s); + } + create_init_sym (file_type, "__exe_constructor_end", "__dll_constructor_end"); + create_init_sym (file_type, "__exe_destructor_start", "__dll_destructor_start"); + s = find_section_create (s1, ".fini_array", 0); + if (s && s->data_offset) { + move_init_exit_data (s1, s); + } + create_init_sym (file_type, "__exe_destructor_end", "__dll_destructor_end"); +} +#endif + /* add tcc runtime libraries */ ST_FUNC void tcc_add_runtime(TCCState *s1) { s1->filetype = 0; tcc_add_bcheck(s1); tcc_add_pragma_libs(s1); -#ifndef TCC_TARGET_PE +#ifdef TCC_TARGET_PE + create_constructor_destructor (s1); +#else /* add libc */ if (!s1->nostdlib) { tcc_add_library_err(s1, "c"); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index e7f2ecb..cec5b50 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -33,7 +33,6 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) endif ifneq (-$(CONFIG_WIN32)$(CONFIG_WIN64)-,--) SKIP += 106_pthread.test # No pthread support - SKIP += 108_constructor.test # No contructor/destructor support endif # Some tests might need arguments diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c index c5047ed..14a8d9e 100644 --- a/win32/lib/crt1.c +++ b/win32/lib/crt1.c @@ -34,6 +34,27 @@ int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int glob void __cdecl __set_app_type(int apptype); unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask); extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]); +extern void (*__exe_constructor_start[]) (void); +extern void (*__exe_constructor_end[]) (void); +extern void (*__exe_destructor_start[]) (void); +extern void (*__exe_destructor_end[]) (void); + +static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[]) +{ + int retval; + long i; + + i = 0; + while (&__exe_constructor_start[i] != __exe_constructor_end) { + (*__exe_constructor_start[i++])(); + } + retval = _tmain(__argc, __targv, _tenviron); + i = 0; + while (&__exe_destructor_end[i] != __exe_destructor_start) { + (*__exe_destructor_end[--i])(); + } + return retval; +} /* Allow command-line globbing with "int _dowildcard = 1;" in the user source */ int _dowildcard; @@ -57,7 +78,7 @@ void _tstart(void) #endif __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info); - exit(_tmain(__argc, __targv, _tenviron)); + exit(do_main(__argc, __targv, _tenviron)); } int _runtmain(int argc, /* as tcc passed in */ char **argv) @@ -78,7 +99,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) #if defined __i386__ || defined __x86_64__ _controlfp(_PC_53, _MCW_PC); #endif - return _tmain(__argc, __targv, _tenviron); + return do_main(__argc, __targv, _tenviron); } // ============================================= diff --git a/win32/lib/dllcrt1.c b/win32/lib/dllcrt1.c index ba1dbd0..5d0cdad 100644 --- a/win32/lib/dllcrt1.c +++ b/win32/lib/dllcrt1.c @@ -2,12 +2,31 @@ #include +extern void (*__dll_constructor_start[]) (void) __attribute((visibility("hidden"))) ; +extern void (*__dll_constructor_end[]) (void) __attribute((visibility("hidden"))); +extern void (*__dll_destructor_start[]) (void) __attribute((visibility("hidden"))); +extern void (*__dll_destructor_end[]) (void) __attribute((visibility("hidden"))); + BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved); BOOL WINAPI _dllstart(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) { - BOOL bRet; - bRet = DllMain (hDll, dwReason, lpReserved); - return bRet; + BOOL bRet; + int i; + + if (dwReason == DLL_PROCESS_ATTACH) { /* ignore DLL_THREAD_ATTACH */ + i = 0; + while (&__dll_constructor_start[i] != __dll_constructor_end) { + (*__dll_constructor_start[i++])(); + } + } + if (dwReason == DLL_PROCESS_DETACH) { /* ignore DLL_THREAD_DETACH */ + i = 0; + while (&__dll_destructor_end[i] != __dll_destructor_start) { + (*__dll_destructor_end[--i])(); + } + } + bRet = DllMain (hDll, dwReason, lpReserved); + return bRet; } diff --git a/win32/lib/wincrt1.c b/win32/lib/wincrt1.c index 5ea10ea..e1fd516 100644 --- a/win32/lib/wincrt1.c +++ b/win32/lib/wincrt1.c @@ -23,6 +23,11 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); #define _runtwinmain _runwinmain #endif +extern void (*__exe_constructor_start[]) (void); +extern void (*__exe_constructor_end[]) (void); +extern void (*__exe_destructor_start[]) (void); +extern void (*__exe_destructor_end[]) (void); + typedef struct { int newmode; } _startupinfo; int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*); @@ -31,6 +36,8 @@ static int go_winmain(TCHAR *arg1) STARTUPINFO si; _TCHAR *szCmd, *p; int fShow; + int retval; + int i; GetStartupInfo(&si); if (si.dwFlags & STARTF_USESHOWWINDOW) @@ -48,7 +55,16 @@ static int go_winmain(TCHAR *arg1) #if defined __i386__ || defined __x86_64__ _controlfp(0x10000, 0x30000); #endif - return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow); + i = 0; + while (&__exe_constructor_start[i] != __exe_constructor_end) { + (*__exe_constructor_start[i++])(); + } + retval = _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow); + i = 0; + while (&__exe_destructor_end[i] != __exe_destructor_start) { + (*__exe_destructor_end[--i])(); + } + return retval; } static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)