If you don't use the standard library, and you don't need JIT, you can simply not use pointers to callbacks. You can still have something like qsort() but you need to have statically defined:
typedef void*(*callback)(...);extern const callback callbacks[256];
and qsort() takes an index instead of a raw pointer to a callback. "Validating" a callback is cheap: Just make sure it's <256 (how many do you need anyway?).
If you don't do an unchecked call*
or a jmp*
then you don't have anything an attacker can exploit, and I find it hard to believe a cached load is going to be slower than something like this.