дизассемблерный листинг исходной функции f с мыщъх'иными комментариями
Содержимое стека на момент вызова f() представляет конгломерат локальных переменных и служебных данных. На вершине стека лежит буфер, под ним располагается целочисленная переменная "a" (на самом деле, порядок размещения переменных не стандартизован и целиком зависит от воли компилятора, то есть может быть любым). За локальными переменными следует сохраненный регистр указателя карда стека (в x86 процессорах его роль обычно играет EBP), а за ним — адрес возврата и аргументы, переданные функции. Короче говоря, все это выглядит так:
[ buf ] ; ß переполняющийся буфер
[ a ] ; ß прочие локальные переменные
[ ebp ] ; ß сохраненный указатель кадра
[ retaddr ] ; ß адрес возврата в материнскую функцию
[ arg 1 ] ; ß аргументы, переданные функции
[ --------- ] ; ß \
[ --------- ] ; ß +- кадр стека материнской функции
[ --------- ] ; ß /