Some modern CPU's now have control flow enforcement. Here's how it works on Intel CPU's:
"The shadow stack stores a copy of the return address of each CALL. On a RET, the processor checks if the return address stored in the normal stack and shadow stack are equal. If the addresses are not equal, the processor generates an INT #21 (Control Flow Protection Fault)." So the two instructions being monitored by the central processing unit are CALL and RET. The CALL instruction can be broken into two instructions. The following instruction: call rax can be turned into: push rip+2 jmp rax Similarly the RET instruction can be turned into: pop r11 jmp r11 Therefore, if you want to compile a source file to an object file replacing all call's with push+jmp, and all ret's with pop+jmp, then the GNU compiler could have a new command line option: gcc -o frog.o -c frog.c --call-push-jmp An alternative would be to have a new function attribute called "call_push_jmp" as follows: extern int Func(int, double) __attribute__((call_push_jmp)); This would allow us to get around the control-flow enforcement (such as when debugging, or when intercepting a function call).