summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.bat1
-rw-r--r--build32.bat2
-rw-r--r--foreign_msvc.c43
-rw-r--r--foreign_msvc32.c46
-rw-r--r--foreign_msvc64.c133
-rw-r--r--main.c1
-rw-r--r--test.toc48
-rw-r--r--toc.c2
-rw-r--r--win64call.asm174
-rw-r--r--win64call_test.c162
10 files changed, 563 insertions, 49 deletions
diff --git a/build.bat b/build.bat
deleted file mode 100644
index 50f2fbc..0000000
--- a/build.bat
+++ /dev/null
@@ -1 +0,0 @@
-cl /DTOC_DEBUG /W3 /wd4146 /D_CRT_SECURE_NO_WARNINGS /Od /Fe:toc.exe /DEBUG /Zi main.c
diff --git a/build32.bat b/build32.bat
new file mode 100644
index 0000000..287e2a5
--- /dev/null
+++ b/build32.bat
@@ -0,0 +1,2 @@
+if x%1 == xrelease cl /W3 /wd4146 /D_CRT_SECURE_NO_WARNINGS /O2 /Fe:toc.exe main.c
+if x%1 == x cl /DTOC_DEBUG /W3 /wd4146 /D_CRT_SECURE_NO_WARNINGS /Od /Fe:toc.exe /DEBUG /Zi main.c
diff --git a/foreign_msvc.c b/foreign_msvc.c
new file mode 100644
index 0000000..1e1cf7c
--- /dev/null
+++ b/foreign_msvc.c
@@ -0,0 +1,43 @@
+#include <windows.h>
+
+typedef struct {
+ HMODULE handle;
+} Library;
+
+static FnPtr msvc_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location call_where) {
+ FnPtr fn_ptr = fn->foreign.fn_ptr;
+ if (!fn_ptr) {
+ assert(fn->flags & FN_EXPR_FOREIGN);
+ char const *libname = fn->foreign.lib;
+ if (!libname) {
+ err_print(call_where, "Attempt to call function at compile time which does not have an associated library.");
+ info_print(fn->where, "Function was declared here.");
+ return false;
+ }
+ Library *lib = str_hash_table_get(&ffmgr->libs_loaded, libname, strlen(libname));
+ if (!lib) {
+ HMODULE handle = LoadLibraryA(libname);
+ if (!handle) {
+ DWORD err = GetLastError();
+ err_print(call_where, "Could not open dynamic library %s (error code %ld).", libname, err);
+ return false;
+ }
+ lib = str_hash_table_insert(&ffmgr->libs_loaded, libname, strlen(libname));
+ lib->handle = handle;
+ }
+ const char *name = fn->foreign.name;
+ fn_ptr = (FnPtr)GetProcAddress(lib->handle, name);
+ if (!fn_ptr) {
+ err_print(call_where, "Could not get function %s from dynamic library.", name);
+ return false;
+ }
+ fn->foreign.fn_ptr = fn_ptr;
+ }
+ return fn_ptr;
+}
+
+#ifdef _WIN64
+#include "foreign_msvc64.c"
+#else
+#include "foreign_msvc32.c"
+#endif
diff --git a/foreign_msvc32.c b/foreign_msvc32.c
index 8ab61a2..89928e4 100644
--- a/foreign_msvc32.c
+++ b/foreign_msvc32.c
@@ -1,24 +1,13 @@
/*
this code is not standard-compliant in the slightest, and a bit dubious,
-but I don't think there's any other way that doesn't involve inline assembly
+but I don't think there's any other way that doesn't involve assembly
*/
-#include <windows.h>
-
typedef size_t Word;
-
#if SIZE_MAX != U32_MAX
-/*
-@TODO
-x64 has its own calling convention
-*/
-#error "Calling #foreign functitons at compile time only works on 32-bit Windows, not 64-bit."
+#error "What's going on? The 32-bit Windows file was included, but size_t isn't 32 bits!"
#endif
-typedef struct {
- HMODULE handle;
-} Library;
-
/* f64s take 2 words */
static Status val_to_words(Value v, Type *t, Location where, Word *w) {
switch (t->kind) {
@@ -171,37 +160,12 @@ static double (*const msvc_callf[11])(FnPtr fn, Word *w) = {
msvc_call10f
};
+
static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type, Type *arg_types, size_t arg_types_stride, Value *args, size_t nargs, Location call_where, Value *ret) {
possibly_static_assert(sizeof(double) == 8);
possibly_static_assert(sizeof(float) == 4);
- FnPtr fn_ptr = fn->foreign.fn_ptr;
- if (!fn_ptr) {
- assert(fn->flags & FN_EXPR_FOREIGN);
- char const *libname = fn->foreign.lib;
- if (!libname) {
- err_print(call_where, "Attempt to call function at compile time which does not have an associated library.");
- info_print(fn->where, "Function was declared here.");
- return false;
- }
- Library *lib = str_hash_table_get(&ffmgr->libs_loaded, libname, strlen(libname));
- if (!lib) {
- HMODULE handle = LoadLibraryA(libname);
- if (!handle) {
- DWORD err = GetLastError();
- err_print(call_where, "Could not open dynamic library %s (error code %ld).", libname, err);
- return false;
- }
- lib = str_hash_table_insert(&ffmgr->libs_loaded, libname, strlen(libname));
- lib->handle = handle;
- }
- const char *name = fn->foreign.name;
- fn_ptr = (FnPtr)GetProcAddress(lib->handle, name);
- if (!fn_ptr) {
- err_print(call_where, "Could not get function %s from dynamic library.", name);
- return false;
- }
- fn->foreign.fn_ptr = fn_ptr;
- }
+ FnPtr fn_ptr = msvc_get_fn_ptr(ffmgr, fn, call_where);
+
Word words[10];
Word *word = words;
char *type = (char *)arg_types;
diff --git a/foreign_msvc64.c b/foreign_msvc64.c
new file mode 100644
index 0000000..4bbb643
--- /dev/null
+++ b/foreign_msvc64.c
@@ -0,0 +1,133 @@
+#if SIZE_MAX != U64_MAX
+#error "What's going on? The 64-bit Windows file was included, but size_t isn't 64 bits!"
+#endif
+
+extern U64 win64_call(FnPtr fn, U64 *args, I64 nargs);
+extern float win64_callf(FnPtr fn, U64 *args, I64 nargs);
+extern double win64_calld(FnPtr fn, U64 *args, I64 nargs);
+
+static Status val_to_word(Value v, Type *t, Location where, U64 *w) {
+ switch (t->kind) {
+ case TYPE_BUILTIN:
+ switch (t->builtin) {
+ case BUILTIN_I8: *w = (U64)v.i8; break;
+ case BUILTIN_I16: *w = (U64)v.i16; break;
+ case BUILTIN_I32: *w = (U64)v.i32; break;
+ case BUILTIN_U8: *w = (U64)v.u8; break;
+ case BUILTIN_U16: *w = (U64)v.u16; break;
+ case BUILTIN_U32: *w = (U64)v.u32; break;
+ case BUILTIN_I64: *w = (U64)v.i64; break;
+ case BUILTIN_U64: *w = v.u64; break;
+ case BUILTIN_F32: *w = (U64)*(U32 *)&v.f32; break;
+ case BUILTIN_F64: *w = *(U64 *)&v.f64; break;
+ case BUILTIN_CHAR: *w = (U64)v.charv; break;
+ case BUILTIN_BOOL: *w = (U64)v.boolv; break;
+ case BUILTIN_TYPE:
+ case BUILTIN_VARARGS:
+ case BUILTIN_NMS:
+ case BUILTIN_VOID:
+ goto unsupported;
+ }
+ break;
+ case TYPE_PTR:
+ *w = (U64)v.ptr; break;
+ default:
+ unsupported: {
+ /* @TODO(eventually) */
+ char *s = type_to_str(t);
+ err_print(where, "#foreign functions can't take arguments of type %s at compile time on Windows.", s);
+ free(s);
+ return false;
+ }
+ }
+ return true;
+}
+
+static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type, Type *arg_types, size_t arg_types_stride, Value *args, size_t nargs, Location call_where, Value *ret) {
+ possibly_static_assert(sizeof(double) == 8);
+ possibly_static_assert(sizeof(float) == 4);
+ FnPtr fn_ptr = msvc_get_fn_ptr(ffmgr, fn, call_where);
+
+ U64 *words = err_malloc(nargs * sizeof *words);
+ U64 *word = words;
+ char *type = (char *)arg_types;
+ for (size_t i = 0; i < nargs; ++i) {
+ if (!val_to_words(args[i], (Type *)type, call_where, word))
+ return false;
+ type += arg_types_stride;
+ ++word;
+ }
+ int kind = 0; /* 0=>integer, 1=>f32, 2=>f64 */
+ switch (ret_type->kind) {
+ case TYPE_BUILTIN:
+ switch (ret_type->builtin) {
+ case BUILTIN_I8:
+ case BUILTIN_I16:
+ case BUILTIN_I32:
+ case BUILTIN_I64:
+ case BUILTIN_U8:
+ case BUILTIN_U16:
+ case BUILTIN_U32:
+ case BUILTIN_U64:
+ case BUILTIN_BOOL:
+ case BUILTIN_CHAR:
+ case BUILTIN_VOID:
+ break;
+ case BUILTIN_F32:
+ kind = 1;
+ break;
+ case BUILTIN_F64:
+ kind = 2;
+ break;
+ default:
+ goto unsupported;
+ }
+ break;
+ case TYPE_PTR:
+ break;
+ default:
+ unsupported: {
+ char *s = type_to_str(ret_type);
+ /* @TODO(eventually) */
+ err_print(call_where, "You can't call functions which return type %s at compile time on Windows.", s);
+ free(s);
+ return false;
+ }
+ }
+
+ switch (kind) {
+ case 0: {
+ U64 r = win64_call(fn_ptr, words, (I64)nargs);
+ switch (ret_type->kind) {
+ case TYPE_BUILTIN:
+ switch (ret_type->builtin) {
+ case BUILTIN_I8: ret->i8 = (I8)r; break;
+ case BUILTIN_I16: ret->i16 = (I16)r; break;
+ case BUILTIN_I32: ret->i32 = (I32)r; break;
+ case BUILTIN_I64: ret->i64 = (I64)r; break;
+ case BUILTIN_U8: ret->u8 = (U8)r; break;
+ case BUILTIN_U16: ret->u16 = (U16)r; break;
+ case BUILTIN_U32: ret->u32 = (U32)r; break;
+ case BUILTIN_U64: ret->u64 = (U64)r; break;
+ case BUILTIN_BOOL: ret->boolv = (bool)r; break;
+ case BUILTIN_CHAR: ret->charv = (char)r; break;
+ case BUILTIN_VOID: (void)r; break;
+ default: assert(0); break;
+ }
+ break;
+ case TYPE_PTR:
+ ret->ptr = (void *)r;
+ break;
+ default: assert(0); break;
+ }
+ } break;
+ case 1:
+ ret->f32 = win64_callf(fn_ptr, words, (I64)nargs);
+ break;
+ case 2:
+ ret->f64 = win64_calld(fn_ptr, words, (I64)nargs);
+ break;
+ }
+ free(words);
+ return true;
+}
diff --git a/main.c b/main.c
index dc166d8..de2c818 100644
--- a/main.c
+++ b/main.c
@@ -8,7 +8,6 @@
/*
@TODO:
-fix puti(puti(x))
win64 #foreign
allow
#include "foo.toc", foo;
diff --git a/test.toc b/test.toc
index 2df6c46..5117906 100644
--- a/test.toc
+++ b/test.toc
@@ -1,9 +1,47 @@
-foo ::= fn(x: int) int {
- 2*x
+#include "std/io.toc", io;
+#include "std/mem.toc";
+
+main ::= fn() {
+ nums := news(int, 10);
+ for x, i := &nums {
+ *x = i*i;
+ }
+ l := slice_to_ll(nums);
+ p := &l;
+ while p {
+ io.puti(p.head);
+ p = p.tail;
+ }
+ f: Foo;
+ f.k = -173;
+ f.b = new(Bar);
+ f.b.f.b = new(Bar);
+ f.b.f.b.f.k = 9;
+ io.puti(f.k);
+ io.puti(f.b.f.k);
+ io.puti(f.b.f.b.f.k);
+}
+
+slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
+ head = slice[0];
+ if slice.len == 1 {
+ tail = null;
+ } else {
+ tail = new(LinkedList(t));
+ *tail = slice_to_ll(slice[1:]);
+ }
}
-main ::=fn(){
- foo(foo(10));
+LinkedList ::= struct (of :: Type) {
+ head: of;
+ tail: &LinkedList(of);
+}
+
+Foo ::= struct {
+ k: int;
+ b: &Bar;
+}
+Bar ::= struct {
+ f: Foo;
}
-main();
diff --git a/toc.c b/toc.c
index ed7443a..6a84170 100644
--- a/toc.c
+++ b/toc.c
@@ -154,7 +154,7 @@ static Location token_location(File *file, Token *t);
#if COMPILE_TIME_FOREIGN_FN_SUPPORT
#if defined _MSC_VER && !defined COMPILE_TIME_FOREIGN_FN_AVCALL
-#include "foreign_msvc32.c"
+#include "foreign_msvc.c"
#else
#include "foreign_avcall.c"
#endif
diff --git a/win64call.asm b/win64call.asm
new file mode 100644
index 0000000..5c1c76a
--- /dev/null
+++ b/win64call.asm
@@ -0,0 +1,174 @@
+;;; Call C functions with a dynamic number of arguments x64 MSVC ;;;
+;;; Written in NASM ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This is free and unencumbered software released into the public domain.
+;;
+;; Anyone is free to copy, modify, publish, use, compile, sell, or
+;; distribute this software, either in source code form or as a compiled
+;; binary, for any purpose, commercial or non-commercial, and by any
+;; means.
+;;
+;; In jurisdictions that recognize copyright laws, the author or authors
+;; of this software dedicate any and all copyright interest in the
+;; software to the public domain. We make this dedication for the benefit
+;; of the public at large and to the detriment of our heirs and
+;; successors. We intend this dedication to be an overt act of
+;; relinquishment in perpetuity of all present and future rights to this
+;; software under copyright law.
+;;
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+;; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+;; OTHER DEALINGS IN THE SOFTWARE.
+;;
+;; For more information, please refer to <http://unlicense.org/>
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;To compile this:
+;; first get nasm: https://nasm.us/
+;; add it to your path, then do:
+;; nasm -f win64 win64call.asm
+;; You will get win64call.lib
+;;To use this in a C/C++ program:
+;; typedef void (*FnPtr)();
+;; extern unsigned long long win64_call(FnPtr fn, void *args, long long nargs);
+;; extern float win64_callf(FnPtr fn, void *args, long long nargs);
+;; extern double win64_calld(FnPtr fn, void *args, long long nargs);
+;; extern SomeType win64_call_other(FnPtr fn, void *args, long long nargs);
+;; (all of these refer to the same actual function)
+;; With MSVC's calling convention, all arguments are treated as if they were 64-bit.
+;; This means you need to convert integer arguments to unsigned long long/uint64_t before using them.
+;; So if you have integer arguments, you probably want to pass an unsigned long long * for args.
+;; Floating point arguments can either be "reinterpreted" as unsigned long longs (see 2nd example), or
+;; you can pass a double *for args instead.
+;; &((unsigned long long *)args)[i] should be a pointer to the ith argument.
+;; If you have a 1, 2, 4, or 8 byte struct argument, convert it to an integer, then pass it (keep in mind that
+;; if your struct is 8 bytes but not aligned to 8 bytes, the *(uint64_t *)&x trick will cause an unaligned read).
+;; Otherwise, pass it by pointer.
+;; For returning structs: if your type is 1, 2, 4, or 8 bytes and is POD, it will be returned as an integer.
+;; Otherwise, you need to pass a pointer to the struct as the first argument.
+;; for more info see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
+;;So, if you want to call it:
+;; simple example (integer arguments):
+;; int foo(int a, int b, int c) {
+;; return a+b+c;
+;; }
+;; int main() {
+;; FnPtr fn = (FnPtr)foo;
+;; unsigned long long args[3] = {
+;; -1000, -3, 65
+;; };
+;; int ret = (int)win64_call(fn, args, 3);
+;; printf("%d\n", ret);
+;; }
+;; more involved example (with floating-point numbers):
+;; float bar(float a, double b, int c, double d, long e) {
+;; return a-(float)b + sinf((float)c) - (float)cos(d) + (float)e;
+;; }
+;; int main() {
+;; FnPtr fn = (FnPtr)bar;
+;; float a = -1.6f;
+;; double b = 3.0, d = 33.7;
+;; unsigned long long args[5] = {
+;; *(uint32_t *)&a, *(uint64_t *)&b, -12, *(uint64_t *)&d, 4
+;; };
+;; float ret = win64_callf(fn, args, 5);
+;; printf("%f\n", ret);
+;; }
+;;Why might you need this?
+;; Sometimes you don't know how many arguments you're gonna call a function with at compile time.
+;; For example, maybe you're making an interpreted programming language which calls out to C.
+;; (python uses libffi but that's not easy to compile...)
+;; Usually it will be with a function pointer you got from GetProcAddress.
+;;If you find a bug...
+;; Please let me know by emailing pommicket@pommicket.com.
+
+global win64_call
+global win64_callf
+global win64_calld
+global win64_call_other
+
+section .text
+
+; takes:
+; rcx - fn - pointer to function
+; rdx - args - pointer to arguments
+; r8 - nargs - number of arguments
+win64_call:
+win64_callf:
+win64_calld:
+win64_call_other:
+ ; use "shadow store" to save rsi
+ mov [rsp+24], rsi
+ mov rax, rcx ; function pointer (rcx may be overwritten)
+ mov r11, rdx ; args (rdx may be overwritten)
+ mov r10, r8 ; index_of_argument
+ mov rsi, rsp ; save original stack pointer
+
+ ; we need to make sure the stack pointer is aligned to 16 bytes when the function is called.
+ ; for some reason, even though we have to align it or stuff breaks, sometimes when
+ ; our function is called, it's not 16-byte aligned :/
+ ; find number of stack arguments:
+ cmp r8, 4
+ jg .align_stack
+ mov r8, 0 ; if there are <=4 arguments, set the number of stack arguments to 0
+.align_stack:
+ and r8, 1 ; is the number of stack arguments even or odd?
+ lea r8, [rsp+8*r8]
+ ; r8 is now equivalent to where the stack pointer will be (mod 16) when we call the function
+ and r8, 0xf ; take r8 mod 16
+ sub rsp, r8 ; align the stack pointer so when we call the function it's 16-byte aligned
+ lea r11, [r11+8*r10] ; go to end of arguments--we go from right to left
+ ; because that's the order things are pushed onto the stack
+
+ cmp r10, 0
+ je .loop_end ; no arguments
+.loop:
+ dec r10 ; --index_of_argument
+ sub r11, 8 ; --arg
+ cmp r10, 0
+ jg .after_1st
+; NOTE: we have to set both the integer and floating-point register for every argument because
+; a. we don't know if it's integer or floating point
+; b. varargs expects to have the value in both registers
+ ; 1st argument
+ mov rcx, qword [r11]
+ movsd xmm0, qword [r11]
+ jmp .continue
+.after_1st:
+ cmp r10, 1
+ jg .after_2nd
+ ; 2nd argument
+ mov rdx, qword [r11]
+ movsd xmm1, qword [r11]
+ jmp .continue
+.after_2nd:
+ cmp r10, 2
+ jg .after_3rd
+ ; 3rd argument
+ mov r8, qword [r11]
+ movsd xmm2, qword [r11]
+ jmp .continue
+.after_3rd:
+ cmp r10, 3
+ jg .after_4th
+ ; 4th argument
+ mov r9, qword [r11]
+ movsd xmm3, qword [r11]
+ jmp .continue
+.after_4th:
+ ; additional argument
+ push qword [r11]
+.continue:
+ cmp r10, 0 ; if index_of_argument > 0
+ jg .loop
+.loop_end:
+ sub rsp, 32 ; "shadow store"
+ call rax ; function pointer stored here before
+
+ mov rsp, rsi ; restore original stack pointer
+ ; restore rsi
+ mov rsi, [rsp+24]
+ ret
diff --git a/win64call_test.c b/win64call_test.c
new file mode 100644
index 0000000..f1950b5
--- /dev/null
+++ b/win64call_test.c
@@ -0,0 +1,162 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+
+Output should be:
+-12387387222 54873482123 4598345 -4
+1 returned: 54873482123
+Hello 5 6 7 8 9
+Hello 5 6 7 8 9 hey 19249488282934 -1
+2 returned: 38
+3 returned: 1.414214
+4 returned: 1.414214
+5.600000 -1.300000 2.000000 -6 2.000000 55 1200.000000
+5 returned: 4.300000
+6 returned: -1.600000
+7 returned: -938
+8 returned: 0.590889
+*/
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <windows.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+
+typedef void (*FnPtr)();
+extern uint64_t win64_call(FnPtr fn, void *args, int64_t nargs);
+extern float win64_callf(FnPtr fn, void *args, int64_t nargs);
+extern double win64_calld(FnPtr fn, void *args, int64_t nargs);
+float asdf(float a, double b, int c, double d, long e, float f) {
+ return (float)f;
+}
+void foobar(void) {
+ FnPtr fn = (FnPtr)asdf;
+ float a = -1.6f;
+ double b = 3.0, d = 33.7;
+ unsigned long long args[6] = {
+ *(uint32_t *)&a, *(uint64_t *)&b, -12, *(uint64_t *)&d, 4, *(uint32_t *)&a
+ };
+ float ret = win64_callf(fn, args, 6);
+ printf("6 returned: %f\n", ret);
+}
+
+uint64_t test_fn(long long a, uint64_t b, uint64_t c, int d) {
+ printf("%lld %llu %llu %d\n",a,b,c,d);
+ return b;
+}
+
+double test_fp(double a, double b, float c, int d, float e, int f, double g) {
+ printf("%f %f %f %d %f %d %f\n", a,b,c,d,e,f,g);
+ return a+b;
+}
+#define arr_size(a) (sizeof (a) / sizeof *(a))
+
+
+int foo(int a, int b, int c) {
+ return a+b+c;
+}
+void main1(void) {
+ FnPtr fn = (FnPtr)foo;
+ unsigned long long args[3] = {
+ -1000, -3, 65
+ };
+ int ret = (int)win64_call(fn, args, 3);
+ printf("7 returned: %d\n", ret);
+}
+float bar(float a, double b, int c, double d, long e) {
+ return a-(float)b + sinf((float)c) - (float)cos(d) + (float)e;
+}
+void main2(void) {
+ FnPtr fn = (FnPtr)bar;
+ float a = -1.6f;
+ double b = 3.0, d = 33.7;
+ unsigned long long args[5] = {
+ *(uint32_t *)&a, *(uint64_t *)&b, -12, *(uint64_t *)&d, 4
+ };
+ float ret = win64_callf(fn, args, 5);
+ printf("8 returned: %f\n", ret);
+}
+
+int main(void) {
+ uint64_t args[] = {-12387387222, 54873482123, 4598345, -4};
+ uint64_t x = win64_call(test_fn, args, arr_size(args));
+ printf("1 returned: %llu\n", x);
+
+ printf("Hello %d %d %d %d %d\n",5,6,7,8,9);
+
+
+ uint64_t args2[] = {(uint64_t)"Hello %d %d %d %d %d %s %llu %d\n", 5, 6, 7, 8, 9, (uint64_t)"hey", 19249488282934, -1};
+ uint64_t x2 = win64_call(printf, args2, arr_size(args2));
+ printf("2 returned: %llu\n",x2);
+
+#if 0
+ {
+ float a = 3.7f;
+ int b = 1;
+ int c = 2;
+ int d = 3;
+ float e = 4.5f;
+ double f = -1.2;
+ float ret = test_fp(a,b,c,d,e,f);
+ printf("%f\n",ret);
+ }
+#endif
+
+ double args3[] = {2.0};
+ double x3 = win64_calld(sqrt, args3, arr_size(args3));
+ printf("3 returned: %f\n",x3);
+
+ float two = 2.0f;
+
+ uint64_t args4[] = {*(uint32_t *)&two};
+ float x4 = win64_callf(sqrtf, args4, arr_size(args4));
+ printf("4 returned: %f\n",x4);
+
+ double num1 = 5.6;
+ double num2 = -1.3;
+ double num3 = 1200;
+ uint64_t args5[] = {
+ *(uint64_t *)&num1,
+ *(uint64_t *)&num2,
+ *(uint32_t *)&two,
+ -6,
+ *(uint32_t *)&two,
+ 55,
+ *(uint64_t *)&num3
+
+ };
+ double x5 = win64_calld(test_fp, args5, arr_size(args5));
+ printf("5 returned: %f\n",x5);
+
+ foobar();
+ main1();
+ main2();
+
+ return 0;
+
+}