Каждый C (кроме некоторых функций inline
, а не только функций C) имеет начало и завершение. Начало обычно выглядит следующим образом:
push ebp
mov ebp, esp
sub esp, x
Первая строка подталкивает старые стековые рамки. Поскольку во время работы программы есть много функций, функции могут сохранять стек стека в стеке при вызове другой функции. Рамка стека (обычно хранится в регистре EBP
) - это то, что является основой каждой локальной адресации. Скажем, у вас есть этот код:
int main() {
__volatile int localVariable = 0x10;
printf("%d");
}
Переменная localVariable
может храниться где-то статический (например, по адресу 0x410000
), но если был main
вызывается снова, то значение по этому адресу будет overwirtten. Поэтому необходимо что-то вроде динамического выделения. Для этого используется рамка стека; сохраняет предыдущий стек стека и «распределяет» место для локальных переменных относительно фактической позиции указателя стека. В этом случае localVariable
должен всегда находиться в позиции EBP-sizeof(int)
.
Вторая и третья строки на самом деле являются частью кода, которая выделяет «новую» память. Третья строка вычитает некоторое значение от ESP
(стек растет) -> и поэтому функции не перезаписывают свои переменные; каждая функция имеет свое место для них. Вторая строка сохраняет старый указатель стека, поэтому, когда вызываемая функция возвращается из фрейма стека, она стекает указателем предыдущей функции.
Стандартное окончание функции
mov esp, ebp
pop ebp
ret
или оставить RET leave
во втором примере является альтернативой первых двух строк в первом примере, как функции возвращают к выполнению предыдущей функции очень часто.
Адресация EBP - something
обычно означает доступ к локальным переменным вызываемой (текущей) функции.
Адресация EBP + someting
обычно означает доступ к аргументам, переданным функции.
Я должен заметить, что адрес, хранящийся в EBP
, фактически не указывает на аргумент, но возвращает адрес функции, который был нажат командой call
при вызове функции. Значение, сохраненное на EBP + 4
, может быть первым (старая практика, используемая, например, для функций с переменным числом аргументов, например printf
) так же, как и последняя переменная (типичная для Java, которая обрабатывает аргументы счетчика аргументов - Object... values
- путем создания нового массива и передачи только ссылка на него).
Ваш пример выглядит несколько необычным, но эта ссылка объяснит установку фрейма стека: http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames – lurker
Также смотрите: http://stackoverflow.com/questions/3699283/ то, что-это-стек-кадр-в-сборке – lurker