Как работает вызов функции?

Стандарт ничего такого не описывает, конечно. Но даже не говоря о конкретных реализациях, вызовы функций по своей природе образуют стек: last in first out. Если код функции вызывает другую функцию, нужно переключиться на эту вторую, вычислить её значение, и вернуться к коду первой функции.

Можно представить себе, что при вызове функции выделяются какие-то ресурсы (например, память для локальных переменных), а также запоминается место возврата - в какую точку программы нужно вернуться после выполнения функции. (Programmers don't die, they GOSUB without RETURN.

). После завершения ресурсы освобождаются и программа переходит в указанную точку. Если вызовов очень много, ресурсов приходится тоже выделять много, и получается stack overflow.

Хвостовая рекурсия - это хак, когда вызов не просто добавляется в верхушку стека, а заменяет её.

В сикпе написано весьма подробно.