I created the windows constructor patch. See attached patch.
I had a good night sleep and realized that I could copy the .init/.fini
arrays + relocations to the text section and then modify the win32/lib
code to call these functions.
I implemented this and it works (even for dll's). So testcase 108 now
runs fine on windows.
The testcode for dll's is also attached (d.c and e.c).
To compile this do:
tcc.exe -g -shared -o libe.dll e.c
tcc.exe -g -o d.exe d.c -L. -le
Running d.exe should result in:
constructor1
constructor
main
destructor
destructor1
The mingw compiler now also works. The problem was that you at least
have to call 1 functions in the dll.
So compiling with:
x86_64-w64-mingw32-gcc -fPIC -shared -o libe.dll e.c
x86_64-w64-mingw32-gcc d.c -o d -L. -le
Running d.exe has the same result as above.
Herman
On 2019-10-29 06:51, Christian Jullien wrote:
Replying to my own question, on Windows gcc does support ctor/dtor so, IHMO,
tcc should do the same.
Taking Herman's 108_constructor.c gcc 9.1 Mingw64 gives:
C:>gcc foo.c -o foo.exe
C:>file foo.exe
foo.exe: PE32+ executable (console) x86-64, for MS Windows
C:>foo
constructor
main
destructor
-----Original Message-----
From: Tinycc-devel [mailto:tinycc-devel-bounces+eligis=orange...@nongnu.org] On
Behalf Of Michael Matz
Sent: Monday, October 28, 2019 10:40
To: Herman ten Brugge via Tinycc-devel
Cc: Herman ten Brugge
Subject: Re: [Tinycc-devel] constructor/destructor support
Hello,
On Fri, 25 Oct 2019, Herman ten Brugge via Tinycc-devel wrote:
I implemented constructors and destructors. This was the one thing I was
missing for my own project.
See the attachment.
Can I push it?
Could you please refactor some things? In particular the duplicate code
of add_init_array and add_fini_array: instead add just one function
(add_sec_array?) that takes the name of the section. Also if you test
the section size for being != 0 before creating the dynamic tags
(DT_INIT* and friends) it might be that you can avoid having to add the
'create' argument to find_section; it would be nice to not have to have
it.
Otherwise, looks good. Thanks for the work. (And yeah, bonus points for
Windows and -run support :) ).
Ciao,
Michael.
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
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 <windows.h>
+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)
extern int write (int fd, void *buf, int len);
static void __attribute__ ((constructor))
testc (void)
{
write (1, "constructor1\n", 13);
}
static void __attribute__ ((destructor))
testd (void)
{
write (1, "destructor1\n", 12);
}
__attribute__((dllexport)) void calle(void)
{
}
extern int write (int fd, void *buf, int len);
static void __attribute__ ((constructor))
testc (void)
{
write (1, "constructor\n", 12);
}
static void __attribute__ ((destructor))
testd (void)
{
write (1, "destructor\n", 11);
}
__attribute__((dllimport)) void calle(void);
int
main (void)
{
calle();
write (1, "main\n", 5);
return 0;
}
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel