changeset 362:78dfa2f9783a

- added helper function dcGetModeFromCCSigChar() mapping callconv sig chars to respective mode - added a signature-based syscall to callf testcode - manual clarification about dcReset usage in combination with dcMode
author Tassilo Philipp
date Tue, 14 Apr 2020 16:56:57 +0200
parents 06c9adae114d
children 3ff4a4ba7f0e
files ChangeLog doc/manual/manual_dyncall_api.tex dyncall/dyncall.3 dyncall/dyncall.h dyncall/dyncall_api.c dyncall/dyncall_callf.c dyncall/dyncall_signature.h test/callf/main.c
diffstat 8 files changed, 57 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Apr 13 21:40:28 2020 +0200
+++ b/ChangeLog	Tue Apr 14 16:56:57 2020 +0200
@@ -5,6 +5,7 @@
   o extended signature with more chars for calling convention switching (only for modes
     that coexist on a platform with other conventions)
   o made "formatted" call interface use calling convention signature chars
+  o added helper function dcGetModeFromCCSigChar() mapping callconv sig chars to respective mode
 dynload:
   o fix to build with musl libc
 doc:
@@ -14,7 +15,7 @@
     'Z' conversions to only immutable types and 'p' to mutable types (and handles), bytearray
 	support, support to specify calling convention
 tests:
-  o extended callf testcode with to test calling convention mode switch signature chars
+  o extended callf testcode to test callconv mode switch signature chars (including syscalls)
 
 Version 1.1 (2020/01/11)
 dyncall:
--- a/doc/manual/manual_dyncall_api.tex	Mon Apr 13 21:40:28 2020 +0200
+++ b/doc/manual/manual_dyncall_api.tex	Tue Apr 14 16:56:57 2020 +0200
@@ -214,11 +214,12 @@
 void dcReset(DCCallVM* vm);
 \end{lstlisting}
 
-
-Resets the internal stack of arguments and prepares it for a new call.
-This function should be called after setting the call mode (using dcMode), but
-prior to binding arguments to the CallVM. Use it also when reusing a CallVM, as
-arguments don't get flushed automatically after a function call invocation.\\
+Resets the internal stack of arguments and prepares it for a new call. This
+function should be called after setting the call mode (using dcMode), but prior
+to binding arguments to the CallVM (except for when setting mode
+DC\_SIGCHAR\_CC\_ELLIPSIS\_VARARGS, which is used prior to binding varargs of
+variadic functions). Use it also when reusing a CallVM, as arguments don't get
+flushed automatically after a function call invocation.\\
 Note: you should also call this function after initial creation of the a CallVM
 object, as dcNewCallVM doesn't do this, implicitly.\\
 
--- a/dyncall/dyncall.3	Mon Apr 13 21:40:28 2020 +0200
+++ b/dyncall/dyncall.3	Tue Apr 14 16:56:57 2020 +0200
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007-2013 Daniel Adler <dadler AT uni-goettingen DOT de>, 
+.\" Copyright (c) 2007-2020 Daniel Adler <dadler AT uni-goettingen DOT de>, 
 .\"                         Tassilo Philipp <tphilipp AT potion-studios DOT com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -112,12 +112,14 @@
 silently ignored.
 .Pp
 .Fn dcReset
-resets the internal stack of arguments and prepares it for a new call.
-This function should be called after setting the call mode (using dcMode), but
-prior to binding arguments to the CallVM. Use it also when reusing a CallVM, as
-arguments don't get flushed automatically after a function call invocation.
-Note: you should also call this function after initial creation of the a CallVM
-object, as dcNewCallVM doesn't do this, implicitly.
+resets the internal stack of arguments and prepares it for a new call. This
+function should be called after setting the call mode (using dcMode), but prior
+to binding arguments to the CallVM (except for when setting mode
+DC_SIGCHAR_CC_ELLIPSIS_VARARGS, which is used prior to binding varargs of
+variadic functions). Use it also when reusing a CallVM, as arguments don't get
+flushed automatically after a function call invocation.  Note: you should also
+call this function after initial creation of the a CallVM object, as
+dcNewCallVM doesn't do this, implicitly.
 .Pp
 .Fn dcArgBool ,
 .Fn dcArgChar ,
--- a/dyncall/dyncall.h	Mon Apr 13 21:40:28 2020 +0200
+++ b/dyncall/dyncall.h	Tue Apr 14 16:56:57 2020 +0200
@@ -39,6 +39,7 @@
 #define DYNCALL_H
 
 #include "dyncall_types.h"
+#include "dyncall_signature.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -136,6 +137,12 @@
 DC_API DCstruct*  dcDefineStruct  (const char* signature);
 
 
+/* helpers */
+
+/* returns respective mode for callconv sig char (w/o checking if mode exists */
+/* on current platform), or DC_ERROR_UNSUPPORTED_MODE if char isn't a sigchar */
+DC_API DCint      dcGetModeFromCCSigChar(DCsigchar sig_char);
+
 #ifdef __cplusplus
 }
 #endif
--- a/dyncall/dyncall_api.c	Mon Apr 13 21:40:28 2020 +0200
+++ b/dyncall/dyncall_api.c	Tue Apr 14 16:56:57 2020 +0200
@@ -6,7 +6,7 @@
  Description: C interface to call vm
  License:
 
-   Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>, 
+   Copyright (c) 2007-2020 Daniel Adler <dadler@uni-goettingen.de>, 
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -27,7 +27,6 @@
 
 #include "dyncall.h"
 #include "dyncall_callvm.h"
-#include "dyncall_alloc.h"
 
 void dcReset(DCCallVM* vm)
 { 
@@ -157,14 +156,23 @@
   return vm->mError;
 }
 
-/*@@@ not used, (re)introduce or cleanup
-const char* dcGetErrorString(int mode)
+DCint dcGetModeFromCCSigChar(DCsigchar sig_char)
 {
-  switch(mode) {
-    case DC_ERROR_NONE: return "none";
-    case DC_ERROR_UNSUPPORTED_MODE: return "unsupported mode";
-    default: return "(unknown mode id)";
+  switch(sig_char)
+  {
+    case DC_SIGCHAR_CC_DEFAULT:          return DC_CALL_C_DEFAULT;
+    case DC_SIGCHAR_CC_ELLIPSIS:         return DC_CALL_C_ELLIPSIS;
+    case DC_SIGCHAR_CC_ELLIPSIS_VARARGS: return DC_CALL_C_ELLIPSIS_VARARGS;
+    case DC_SIGCHAR_CC_CDECL:            return DC_CALL_C_X86_CDECL;
+    case DC_SIGCHAR_CC_STDCALL:          return DC_CALL_C_X86_WIN32_STD;
+    case DC_SIGCHAR_CC_FASTCALL_MS:      return DC_CALL_C_X86_WIN32_FAST_MS;
+    case DC_SIGCHAR_CC_FASTCALL_GNU:     return DC_CALL_C_X86_WIN32_FAST_GNU;
+    case DC_SIGCHAR_CC_THISCALL_MS:      return DC_CALL_C_X86_WIN32_THIS_MS;
+    case DC_SIGCHAR_CC_THISCALL_GNU:     return DC_CALL_C_X86_WIN32_THIS_GNU;
+    case DC_SIGCHAR_CC_ARM_ARM:          return DC_CALL_C_ARM_ARM;
+    case DC_SIGCHAR_CC_ARM_THUMB:        return DC_CALL_C_ARM_THUMB;
+    case DC_SIGCHAR_CC_SYSCALL:          return DC_CALL_SYS_DEFAULT;
   }
+  return DC_ERROR_UNSUPPORTED_MODE;
 }
-*/
 
--- a/dyncall/dyncall_callf.c	Mon Apr 13 21:40:28 2020 +0200
+++ b/dyncall/dyncall_callf.c	Tue Apr 14 16:56:57 2020 +0200
@@ -53,28 +53,12 @@
       case DC_SIGCHAR_STRING:    dcArgPointer (vm, (DCpointer)        va_arg(args, DCpointer )); break;
       /* calling convention modes */
       case DC_SIGCHAR_CC_PREFIX:
-      {
         if(*((*sigptr)+1) != '\0') {
-          switch(*(*sigptr)++) {
-            case DC_SIGCHAR_CC_DEFAULT:          dcMode(vm, DC_CALL_C_DEFAULT           ); break;
-            case DC_SIGCHAR_CC_ELLIPSIS:         dcMode(vm, DC_CALL_C_ELLIPSIS          ); break;
-            case DC_SIGCHAR_CC_ELLIPSIS_VARARGS: dcMode(vm, DC_CALL_C_ELLIPSIS_VARARGS  ); break;
-#if defined(DC__Arch_Intel_x86) /* @@@ theoretically not needed, if mode isn't understood the implementations shouldn't attempt ny mode switch */
-            case DC_SIGCHAR_CC_CDECL:            dcMode(vm, DC_CALL_C_X86_CDECL         ); break;
-            case DC_SIGCHAR_CC_STDCALL:          dcMode(vm, DC_CALL_C_X86_WIN32_STD     ); break;
-            case DC_SIGCHAR_CC_FASTCALL_MS:      dcMode(vm, DC_CALL_C_X86_WIN32_FAST_MS ); break;
-            case DC_SIGCHAR_CC_FASTCALL_GNU:     dcMode(vm, DC_CALL_C_X86_WIN32_FAST_GNU); break;
-            case DC_SIGCHAR_CC_THISCALL_MS:      dcMode(vm, DC_CALL_C_X86_WIN32_THIS_MS ); break;
-            case DC_SIGCHAR_CC_THISCALL_GNU:     dcMode(vm, DC_CALL_C_X86_WIN32_THIS_GNU); break;
-#elif defined(DC__Arch_ARM) /* @@@ theoretically not needed, if mode isn't understood the implementations shouldn't attempt any mode switch */
-            case DC_SIGCHAR_CC_ARM_ARM:          dcMode(vm, DC_CALL_C_ARM_ARM           ); break;
-            case DC_SIGCHAR_CC_ARM_THUMB:        dcMode(vm, DC_CALL_C_ARM_THUMB         ); break;
-#endif
-            case DC_SIGCHAR_CC_SYSCALL:          dcMode(vm, DC_CALL_SYS_DEFAULT         ); break;
-          }
+          DCint mode = dcGetModeFromCCSigChar(*(*sigptr)++);
+          if(mode != DC_ERROR_UNSUPPORTED_MODE)
+            dcMode(vm, mode);
         }
-      }
-	  break;
+        break;
     }
   }
 }
--- a/dyncall/dyncall_signature.h	Mon Apr 13 21:40:28 2020 +0200
+++ b/dyncall/dyncall_signature.h	Tue Apr 14 16:56:57 2020 +0200
@@ -6,7 +6,7 @@
  Description: Type and calling-convention signature character defines
  License:
 
-   Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>, 
+   Copyright (c) 2007-2020 Daniel Adler <dadler@uni-goettingen.de>, 
                            Tassilo Philipp <tphilipp@potion-studios.com>
 
    Permission to use, copy, modify, and distribute this software for any
--- a/test/callf/main.c	Mon Apr 13 21:40:28 2020 +0200
+++ b/test/callf/main.c	Tue Apr 14 16:56:57 2020 +0200
@@ -32,6 +32,9 @@
 #include "../common/platformInit.c" /* Impl. for functions only used in this translation unit */
 
 #include <stdarg.h>
+#if defined(DC_UNIX)
+#include <sys/syscall.h> 
+#endif
 
 
 /* sample void function */
@@ -129,6 +132,14 @@
   dcArgF(vm, "ffiffiffi", 1.f, 2.f, 3, 4.f, 5.f, 6, 7.f, 8.f, 9);
   r = r && dcCallInt(vm, (void*)&vf_ffiffiffi);
 
+#if defined(DC_UNIX)
+  /* testing syscall using calling convention prefix - not available on all platforms */
+  dcReset(vm);
+  printf("\ncallf _$ipi)i");
+  fflush(NULL); /* needed before syscall write as it's immediate, or order might be incorrect */
+  dcCallF(vm, &ret, (DCpointer)(ptrdiff_t)SYS_write, "_$ipi)i", 1/*stdout*/, " = syscall: 1", 13);
+  r = ret.i == 13 && r;
+#endif
 
   /* free vm */
   dcFree(vm);