99 lines
2.6 KiB
C
99 lines
2.6 KiB
C
#ifndef __VHEX_DEFS_CALL__
|
|
# define __VHEX_DEFS_CALL__
|
|
|
|
#include <vhex/defs/types.h>
|
|
|
|
/* vhex_call_arg_t: All types of arguments allowed in an indirect call
|
|
|
|
Because a function call cannot be easily pieced together, there are
|
|
restrictions on what arguments can be passed. The following union lists all
|
|
of the available types. Other types can be used if casted, mainly pointers;
|
|
see the description of VHEX_CALL() for details. */
|
|
typedef union {
|
|
/* 32-bit integers */
|
|
int i;
|
|
unsigned int u;
|
|
int32_t i32;
|
|
uint32_t u32;
|
|
uintptr_t up32;
|
|
intptr_t ip32;
|
|
/* 32-bit floating-point */
|
|
float f;
|
|
|
|
/* Pointers to most common types, in all possible const/volatile
|
|
qualifications */
|
|
#define POINTER(type, name) \
|
|
type *name; \
|
|
type const *name ## _c; \
|
|
type volatile *name ## _v; \
|
|
type volatile const *name ## _cv;
|
|
|
|
POINTER(void, pv)
|
|
POINTER(char, pc)
|
|
POINTER(unsigned char, puc)
|
|
POINTER(short, ps)
|
|
POINTER(unsigned short, pus)
|
|
POINTER(int, pi)
|
|
POINTER(unsigned int, pui)
|
|
POINTER(int8_t, pi8)
|
|
POINTER(uint8_t, pu8)
|
|
POINTER(int16_t, pi16)
|
|
POINTER(uint16_t, pu16)
|
|
POINTER(int32_t, pi32)
|
|
POINTER(uint32_t, pu32)
|
|
POINTER(int64_t, pi64)
|
|
POINTER(uint64_t, pu64)
|
|
POINTER(long long int, pll)
|
|
POINTER(unsigned long long int, pull)
|
|
POINTER(float, pf)
|
|
POINTER(double, pd)
|
|
|
|
#undef POINTER
|
|
} vhex_call_arg_t;
|
|
|
|
/* vhex_call_t: Indirect call with up to 4 register arguments */
|
|
struct vhex_call {
|
|
void *function;
|
|
vhex_call_arg_t args[4];
|
|
};
|
|
typedef struct vhex_call vhex_call_t;
|
|
|
|
/* VHEX_CALL(): Build an callback from function and arguments */
|
|
#define VHEX_CALL(fct, ...) \
|
|
(vhex_call_t){ \
|
|
.function = (void*)fct, \
|
|
.args = { __VA_OPT__(VHEX_CALL_ARGS1(__VA_ARGS__)) } \
|
|
}
|
|
#define VHEX_CALL_ARGS1(a1, ...) \
|
|
(vhex_call_arg_t)(a1), __VA_OPT__(VHEX_CALL_ARGS2(__VA_ARGS__))
|
|
#define VHEX_CALL_ARGS2(a2, ...) \
|
|
(vhex_call_arg_t)(a2), __VA_OPT__(VHEX_CALL_ARGS3(__VA_ARGS__))
|
|
#define VHEX_CALL_ARGS3(a3, ...) \
|
|
(vhex_call_arg_t)(a3), __VA_OPT__(VHEX_CALL_ARGS4(__VA_ARGS__))
|
|
#define VHEX_CALL_ARGS4(a4, ...) \
|
|
({ \
|
|
__VA_OPT__( \
|
|
_Static_assert( \
|
|
0, \ \
|
|
"VHEX_CALL: too many arguments (maximum 4)" \
|
|
); \
|
|
) \
|
|
(vhex_call_arg_t)(a4); \
|
|
})
|
|
|
|
/* VHEX_CALL_NULL: Empty function call */
|
|
#define VHEX_CALL_NULL ((vhex_call_t){ .function = NULL, .args = {} })
|
|
|
|
/* vhex_call(): Perform an indirect call */
|
|
static VINLINE int vhex_call(vhex_call_t callback)
|
|
{
|
|
return ((int(*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t))callback.function)(
|
|
callback.args[0].up32,
|
|
callback.args[1].up32,
|
|
callback.args[2].up32,
|
|
callback.args[3].up32
|
|
);
|
|
}
|
|
|
|
#endif /* __VHEX_DEFS_CALL__ */
|