Нет требования для конкретного соглашения о вызовах, которое будет использоваться в коде сборки, сгенерированном компилятором. Вот почему это называется соглашение , а не требование: -)
В любом случае вам следует помнить, что для «нормального» соглашения о вызовах x86 для C требуется, чтобы сама функция выполняла настройку и удаление кадра стека. Другими словами, это ответственность main
вместо кода запуска (код, который обычно запускается до вашего main
для настройки среды выполнения C, такой как настройка стека, создание argc/argv
, любая предварительная инициализация библиотеки и т. д.).
Кроме того, ebp
, помещенный в стек, равен предыдущему значению ebp
до построения текущего кадра стека.
Частью этого процесса сборки для текущего фрейма стека является сохранение текущего ebp, а затем загрузка нового значения в регистр ebp
для легкого доступа к переданным параметрам и локальным объектам.
Это можно увидеть, скомпилировав фрагмент кода с помощью gcc -S
:
main:
pushl %ebp ; Push PREVIOUS ebp.
movl %esp, %ebp ; Load ebp for variable access.
subl $16, %esp ; Allocate space on stack.
movb $97, -1(%ebp) ; Store 'a' into variable.
leave ; Tear down frame and return.
ret
Первые три строки и последние две являются зеркальными отображениями друг друга, кода установки и разрыва. В этом случае велика вероятность того, что для кода запуска было установлено значение ebp
равное нулю, возможно, потому, что ему было все равно - ему не нужно беспокоиться о соглашениях о вызовах, за исключением того, что argc
и argv
существуют. .