код
Следующий простой код сборки x86 указан в Wikibooks для соглашения о вызовах CDECL:
Определение функции:
_MyFunction1:
push ebp
mov ebp, esp
mov eax, [ebp + 8]
mov edx, [ebp + 12]
add eax, edx
pop ebp
ret
Функция вызова:
push 3
push 2
call _MyFunction1
add esp, 8
Это то, что будет сгенерировано из следующего кода C:
_cdecl int MyFunction1(int a, int b)
{
return a + b;
}
И этот вызов функции:
x = MyFunction1(2, 3);
выпуск
К сожалению, я не могу полностью обернуться вокруг того, что здесь происходит. Вот список событий, как я их понимаю, начиная с вызывающей функции:
- вставить целое число 3 в стек
- положить целое число 2 в стек
- вызов _MyFunction1, помещающий IP-адрес указателя инструкций в стек
- поместите базовый указатель ebp в стек, чтобы иметь возможность восстановить его позже. Я полагаю, это необходимо только потому, что в следующей инструкции мы переносим значение в ebp?
- переместить значение текущего указателя стека esp в ebp для последующего использования при адресации памяти. Зачем это делать? Почему бы просто не использовать значение esp в следующих двух инструкциях напрямую (т.е. [esp + 8], [esp + 12])
- получить два целочисленных значения, которые мы поместили в стек, и сохранить их в eax и edx. Очевидно, что мы делаем это, указывая каждый адрес памяти. Как процессор знает, как далеко он должен смотреть, пока полностью не прочитает, например, целое число 3? Откуда он знает, что это 32 или 16-битное целое число здесь? Как именно получаются 8 и 12 как смещение указателя стека? Что они имеют в виду, например 8 означает 8-битное смещение?
- сложить два значения вместе в eax
- восстановить ebp из стека
- return, то есть выталкивание eip, содержащего следующую инструкцию из стека, и переход к ней
- добавить 8 (опять, какой блок?) К указателю стека esp
- теперь, с CDECL, вызывающая сторона должна очистить стек. Я считаю, что это должно было произойти с этой инструкцией. Но как просто продвигать указатель как способ очистки стека? Целочисленные значения 3 и 2 никогда не выталкивались. Во всяком случае, я бы подумал, что уменьшение значение указателя сделает свое дело, а не увеличение его, как здесь