Files
FEX-Emu--FEX/ThunkLibs/include/common/Host.h
T
Tony Wasserka 1c86f7ed36 Thunks/gen: Support annotating guest-exclusive function pointers
Function pointer arguments given to the guest thunk library aren't
callable on the host, so they need special handling on a case-by-case
basis. Similar problems arise when the guest-side tries to consume a
pointer returned from a native host library. To automate some common
scenarios, this change adds two new annotations:

"callback_guest" indicates the callback parameter is never called on the
host and hence can be marshalled like any other argument. Accidental host
calls to the function pointer are prevented by wrapping it in an opaque
type alias.

"returns_guest_pointer" indicates that the host function returns a pointer
usable in the guest context. This applies e.g. to functions that derive
the returned pointer from input guest pointer arguments.
2021-12-10 11:24:58 +01:00

89 lines
2.1 KiB
C++

/*
$info$
category: thunklibs ~ These are generated + glue logic 1:1 thunks unless noted otherwise
$end_info$
*/
#pragma once
#include <stdint.h>
template<typename Fn>
struct function_traits;
template<typename Result, typename Arg>
struct function_traits<Result(*)(Arg)> {
using result_t = Result;
using arg_t = Arg;
};
template<auto Fn>
static typename function_traits<decltype(Fn)>::result_t
fexfn_type_erased_unpack(void* argsv) {
using args_t = typename function_traits<decltype(Fn)>::arg_t;
return Fn(reinterpret_cast<args_t>(argsv));
}
struct ExportEntry { uint8_t* sha256; void(*fn)(void *); };
typedef void fex_call_callback_t(uintptr_t callback, void *arg0, void* arg1);
static fex_call_callback_t* call_guest;
/**
* Opaque wrapper around a guest function pointer.
*
* This prevents accidental calls to foreign function pointers while still
* allowing us to label function pointers as such.
*/
struct fex_guest_function_ptr {
private:
void* value = nullptr;
public:
fex_guest_function_ptr() = default;
template<typename Ret, typename... Args>
fex_guest_function_ptr(Ret (*ptr)(Args...)) : value(reinterpret_cast<void*>(ptr)) {}
};
#define EXPORTS(name) \
extern "C" { \
ExportEntry* fexthunks_exports_##name(void *a0, uintptr_t a1) { \
call_guest = (fex_call_callback_t*)a0; \
if (!fexldr_init_##name()) { \
return nullptr; \
} \
return exports; \
} \
}
#define EXPORTS_INIT(name, init_fn) \
extern "C" { \
ExportEntry* fexthunks_exports_##name(void *a0, uintptr_t a1) { \
call_guest = (fex_call_callback_t*)a0; \
if (!fexldr_init_##name()) { \
return nullptr; \
} \
init_fn (); \
return exports; \
} \
}
#define EXPORTS_WITH_CALLBACKS(name) \
extern "C" { \
ExportEntry* fexthunks_exports_##name(void *a0, uintptr_t a1) { \
call_guest = (fex_call_callback_t*)a0; \
(uintptr_t&)callback_unpacks = a1; \
if (!fexldr_init_##name()) { \
return nullptr; \
} \
return exports; \
} \
}
#define LOAD_LIB_INIT(init_fn) \
__attribute__((constructor)) static void loadlib() \
{ \
init_fn (); \
}