mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-06-30 21:55:18 +02:00
Attept 64-bit MiniFFI on Windows
This commit is contained in:
parent
7db1c1219e
commit
69514de7c6
5 changed files with 170 additions and 99 deletions
|
@ -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"(¶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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
98
binding/miniffi.c
Normal file
98
binding/miniffi.c
Normal 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
32
binding/miniffi.h
Normal 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
|
|
@ -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 */,
|
||||
|
|
10
meson.build
10
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
|
||||
|
|
Loading…
Add table
Reference in a new issue