diff --git a/binding/miniffi-binding.cpp b/binding/miniffi-binding.cpp index 85ac89e1..952e4464 100644 --- a/binding/miniffi-binding.cpp +++ b/binding/miniffi-binding.cpp @@ -1,12 +1,25 @@ // Most of the MiniFFI class was taken from Ruby 1.8's Win32API.c, // it's just as basic but should work fine for the moment -#include "fake-api.h" +#include "system/fake-api.h" #include #include +#include "miniffi.h" #include "binding-util.h" -#include "debugwriter.h" + +#if defined(__linux__) || defined(__APPLE__) + #define MVAL2RB(v) ULONG2NUM(v) + #define RB2MVAL(v) (mffi_value)NUM2ULONG(v) +#else + #ifdef _WIN64 + #define MVAL2RB(v) ULL2NUM(v) + #define RB2MVAL(v) (mffi_value)NUM2ULL(v) + #else + #define MVAL2RB(v) UINT2NUM(v) + #define RB2MVAL(v) (mffi_value)NUM2UINT(v) + #endif +#endif #define _T_VOID 0 #define _T_NUMBER 1 @@ -14,40 +27,6 @@ #define _T_INTEGER 3 #define _T_BOOL 4 -#ifndef __WIN32__ -#define MINIFFI_MAX_ARGS 8l -#else -#define MINIFFI_MAX_ARGS 32l -#endif - -#define INTEL_ASM ".intel_syntax noprefix\n" - -// Might need to let MiniFFI.initialize set calling convention -// as an optional arg, this won't work with everything -// Maybe libffi would help out with this - -// Only using 8 max args instead of 16 to reduce the time taken -// to set all those variables up and ease the eyesore, and I don't -// think there are many functions one would need to use that require -// that many arguments anyway - -typedef struct { - unsigned long params[MINIFFI_MAX_ARGS]; -} MiniFFIFuncArgs; - -#ifndef __WIN32__ -// L O N G, but variables won't get set up correctly otherwise -// should allow for __fastcalls (macOS likes these) and whatever else -typedef PREFABI void *(*MINIFFI_FUNC)(unsigned long, unsigned long, - unsigned long, unsigned long, - unsigned long, unsigned long, - unsigned long, unsigned long); -#else -typedef PREFABI void *(*MINIFFI_FUNC)(...); -#endif -// MiniFFI class, also named Win32API on Windows -// Uses LoadLibrary/GetProcAddress on Windows, dlopen/dlsym everywhere else - #if RAPI_FULL > 187 DEF_TYPE_CUSTOMFREE(MiniFFI, SDL_UnloadObject); #else @@ -115,7 +94,7 @@ RB_METHOD(MiniFFI_initialize) { if (!hfunc) rb_raise(rb_eRuntimeError, "%s", SDL_GetError()); - rb_iv_set(self, "_func", ULONG2NUM((unsigned long)hfunc)); + rb_iv_set(self, "_func", MVAL2RB((mffi_value)hfunc)); rb_iv_set(self, "_funcname", func); rb_iv_set(self, "_libname", libname); @@ -251,7 +230,7 @@ RB_METHOD(MiniFFI_call) { if (NIL_P(str)) { lParam = 0; } else if (FIXNUM_P(str)) { - lParam = NUM2ULONG(str); + lParam = RB2MVAL(str); } else { StringValue(str); rb_str_modify(str); @@ -265,70 +244,22 @@ RB_METHOD(MiniFFI_call) { case _T_INTEGER: #if INTPTR_MAX == INT64_MAX - lParam = NUM2UINT(rb_ary_entry(args, i)) & UINT32_MAX; + lParam = RB2MVAL(rb_ary_entry(args, i)) & UINT32_MAX; break; #endif case _T_NUMBER: default: - lParam = NUM2ULONG(rb_ary_entry(args, i)); + lParam = RB2MVAL(rb_ary_entry(args, i)); break; } params[i] = lParam; } -#ifndef __WINDOWS__ - unsigned long ret = - (unsigned long)ApiFunction(params[0], params[1], params[2], params[3], - params[4], params[5], params[6], params[7]); - -// Telling the compiler that the called function uses stdcall -// apparently doesn't work anymore, so assembly is used instead. -// Technically also allows for an unlimited number of arguments, -// but the above code does not -#else - unsigned long ret = 0; - void *old_esp = 0; - - asm volatile(INTEL_ASM - - "MiniFFI_call_asm:\n" - "mov [edi], esp\n" - "test ebx, ebx\n" - "jz mffi_call_void\n" - - "shl ebx, 2\n" - "mov ecx, ebx\n" - - "mffi_call_loop:\n" - "sub ecx, 4\n" - "mov ebx, [esi+ecx]\n" - "push ebx\n" - "test ecx, ecx\n" - "jnz mffi_call_loop\n" - - "mffi_call_void:\n" - "call edx\n" - - : "=a"(ret) - : "b"(nimport), "S"(¶m), "d"(ApiFunction), "D"(&old_esp) - : "ecx"); - - - // If esp doesn't match, this was probably a cdecl and not a stdcall. - // Move the stack pointer back to where it should be - asm volatile(INTEL_ASM - "mov edx, [edi]\n" - "cmp edx, esp\n" - "cmovne esp, edx" - : - : "D"(&old_esp) - : "edx" - ); -#endif + mffi_value ret = miniffi_call_intern(ApiFunction, ¶m, nimport); switch (FIX2INT(own_exports)) { case _T_NUMBER: case _T_INTEGER: - return ULONG2NUM(ret); + return MVAL2RB(ret); case _T_POINTER: return rb_str_new_cstr((char *)ret); @@ -338,7 +269,7 @@ RB_METHOD(MiniFFI_call) { case _T_VOID: default: - return ULONG2NUM(0); + return MVAL2RB(0); } } diff --git a/binding/miniffi.c b/binding/miniffi.c new file mode 100644 index 00000000..d724ee95 --- /dev/null +++ b/binding/miniffi.c @@ -0,0 +1,98 @@ +#include "miniffi.h" +#include + +#if defined(__linux__) || defined(__APPLE__) +mffi_value miniffi_call_intern(MINIFFI_FUNC target, MiniFFIFuncArgs *p, int nparams) { + assert(nparams <= 8); + return target(p->params[0], p->params[1], p->params[2], p->params[3], + p->params[4], p->params[5], p->params[6], p->params[7]); +} +#else +mffi_value miniffi_call_intern(MINIFFI_FUNC target, MiniFFIFuncArgs *params, size_t nparams) { + return call_asm(target, params, nparams); +} + +#define INTEL_ASM ".intel_syntax noprefix\n" +#ifdef _WIN32 +mffi_value call_asm(MINIFFI_FUNC target, MINIFFIFuncArgs *params, size_t nparams) { + mffi_value ret; + void *old_esp = 0; + + asm volatile(INTEL_ASM + + "MiniFFI_call_asm:\n" + "mov [edi], esp\n" + "test ebx, ebx\n" + "jz mffi_call_void\n" + + "shl ebx, 2\n" + "mov ecx, ebx\n" + + "mffi_call_loop:\n" + "sub ecx, 4\n" + "mov ebx, [esi+ecx]\n" + "push ebx\n" + "test ecx, ecx\n" + "jnz mffi_call_loop\n" + + "mffi_call_void:\n" + "call edx\n" + + : "=a"(ret) + : "b"(nparams), "S"(params), "d"(target), "D"(&old_esp) + : "ecx" + ); + + + // If esp doesn't match, this was probably a cdecl and not a stdcall. + // Move the stack pointer back to where it should be + asm volatile(INTEL_ASM + "mov edx, [edi]\n" + "cmp edx, esp\n" + "cmovne esp, edx" + : + : "D"(&old_esp) + : "edx" + ); + return ret; +} +#else +mffi_value call_asm(MINIFFI_FUNC target, MINIFFIFuncArgs *params, size_t nparams) { + mffi_value ret; + void *old_rsp = 0; + asm volatile(INTEL_ASM + + "MiniFFI_call_asm:\n" + "mov [rdi], rsp\n" + "test rbx, rbx\n" + "jz mffi_call_void\n" + + "shl rbx, 2\n" + "mov rcx, rbx\n" + + "mffi_call_loop:\n" + "sub rcx, 4\n" + "mov rbx, [rsi+rcx]\n" + "push rbx\n" + "test rcx, rcx\n" + "jnz mffi_call_loop\n" + + "mffi_call_void:\n" + "call rdx\n" + + : "=a"(ret) + : "b"(nparams), "S"(params), "d"(target), "D"(&old_rsp) + : "rcx" + ); + asm volatile(INTEL_ASM + "mov rdx, [rdi]\n" + "cmp rdx, rsp\n" + "cmovne rsp, rdx" + : + : "D"(&old_rsp) + : "rdx" + ); + return ret; +} +#endif +#endif diff --git a/binding/miniffi.h b/binding/miniffi.h new file mode 100644 index 00000000..e21a937f --- /dev/null +++ b/binding/miniffi.h @@ -0,0 +1,32 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__linux__) || defined(__APPLE__) + #define MINIFFI_MAX_ARGS 8l + typedef unsigned long mffi_value; + typedef mffi_value (*MINIFFI_FUNC)(mffi_value, mffi_value, + mffi_value, mffi_value, + mffi_value, mffi_value, + mffi_value, mffi_value); +#else // Windows + #define MINIFFI_MAX_ARGS 32l + #ifdef _WIN64 + typedef uint64_t mffi_value; + #else + typedef uint32_t mffi_value; + #endif + typedef mffi_value (*MINIFFI_FUNC)(...); +#endif + +typedef struct { + mffi_value params[MINIFFI_MAX_ARGS]; +} MiniFFIFuncArgs; + +mffi_value miniffi_call_intern(MINIFFI_FUNC target, MiniFFIFuncArgs *p, int nparams); + +#ifdef __cplusplus +} +#endif diff --git a/macos/mkxp-z.xcodeproj/project.pbxproj b/macos/mkxp-z.xcodeproj/project.pbxproj index baf2ca5f..a72dd4db 100644 --- a/macos/mkxp-z.xcodeproj/project.pbxproj +++ b/macos/mkxp-z.xcodeproj/project.pbxproj @@ -117,6 +117,12 @@ 3B10EE092568E96A00372D13 /* binding-mri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF02568E96A00372D13 /* binding-mri.cpp */; }; 3B10EE0B2568E96A00372D13 /* module_rpg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF32568E96A00372D13 /* module_rpg.cpp */; }; 3B10EE0C2568E96A00372D13 /* viewport-binding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF42568E96A00372D13 /* viewport-binding.cpp */; }; + 3B312843259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; + 3B312844259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; + 3B312845259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; + 3B312846259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; + 3B312847259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; + 3B312848259E7DC1002EAB43 /* miniffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 3B312842259E7DC1002EAB43 /* miniffi.c */; }; 3B426F77256BA847009EA00F /* libsigc-2.0.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B426F76256BA847009EA00F /* libsigc-2.0.a */; }; 3B522DA9259BAA42003301C4 /* libfluidsynth.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B522DA1259BAA13003301C4 /* libfluidsynth.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 3B522DAA259BAA4A003301C4 /* libfluidsynth.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B522DA1259BAA13003301C4 /* libfluidsynth.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -1159,6 +1165,8 @@ 3B10EDF32568E96A00372D13 /* module_rpg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = module_rpg.cpp; sourceTree = ""; }; 3B10EDF42568E96A00372D13 /* viewport-binding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "viewport-binding.cpp"; sourceTree = ""; }; 3B10EE1F2569348E00372D13 /* json5pp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json5pp.hpp; sourceTree = ""; }; + 3B312841259E7DC1002EAB43 /* miniffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = miniffi.h; sourceTree = ""; }; + 3B312842259E7DC1002EAB43 /* miniffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = miniffi.c; sourceTree = ""; }; 3B426F6B256B8AC0009EA00F /* fs_std_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_std_impl.hpp; sourceTree = ""; }; 3B426F6C256B8AC0009EA00F /* fs_fwd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_fwd.hpp; sourceTree = ""; }; 3B426F6D256B8AC0009EA00F /* fs_std.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_std.hpp; sourceTree = ""; }; @@ -1814,6 +1822,8 @@ 3B10EDE62568E96A00372D13 /* etc-binding.cpp */, 3B10EDE72568E96A00372D13 /* tilemap-binding.cpp */, 3B10EDE82568E96A00372D13 /* miniffi-binding.cpp */, + 3B312842259E7DC1002EAB43 /* miniffi.c */, + 3B312841259E7DC1002EAB43 /* miniffi.h */, 3B10EDE92568E96A00372D13 /* graphics-binding.cpp */, 3B10EDEA2568E96A00372D13 /* plane-binding.cpp */, 3B10EDEB2568E96A00372D13 /* binding-types.h */, @@ -2335,6 +2345,7 @@ 3B8E43752587B200008218FC /* windowvx.cpp in Sources */, 3B522DEA259C2039003301C4 /* LUrlParser.cpp in Sources */, 3B8E43762587B200008218FC /* module_rpg.cpp in Sources */, + 3B312848259E7DC1002EAB43 /* miniffi.c in Sources */, 3B8E43772587B200008218FC /* autotiles.cpp in Sources */, 3B8E43782587B200008218FC /* audiostream.cpp in Sources */, 3B8E43792587B200008218FC /* binding-util.cpp in Sources */, @@ -2429,6 +2440,7 @@ 3BC65CE52584EDC60063AFF1 /* windowvx.cpp in Sources */, 3B522DE7259C2039003301C4 /* LUrlParser.cpp in Sources */, 3BC65CE62584EDC60063AFF1 /* module_rpg.cpp in Sources */, + 3B312845259E7DC1002EAB43 /* miniffi.c in Sources */, 3BC65CE72584EDC60063AFF1 /* autotiles.cpp in Sources */, 3BC65CE82584EDC60063AFF1 /* audiostream.cpp in Sources */, 3BC65CE92584EDC60063AFF1 /* binding-util.cpp in Sources */, @@ -2516,6 +2528,7 @@ 3BC65DA62584F3AD0063AFF1 /* windowvx.cpp in Sources */, 3B522DE5259C2039003301C4 /* LUrlParser.cpp in Sources */, 3BC65DA72584F3AD0063AFF1 /* module_rpg.cpp in Sources */, + 3B312843259E7DC1002EAB43 /* miniffi.c in Sources */, 3BC65DA82584F3AD0063AFF1 /* autotiles.cpp in Sources */, 3BC65DA92584F3AD0063AFF1 /* audiostream.cpp in Sources */, 3BC65DAA2584F3AD0063AFF1 /* binding-util.cpp in Sources */, @@ -2603,6 +2616,7 @@ 3B10EDBC2568E95E00372D13 /* windowvx.cpp in Sources */, 3B522DE6259C2039003301C4 /* LUrlParser.cpp in Sources */, 3B10EE0B2568E96A00372D13 /* module_rpg.cpp in Sources */, + 3B312844259E7DC1002EAB43 /* miniffi.c in Sources */, 3B10EDD22568E95E00372D13 /* autotiles.cpp in Sources */, 3B10EDB92568E95E00372D13 /* audiostream.cpp in Sources */, 3B10EE082568E96A00372D13 /* binding-util.cpp in Sources */, @@ -2690,6 +2704,7 @@ 3BF694F02595FE5F0016920C /* windowvx.cpp in Sources */, 3B522DE9259C2039003301C4 /* LUrlParser.cpp in Sources */, 3BF694F12595FE5F0016920C /* module_rpg.cpp in Sources */, + 3B312847259E7DC1002EAB43 /* miniffi.c in Sources */, 3BF694F22595FE5F0016920C /* autotiles.cpp in Sources */, 3BF694F32595FE5F0016920C /* audiostream.cpp in Sources */, 3BF694F42595FE5F0016920C /* binding-util.cpp in Sources */, @@ -2777,6 +2792,7 @@ 3BF6958E259608050016920C /* windowvx.cpp in Sources */, 3B522DE8259C2039003301C4 /* LUrlParser.cpp in Sources */, 3BF6958F259608050016920C /* module_rpg.cpp in Sources */, + 3B312846259E7DC1002EAB43 /* miniffi.c in Sources */, 3BF69590259608050016920C /* autotiles.cpp in Sources */, 3BF69591259608050016920C /* audiostream.cpp in Sources */, 3BF69592259608050016920C /* binding-util.cpp in Sources */, diff --git a/meson.build b/meson.build index f5dd318a..539f7aaf 100644 --- a/meson.build +++ b/meson.build @@ -93,14 +93,8 @@ endif # Decide whether or not to use MiniFFI miniffi = get_option('use_miniffi') if miniffi == true - if win64 != true - miniffi = true - global_args += '-DMKXPZ_MINIFFI' - else - warning('64-bit MiniFFI is only supported on Linux and macOS.') - warning('To use MiniFFI/Win32API on Windows, target 32-bit.') - miniffi = false - endif + miniffi = true + global_args += '-DMKXPZ_MINIFFI' endif # Defines