libwine: Added a wine_call_on_stack function.
authorAlexandre Julliard <julliard@winehq.org>
Wed, 26 Mar 2008 14:38:00 +0000 (15:38 +0100)
committerAlexandre Julliard <julliard@winehq.org>
Wed, 26 Mar 2008 14:38:00 +0000 (15:38 +0100)
include/wine/library.h
libs/wine/port.c
libs/wine/wine.def
libs/wine/wine.map

index f00919e097a119a90975af1a82eb3f2b80ba3aa3..2c3b7bbe1b34e2ac01f573eb08c6de501a0d5410 100644 (file)
@@ -66,6 +66,7 @@ extern void wine_init( int argc, char *argv[], char *error, int error_size );
 /* portability */
 
 extern void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack );
+extern int wine_call_on_stack( int (*func)(void *), void *arg, void *stack );
 extern void wine_set_pe_load_area( void *base, size_t size );
 extern void wine_free_pe_load_area(void);
 
index 838c3ffea58fd44ddc5677010159f77be6c2863b..e2f7b0cbbe3f9d733063ee876032eddccc56939c 100644 (file)
@@ -116,5 +116,69 @@ __ASM_GLOBAL_FUNC( wine_switch_to_stack,
                    "callq *%rax\n\t"    /* call func */
                    "int $3")
 #else
+void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack )
+{
+    wine_call_on_stack( (int (*)(void *))func, arg, stack );
+    abort();
+}
+#endif
+
+
+/***********************************************************************
+ *           wine_call_on_stack
+ *
+ * Switch to the specified stack to call the function and return.
+ */
+int wine_call_on_stack( int (*func)(void *), void *arg, void *stack );
+#if defined(__i386__) && defined(__GNUC__)
+__ASM_GLOBAL_FUNC( wine_call_on_stack,
+                   "pushl %ebp\n\t"
+                   "pushl %esi\n\t"
+                   "movl 12(%esp),%ecx\n\t"  /* func */
+                   "movl 16(%esp),%edx\n\t"  /* arg */
+                   "movl 20(%esp),%esi\n\t"  /* stack */
+                   "andl $~15,%esi\n\t"
+                   "subl $12,%esi\n\t"
+                   "xchgl %esi,%esp\n\t"
+                   "pushl %edx\n\t"
+                   "xorl %ebp,%ebp\n\t"
+                   "call *%ecx\n\t"
+                   "movl %esi,%esp\n\t"
+                   "popl %esi\n\t"
+                   "popl %ebp\n\t"
+                   "ret" )
+#elif defined(__i386__) && defined(_MSC_VER)
+__declspec(naked) int wine_call_on_stack( int (*func)(void *), void *arg, void *stack )
+{
+  __asm push ebp;
+  __asm push esi;
+  __asm mov ecx, 12[esp];
+  __asm mov edx, 16[esp];
+  __asm mov esi, 20[esp];
+  __asm xchg esp, esi;
+  __asm push edx;
+  __asm xor ebp, ebp;
+  __asm call [ecx];
+  __asm mov esp, esi;
+  __asm pop esi;
+  __asm pop ebp
+  __asm ret;
+}
+#elif defined(__x86_64__) && defined(__GNUC__)
+__ASM_GLOBAL_FUNC( wine_call_on_stack,
+                   "pushq %rbp\n\t"
+                   "pushq %rbx\n\t"
+                   "movq %rsp,%rbx\n\t"
+                   "movq %rdi,%rax\n\t" /* func */
+                   "movq %rsi,%rdi\n\t" /* arg */
+                   "andq $~15,%rdx\n\t" /* stack */
+                   "movq %rdx,%rsp\n\t"
+                   "xorq %rbp,%rbp\n\t"
+                   "callq *%rax\n\t"    /* call func */
+                   "movq %rbx,%rsp\n\t"
+                   "popq %rbx\n\t"
+                   "popq %rbp\n\t"
+                   "ret")
+#else
 #error You must implement wine_switch_to_stack for your platform
 #endif
index 462a6191278c669155403756e70128498126984c..6304113119627296ef7273beda25316e88e894fa 100644 (file)
@@ -50,6 +50,7 @@ EXPORTS
     vsnprintfW
     vsprintfW
     wine_anon_mmap
+    wine_call_on_stack
     wine_casemap_lower
     wine_casemap_upper
     wine_compare_string
@@ -65,7 +66,7 @@ EXPORTS
     wine_dbgstr_an
     wine_dbgstr_wn
     wine_dlclose
-    wine_dll_enum_load_path;
+    wine_dll_enum_load_path
     wine_dll_get_owner
     wine_dll_load
     wine_dll_load_main_exe
index 47e58ced824c69505399bb90bba3be2cb4031740..ef8d823f62707e7242f6f325da220eb00f21b254 100644 (file)
@@ -50,6 +50,7 @@ WINE_1.0
     vsnprintfW;
     vsprintfW;
     wine_anon_mmap;
+    wine_call_on_stack;
     wine_casemap_lower;
     wine_casemap_upper;
     wine_compare_string;