Разрядность адреса возврата из процедуры

Тема в разделе "WASM.ASSEMBLER", создана пользователем dzga, 27 ноя 2008.

  1. dzga

    dzga New Member

    Публикаций:
    0
    Регистрация:
    24 ноя 2008
    Сообщения:
    5
    Заношу в стек пару чисел типа 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
     
  2. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    Судя по всему, из-за вот этого:

    LOCAL temp : dword

    Где локальная переменная размещена-то будет? В стеке, но уже после адреса возврата. Транслятор ассемблера порождает, надо полагать, специальные пролог и эпилог, чтобы поддерживать эти "высокоуровневые" фичи.
     
  3. dzga

    dzga New Member

    Публикаций:
    0
    Регистрация:
    24 ноя 2008
    Сообщения:
    5
    Т.е. "LOCAL temp : dword" закидывает в стек два dword-a ?
     
  4. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Угу, в результате выполнения стандартного пролога:
    Код (Text):
    1. push ebp
    2. mov ebp,esp
    3. add esp,local_size
    так и получается:
    Код (Text):
    1. esp+0 = temp
    2. esp+4 = ebp
    3. esp+8 = адрес возврата
    4. esp+12 = "Первое число"
    5. esp+16 = "Второе число"
     
  5. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    sub esp,local_size
     
  6. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    сорри, конечно sub
     
  7. dzga

    dzga New Member

    Публикаций:
    0
    Регистрация:
    24 ноя 2008
    Сообщения:
    5
    а как в этом случае выровнять стек при выходе из подпрограммы? Ведь выше адреса возврата в стеке еще находятся:
    esp+0 = temp
    esp+4 = ebp

    Или ret 8 будет достаточно?
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    dzga
    Нет не достаточно, нужно
    Код (Text):
    1. add esp,4
    2. mov esp,ebp
    3. 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
     
  9. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.787
    dzga
    Можно и по имени, если использовать equ (в примере синтаксис nasm)
    Код (Text):
    1. window_procedure:
    2. %define hWnd     ebp+8
    3. %define uMsg     ebp+0xC
    4. %define oldf     ebp  - 4
    5. enter PAINTSTRUCT_size+4,0
    6. mov eax,[uMsg]<--- генерируется код mov eax,[ebp+0xC] но я обращаюсь к переменной uMsg
    7. mov edi,[hWnd]
    PS
    Код (Text):
    1. add esp,4<-- смысл выравнивать стек если следующая команда mov esp,ebp ?
    2. mov esp,ebp
    если требуется компактность, а не быстродействие используйте 1 байтную команду leave
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Mikl___
    Да, чет я туплю :dntknw:
    Еще и про pop ebp забыл - маша растеряша :)
    Код (Text):
    1. mov esp,ebp
    2. pop ebp
    3. retn 8