Attept 64-bit MiniFFI on Windows

This commit is contained in:
Struma 2020-12-31 16:58:47 -05:00 committed by Roza
parent 7db1c1219e
commit 69514de7c6
5 changed files with 170 additions and 99 deletions

View file

@ -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 <SDL.h>
#include <cstdint>
#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"(&param), "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, &param, 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);
}
}

98
binding/miniffi.c Normal file
View file

@ -0,0 +1,98 @@
#include "miniffi.h"
#include <assert.h>
#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

32
binding/miniffi.h Normal file
View file

@ -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

View file

@ -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 = "<group>"; };
3B10EDF42568E96A00372D13 /* viewport-binding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "viewport-binding.cpp"; sourceTree = "<group>"; };
3B10EE1F2569348E00372D13 /* json5pp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json5pp.hpp; sourceTree = "<group>"; };
3B312841259E7DC1002EAB43 /* miniffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = miniffi.h; sourceTree = "<group>"; };
3B312842259E7DC1002EAB43 /* miniffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = miniffi.c; sourceTree = "<group>"; };
3B426F6B256B8AC0009EA00F /* fs_std_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_std_impl.hpp; sourceTree = "<group>"; };
3B426F6C256B8AC0009EA00F /* fs_fwd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_fwd.hpp; sourceTree = "<group>"; };
3B426F6D256B8AC0009EA00F /* fs_std.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fs_std.hpp; sourceTree = "<group>"; };
@ -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 */,

View file

@ -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