push ax и wsprintf

Тема в разделе "WASM.WIN32", создана пользователем mkl, 20 сен 2004.

  1. mkl

    mkl New Member

    Публикаций:
    0
    Регистрация:
    11 сен 2003
    Сообщения:
    3
    Адрес:
    Russia
    Уважаемые коллеги !

    Я сильно начинающий и наверное чего то не дочитал, но почему



    mov ax, 38

    mov ebx, eax

    push ax

    ; это показывает

    invoke wsprintf, ADDR buf, ADDR ifmt, ebx

    invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL

    pop ax

    mov ebx, eax

    ; а это не показывает

    invoke wsprintf, ADDR buf, ADDR ifmt, ebx

    invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL



    Хотя если заменить



    push ax

    ....

    pop ax



    на



    push eax

    ....

    pop eax



    , то оба вывода появляются на экране. Что в Win32 надо помещать в стек только 32бит значения ? Вроде нигде такого не написано. Может плохо читал ?



    Спасибо
     
  2. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    mkl



    Логичное заключение, но не совсем правильное. Всё зависит от кода. Вместо одного 32-битного push'а можно сделать два 16-битных и т.д. С другой стороны, если участок кода не содержит вызовов API и не является callback'ом, нитью и т.п., то можно спокойно кромсать стек 16-битными push'ами.
     
  3. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Возможно, дело не в push\pop, а в некорректной пересылке ax в ebx, т.к. после invoke в старшем ворде eax может быть любой мусор => для гарантии обнуления старшего ворда ebx нужно использовать либо
    Код (Text):
    1.     pop ax
    2.     movzx ebx,ax
    3.  
    4. либо    xor eax,eax
    5.     pop ax
    6.     mov ebx,eax
     
  4. mkl

    mkl New Member

    Публикаций:
    0
    Регистрация:
    11 сен 2003
    Сообщения:
    3
    Адрес:
    Russia
    Обнуления безусловно нужны, но они не при чем. В аттаче полный пример. Самое интересное - в отладчике содержимое регистров перед вторым вызовом такое же как перед первым, но на экране - ничего, а в eax - 1, т.е. ошибка, как я понимаю. Только не понимаю какая (про get last error еще не проходили ...).

    [​IMG] 131853869__L.asm
     
  5. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Не знаю, как ты увидел код ответа -1,

    но заменив перед второй выдачей mov ebx,eax

    на mov ebx,27

    ты поймешь что не работает 1-ая выдача.

    Почему ? Не знаю, но подозреваю, что стек должен

    идти по двойным словам ( 32-бит ) и система

    начинает дурить. Возможно, что это еще один

    из методов куда-нибудь влезть, типа переполнения буфера...

    Отладчик показывает, что не работает WriteConsole.
     
  6. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    WriteConsole не нравится, то что стек не выровнен по границе двойного слова. Вот так будет работать.


    Код (Text):
    1.  
    2.     xor eax, eax
    3.     mov ax, 38
    4.     mov ebx, eax
    5.     push ax
    6.     push ax
    7.     invoke wsprintf, ADDR buf, ADDR ifmt, ebx
    8.     invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL
    9.     xor eax, eax
    10.     pop ax
    11.     pop ax
    12.     mov ebx, eax
    13.     invoke wsprintf, ADDR buf, ADDR ifmt, ebx
    14.     invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL
    15.  
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Выравнивание стека здесь ни причем.

    Нужно внимательнее читать описание функций:

    "Unlike other Windows functions, wsprintf uses the C calling convention (_cdecl)... As a result, it is the responsibility of the calling process to pop arguments off the stack.. In C-language modules, the C compiler performs this task"

    Если после wsprintf вставить как положено add esp,12 то все будет OK и при push ax и push eax.
     
  8. Dr.Golova

    Dr.Golova New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2002
    Сообщения:
    348
    > Если после wsprintf вставить как положено add esp,12 то все будет OK



    Не вводи людей в заблуждение - invoke сам ставит add esp, 0Ch

    Дело именно в невыровнянности стэка.
     
  9. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    "invoke сам ставит add esp, 0Ch "

    С инвоками не работаю принципиально, поэтому сказать ничего не могу.

    Но с add esp у меня прекрасно работает и push ax и push eax. Для проверки нужно посмотреть esp до и после вызова wsprintf, или оформить код в виде процедуры - без очистки стека мы из нее не выйдем.



    PS: я проверял в 9x, может в nt-шных осях и не так - ну тады не знаю...
     
  10. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Возможно в 9х выравнивание по-барабану, но под nt+ точно в этом дело.
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Four-F

    "Возможно в 9х выравнивание по-барабану, но под nt+ точно в этом дело"

    Хорошо. Может тогда ответишь на исходный вопрос mkl: "Вроде нигде такого не написано. Может плохо читал ?"



    All

    Насчет выравнивания молчу. Но еще один источник ошибки - это BSIZE = 15 в то время как длина строки = 2. По правильному вместо BSIZE нужно использовать значение eax, возвращаемое wsprintf. Что может быть при выдаче на консоль разного мусора уже недавно обсуждалось (см.Смерть винде).
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    На мой взгляд все, что до сих пор говорилось о выравнивании стека похоже на предположения. Судя по вопросу даже для "сильно начинающих" ясно, что выравнивать "хорошо", а нарушать выравнивание "плохо" и лучше не рисковать. Вопрос то в том, а что будет если мы поступим плохо и вызовем API с невыровненным стеком. В 9х для данного примера ничего страшного не происходит, "но под nt+ точно в этом дело". А какое дело так никто и не уточнил. Контролирует система выравнивание или нет ? Что означает фраза Four-F "WriteConsole не нравится.." ? "Система начинает дурить" и "это еще один из методов куда-нибудь влезть" как подозревает valterg или мы дурим, не делая проверки результата WriteConsole на 0 и GetLastError <> 0 и не устанавливая свой SEH-обработчик. Что выдает отладчик после вызова WriteConsole ? Или может не срабатывает первый вызов, возвращая 0, а срабатывает второй после pop ax.



    PS: сам бы проверил, да не на чем - 9х никак умирать не хочет.
     
  13. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    ESP в NT не только должен быть выровнен по DWORD, но так же должен находиться в пределах, хранящихся в



    FS:[4] //StackBase Upper Address

    FS:[8] //StackLimit Lower Address



    не знаю, где написано про это всё явно, но вроде бы это одно из основных правил, вроде "API сохраняет значения регистров ESP, EBP, ESI, EDI и EBX, а EAX, EDX и ECX портит; и подразумевает, что флаг DF сброшен"



    Кстати, про необходимость выравнивания стека в 32разрядных режимах пишет intel в optimization reference manual.

    А то, что мастдаю это не проверяет - дык, система не является 32разрядной :derisive:
     
  14. leo

    leo Active Member

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

    То, о чем ты говоришь - ясно и понятно. Если мы выйдем за границы стека, то наверное получим #SS или #GP. А вот выравнивание по dword в том числе у intel выглядит как рекомендация для улучшения performance, а ошибки выравнивания в процессоре генерятся только при установленном флаге AC. Я уже повторяюсь, но вопрос в том что будет если если кто-то тупой и безграмотный нарушит эти рекомендации. Система может или 1) контролировать выравнивание (например по #AC или test esp,..) и выдавать ошибку или 2) тупо надеятся на "сознательность" кодеров, что чревато последствиями. Я все-таки надеюсь на первое и поэтому хотелось бы до конца разобраться где возникает ошибка в приведенном примере (неужели это так долго и трудно ...).
     
  15. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    [ leo: <font color="indigo]Может тогда ответишь на исходный вопрос</font><!--color--> ]



    S_T_A_S_ вобщем уже ответил. Все эти тонкости с созранением регистров и выравниванием стека мало интересуют рядового программиста на ЯВУ. Этим занимаются разработчики компиляторов. А поскольку доки пишут именно для ЯВУ-программистов, то всю эту низкоуровневую хрень пытаются опустить. И программист на ЯВУ на эти грабли никогда не наступит. Про выравнивание довольно много написано в DDK в разделе по 64-битному кодингу.



    Касательно косяка с WriteConsole, дело обстоит так:



    kernel32!WriteConsole -> kernel32!WriteConsoleInternal -> ntdll!CsrClientCallServer -> ntdll!ZwRequestWaitReplyPort -> переход в режим ядра -> ntoskrnl!ZwRequestWaitReplyPort


    Код (Text):
    1. :0049BA97 _NtRequestWaitReplyPort@12 proc near
    2. . . .
    3. :0049BA97 RequestMessage= dword ptr  0Ch            ; IN PPORT_MESSAGE
    4. . . .
    5. ;
    6. ; ставим SEH
    7. ;
    8. :0049BA9A       push -1
    9. :0049BA9C       push offset dword_402DE0
    10. :0049BAA1       push offset __except_handler3
    11. :0049BAA6       mov eax, large fs:0
    12. :0049BAAC       push eax
    13. :0049BAAD       mov large fs:0, esp
    14. . . .
    15. ;
    16. ; проверяем выравнивание
    17. ;
    18. :0049BAF5       mov ecx, [ebp+RequestMessage]       ; IN PPORT_MESSAGE
    19. <font color="red]:0049BAF8       test cl, 3                          ; ВОТ ПРОВЕРКА НА КРАТНОСТЬ DWORD</font><!--color-->
    20. :0049BAFB       jnz loc_4ED687
    21. ...
    22. ;
    23. ; вбрасываем исключение STATUS_DATATYPE_MISALIGNMENT, с которым разбирается обработчик SEH
    24. ;
    25. :004ED687 loc_4ED687:
    26. :004ED687       call _ExRaiseDatatypeMisalignment
     
  16. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Four-F



    И последняя точка. Из описания WrriteConsole :



    <font color="red]Return Values

    If the function succeeds, the return value is nonzero.



    If the function fails, the return value is zero. To get extended error information, call GetLastError. </font><!--color-->

    Прогнал еще раз в MS Visual Studio.

    Действительно в первом случае код ответа 0,

    а во втором - 1.

    Вот к чему приводит пренебрежение к документации :)
     
  17. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Four_F & valterg

    Спасибо за исчерпывающий ответ.



    PS: "и все таки она вертится", в том смысле, что выполняет явный контроль, а не виснет по тихому.
     
  18. bogrus

    bogrus Active Member

    Публикаций:
    0
    Регистрация:
    24 окт 2003
    Сообщения:
    1.338
    Адрес:
    ukraine
    Жаль не все ф-ции возвращают ошибку .



    push ax

    invoke MessageBox,0,0,0,0
     
  19. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    bogrus

    Такой код, даже без push ax, в win98 не прокатит :derisive:
     
  20. mkl

    mkl New Member

    Публикаций:
    0
    Регистрация:
    11 сен 2003
    Сообщения:
    3
    Адрес:
    Russia
    Уважаемые коллеги, огромное спасибо за исчерпывающие ответы. Все стало понятно, сам бы дошел не скоро.



    А много ли в низком уровне такого, о чем написано только в местах, подобных DDK в разделе по 64-битному(?) кодингу или intel в optimization reference manual ?