Skip to content

Instantly share code, notes, and snippets.

@ComFreek
Last active January 24, 2020 12:55
Show Gist options
  • Save ComFreek/5c7bfc94e6e24f1249add84998caf36a to your computer and use it in GitHub Desktop.
Save ComFreek/5c7bfc94e6e24f1249add84998caf36a to your computer and use it in GitHub Desktop.
Call a C function with arguments given as array (also known as fun.apply in JavaScript or PHP)
// Only works with System V AMD64 ABI (e.g. if you compile your code to 64-bit targetting Linux)
typedef uint64_t fun_arg_t;
/**
* Call a function with given arguments.
*
* This requires System V AMD64 ABI compilation for this function as well as the called function.
*
* @param fun Pointer to the function
* @param args The arguments, must be at most 6
* @param arg_count The number of actual arguments (0 <= arg_count <= 6)
* @return The return value of the called function. If the function had a void return type, it is unspecified what this function returns.
*/
static inline uint64_t call_function(void *fun, fun_arg_t *args, size_t arg_count) {
// In the System V AMD64 ABI only the first 6 arguments will be passed via registers
// And only for arguments passed via registers, it doesn't matter if we pretend the function pointer
// to have fun_arg_t parameters or, say, uint8_t parameters! They will all be extended to
// 64 bits.
assert(arg_count <= 6);
typedef uint64_t (*fun_ptr0)(void);
typedef uint64_t (*fun_ptr1)(fun_arg_t);
typedef uint64_t (*fun_ptr2)(fun_arg_t, fun_arg_t);
typedef uint64_t (*fun_ptr3)(fun_arg_t, fun_arg_t, fun_arg_t);
typedef uint64_t (*fun_ptr4)(fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t);
typedef uint64_t (*fun_ptr5)(fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t);
typedef uint64_t (*fun_ptr6)(fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t, fun_arg_t);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
switch (arg_count) {
case 0:
return ((fun_ptr0) fun)();
case 1:
return ((fun_ptr1) fun)(args[0]);
case 2:
return ((fun_ptr2) fun)(args[0], args[1]);
case 3:
return ((fun_ptr3) fun)(args[0], args[1], args[2]);
case 4:
return ((fun_ptr4) fun)(args[0], args[1], args[2], args[3]);
case 5:
return ((fun_ptr5) fun)(args[0], args[1], args[2], args[3], args[4]);
case 6:
return ((fun_ptr6) fun)(args[0], args[1], args[2], args[3], args[4], args[5]);
default:
assert(0);
}
#pragma GCC diagnostic pop
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment