mov [ebp+var_8], edx
; Поскольку, EDX используется без явной инициализации, очевидно,
; через него передается второй слева аргумент функции.
; (согласно соглашению fastcall компилятора Microsoft Visual C++)
; Из анализа кода вызывающей функции мы уже знаем,
; что в EDX помещается указатель на var_4, следовательно,
; var_8 теперь содержит указатель на var_4.
mov [ebp+var_4], cl
; Через CL передается самый левый аргумент функции типа char
и тут же
; заносится в локальную переменную var_4.
movsx eax, [ebp+var_4]
; Переменная var_4 расширяется до signed int.
mov ecx, [ebp+var_8]
; В регистр ECX загружается содержимое указателя var_8, переданного через EDX.
; Действительно, как мы помним, через EDX
функции передавался указатель.
add eax, [ecx]
; Складываем EAX (хранит первый слева аргумент функции) с содержимым
; ячейки памяти, на которую указывает указатель ECX
(второй слева аргумент).
add eax, [ebp+arg_0]
; А вот и обращение к тому аргументу функции, что был передан через стек
mov esp, ebp
pop ebp
; Закрываем кадр стека
retn 4
; Функции был передан 1 аргумент через стек
MyFunc endp
Листинг 75
Просто? Просто! Тогда рассмотрим результат творчества Borland C++, который должен выглядеть так:
; int __cdecl main(int argc,const char **argv,const char *envp)
_main proc near ; DATA XREF: DATA:00407044o
var_4 = dword ptr -4
argc = dword ptr 8
argv = dword ptr 0Ch
envp = dword ptr 10h
push ebp
mov ebp, esp
; Открываем кадр стека
push ecx
; Сохраняем ECX... Постойте! Это что-то новое! В прошлых примерах Borland
; никогда не сохранял ECX при входе в функцию. Очень похоже, что через ECX
; функции был передан какой-то аргумент, и теперь она передает его другой
; функции через стек.
; Увы, каким бы убедительным такое решение ни выглядело оно неверно!