Last active
January 24, 2020 12:55
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
Related code: https://github.com/kosh04/newlisp/blob/9eb8f27de842ebe96e8a6f8e631ffd3fa37d4611/nl-import.c#L248-L390