Заношу в стек пару чисел типа dword. И вызываю процедуру, в которой они последовательно печатаются. Экспериментально подобрал, что в стеке они хранятся по смещению esp+12. В книгах (например Крупник. Самоучитель ассемблер 2005) сказано, что команда call помещает в стек адрес возврата из подпрограммы в виде dword. Тогда, по-идее, адрес возврата должен лежать по адресу esp+0, а мои данные должны начинаться как esp+4 и esp+8 соответственно. А судя из того, что получается на самом деле, в стек (в качестве адреса возврата) отсылается три dword-a. Я правильно понял? ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ include \masm32\include\masm32rt.inc ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ .data array dd 9,2,3,4,13 .code start: ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ call main inkey exit ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ main proc push dword ptr [7] push dword ptr [8] call calculation ret main endp ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ calculation proc LOCAL temp : dword mov eax, dword ptr [esp+12] mov temp, eax pushad fn MessageBox, 0, str$(temp), "Первое число", MB_OK popad mov eax, dword ptr [esp+16] mov temp, eax pushad fn MessageBox, 0, str$(temp), "Второе число", MB_OK popad ret calculation endp end start
Судя по всему, из-за вот этого: LOCAL temp : dword Где локальная переменная размещена-то будет? В стеке, но уже после адреса возврата. Транслятор ассемблера порождает, надо полагать, специальные пролог и эпилог, чтобы поддерживать эти "высокоуровневые" фичи.
Угу, в результате выполнения стандартного пролога: Код (Text): push ebp mov ebp,esp add esp,local_size так и получается: Код (Text): esp+0 = temp esp+4 = ebp esp+8 = адрес возврата esp+12 = "Первое число" esp+16 = "Второе число"
а как в этом случае выровнять стек при выходе из подпрограммы? Ведь выше адреса возврата в стеке еще находятся: esp+0 = temp esp+4 = ebp Или ret 8 будет достаточно?
dzga Нет не достаточно, нужно Код (Text): add esp,4 mov esp,ebp retn 8 ;!! не ret, а retn А вообще ты делаешь не правильно, т.к. если бы ты нормально объявил параметры у proc, то было бы достаточно просто ret. На самом деле proc, ret и endp это макросы. Если не вдаваться в подробности, то макрос proc выполняет пролог и объявляет макрос ret, который в свою очередь выполняет эпилог (add esp,local_size + mov esp,ebp) и инструкцию retn param_size. Макрос endp отменяет действие макроса ret и поэтому дальше ret вместо макроса становится инструкцией процессора ret = retn. Другими словами между proc и endp, ret это не инструкция, а макрос. Если нужна инструкция, а не макрос то следует юзать retn Другой вариант - отключить генерацию пролога\эпилога (см. option prologue\epilogue), но тогда нужно будет самому выделять локальные переменные и обращаться к ним не по имени, а по esp или ebp
dzga Можно и по имени, если использовать equ (в примере синтаксис nasm) Код (Text): window_procedure: %define hWnd ebp+8 %define uMsg ebp+0xC %define oldf ebp - 4 enter PAINTSTRUCT_size+4,0 mov eax,[uMsg]<--- генерируется код mov eax,[ebp+0xC] но я обращаюсь к переменной uMsg mov edi,[hWnd] PS Код (Text): add esp,4<-- смысл выравнивать стек если следующая команда mov esp,ebp ? mov esp,ebp если требуется компактность, а не быстродействие используйте 1 байтную команду leave
Mikl___ Да, чет я туплю Еще и про pop ebp забыл - маша растеряша Код (Text): mov esp,ebp pop ebp retn 8