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

Reply via email to