Также как пролог функции подготавливает для нее окружение, вызов функции позволяет ей принимать аргументы, и при завершении, возвратиться в вызывающую функцию.
Перед вызовом функции, аргументы, ей необходимые, сохраняются в стек. В нашем примере вначале в стек помещаются два постоянных целых 1 и 2, начиная с последнего. Регистр %eip содержит адрес следующей инструкции для выполнения, в нашем случае - вызова функции.
При исполнении инструкции call, %eip принимает значение адреса последующей инструкции, расположеной ниже на 5 байт (инструкция call занимает 5 байт - не все инструкции используют столько же места, размер зависит от центрального процессора). call сохраняет адрес, содержащийся в %eip, для того чтобы была возможность вернуться к выполнению после работы функции. Это "резервная копия" делается неявной инструкцией, которая помещает регистр в стек:
push %eip
Значение данное call в качестве аргумента, соответствует адресу первой инструкции в прологе функции toto(). Этот адрес затем копируется в %eip, таким образом следующей инструкцией для выполнения будет инструкция, расположенная по этому адресу.
Оказавшись в теле функции, ее аргументы и адрес возврата
имеют положительное смещение по отношению к %ebp, так
как следующая инструкция помещает этот регистр на вершину стека. Инструкция
j=0 в функции toto() иллюстрирует это. Ассемблерный
код опять использует косвенную адресацию для доступа к j:
0x80483ed <toto+29>: movl $0x0,0xc(%ebp)
Шеснадцатиричное 0xc представляет целое +12.
Запись обозначает: поместить значение 0 в переменную, отстоящую от
регистра %ebp на "+12 байт". j - второй аргумент
функции, он находится на 12 байт "выше" регистра %ebp (4 для копии
указателя инструкции, 4 для первого аргумента и 4 для второго - сравните с
первой диаграммой в секции возврата)