This is far from trivial, since x86-64 uses register passing for arguments [and it's a rather ugly solution in the first place, since it's basically assuming no arguments are passed in registers, and that the callee function takes all arguments on the stack].
I would probably avoid the assembly version altogether, and instead of the second for-loop (with the assembly code) write something like:
switch(nArgs)
{
case 0:
(*funcptr)();
break;
case 1:
(*funcptr)(fptrs[0]);
break;
case 2:
(*funcptr)(fptrs[0], fptrs[1]);
break;
... Repeat until MAX_FUNCTION_ARGS is covered.
}
It is unlikely to generate terribly bad code unless MAX_FUNCTION_ARGS is VERY large [in which case you probably want to change the calling convention of funcptr
in the first place].