inspired by @pinskia mentioning musttail
, today I learned that you can implement state machines in C such that state transitions are implemented as calls:
#include <stdlib.h>
#include <stdio.h>
#define VOID __attribute__((noinline)) void
#define JUMP [[clang::musttail]] return
static char *input;
static int acc = 0;
static int state = 0;
VOID initial_state(void);
VOID digit(void) {
acc += *(input++) - '0';
JUMP initial_state();
}
VOID separator(void) {
state = acc;
acc = 0;
input++;
JUMP initial_state();
}
VOID add(void) {
state += acc;
acc = 0;
input++;
JUMP initial_state();
}
VOID minus(void) {
state -= acc;
acc = 0;
input++;
JUMP initial_state();
}
VOID initial_state(void) {
switch (*input) {
case '0'...'9':
JUMP digit();
case ' ':
JUMP separator();
case '+':
JUMP add();
case '-':
JUMP minus();
default:
printf("result: %d\n", state);
exit(0);
}
}
int main(int argc, char **argv) {
puts("welcome to my calculator");
input = argv[1];
initial_state();
}
compiles to stuff like this, all jumps:
add:
mov eax, dword ptr [rip + acc]
add dword ptr [rip + state], eax
mov dword ptr [rip + acc], 0
inc qword ptr [rip + input]
jmp initial_state
And the security benefits are obvious! The less stack you have, the less potential for the stack pointer being hijacked! 