Идентификация аргументов функций - часть 25
; 0x0, 0x10, 0x20, 0x30, 0x40. Теперь становится понятным смысл программы
; Взяв остаток, полученный делением количества миллисекунд, прошедших с минуты
; включения системы на 5, мы получаем число в интервале от 0 до 4. Умножая его
; на 0x10, - 0x0, 0x0x10 – 0x40.
call ds:MessageBeep
; Бибикаем на все лады
mov eax, [ebp+arg_C]
; Заносим в EAX dwTime
xor edx, edx
; Обнуляем EDX
mov ecx, 3E8h
; В десятичном 0x3E8 равно 1000
div ecx
; Делим dwTime на 1000 – т.е. переводим миллисекунды в секунды и…
push eax
; …передаем его функции printf
push offset aD ; "\r:=%d"
call _printf
add esp, 8
; printf("\r:=%d")
pop ebp
retn 10h
; Выходя – гасите свет, т.е. чистите за собой стек!
TimerProc endp
Листинг 67
Важное замечание о типах, определенных в <WINDOWS.H>! Хотя об этом уже говорилось в комментариях к предыдущему листингу, повторение не будет лишним, хотя бы уже потому, что не все читатели вчитываются в разборы дизассемблерных текстов.
Итак, CALLBACK и WINAPI функции следуют соглашению о вызовах PASCAL, но сам PASACAL определен в <WINDEF.H> как stdcall (а на некоторых платформах и как cdecl). Таким образом, на платформе INTEL все Windows-функции следуют соглашению: аргументы заносятся справа налево, а стек вычищает вызываемая функция.
Давайте для знакомства в PASCAL-соглашением создадим простенькую PASCAL программу и дизассемблируем ее (это, не обозначает, что PASCAL-вызовы встречаются только в PASCAL-программах, но так будет справедливо):
USES WINCRT;
Procedure MyProc(a:Word; b:Byte; c:String);
begin
WriteLn(a+b,' ',c);
end;
BEGIN
MyProc($666,$77,'Hello,Sailor!');
END.
Листинг 68 Демонстрация PASCAL-вызова
Результат компиляции компилятором "Turbo Pascal for Windows" должен выглядеть так:
PROGRAM proc near
call INITTASK
; Вызов INITTASK из KRNL386.EXE для инициализации 16-разрядной задачи
