· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.WIN32 —› push ax и wsprintf

. 1 . 2 . >>

Посл.отвђт Сообщенiе


Дата: Сен 20, 2004 06:34:52

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

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бит значения ? Вроде нигде такого не написано. Может плохо читал ?

Спасибо


Дата: Сен 20, 2004 06:48:13

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


Дата: Сен 20, 2004 08:28:07

Возможно, дело не в push\pop, а в некорректной пересылке ax в ebx, т.к. после invoke в старшем ворде eax может быть любой мусор => для гарантии обнуления старшего ворда ebx нужно использовать либо
	pop ax
	movzx ebx,ax

либо	xor eax,eax
	pop ax
	mov ebx,eax


Дата: Сен 20, 2004 08:47:13

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

131853869__L.asm


Дата: Сен 20, 2004 09:59:21 · Поправил: valterg

Не знаю, как ты увидел код ответа -1,
но заменив перед второй выдачей mov ebx,eax
на mov ebx,27
ты поймешь что не работает 1-ая выдача.
Почему ? Не знаю, но подозреваю, что стек должен
идти по двойным словам ( 32-бит ) и система
начинает дурить. Возможно, что это еще один
из методов куда-нибудь влезть, типа переполнения буфера...
Отладчик показывает, что не работает WriteConsole.


Дата: Сен 20, 2004 10:52:34

WriteConsole не нравится, то что стек не выровнен по границе двойного слова. Вот так будет работать.
    xor eax, eax
    mov ax, 38
    mov ebx, eax
    push ax
    push ax
    invoke wsprintf, ADDR buf, ADDR ifmt, ebx
    invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL
    xor eax, eax
    pop ax
    pop ax
    mov ebx, eax
    invoke wsprintf, ADDR buf, ADDR ifmt, ebx
    invoke WriteConsole, stdout, ADDR buf, BSIZE, ADDR cWritten, NULL


Дата: Сен 20, 2004 11:28:31 · Поправил: leo

Выравнивание стека здесь ни причем.
Нужно внимательнее читать описание функций:
"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.


Дата: Сен 20, 2004 11:37:33

> Если после wsprintf вставить как положено add esp,12 то все будет OK

Не вводи людей в заблуждение - invoke сам ставит add esp, 0Ch
Дело именно в невыровнянности стэка.


Дата: Сен 20, 2004 11:46:56 · Поправил: leo

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

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


Дата: Сен 20, 2004 12:40:17

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


Дата: Сен 20, 2004 13:03:56 · Поправил: leo

Four-F
"Возможно в 9х выравнивание по-барабану, но под nt+ точно в этом дело"
Хорошо. Может тогда ответишь на исходный вопрос mkl: "Вроде нигде такого не написано. Может плохо читал ?"

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


Дата: Сен 21, 2004 08:57:40 · Поправил: leo

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

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


Дата: Сен 21, 2004 09:56:12

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разрядной ;-)


Дата: Сен 21, 2004 10:50:28 · Поправил: leo

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


Дата: Сен 21, 2004 14:15:16

[ leo: Может тогда ответишь на исходный вопрос ]

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

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

kernel32!WriteConsole -> kernel32!WriteConsoleInternal -> ntdll!CsrClientCallServer -> ntdll!ZwRequestWaitReplyPort -> переход в режим ядра -> ntoskrnl!ZwRequestWaitReplyPort
:0049BA97 _NtRequestWaitReplyPort@12 proc near
. . .
:0049BA97 RequestMessage= dword ptr  0Ch            ; IN PPORT_MESSAGE
. . .
;
; ставим SEH
;
:0049BA9A       push -1
:0049BA9C       push offset dword_402DE0
:0049BAA1       push offset __except_handler3
:0049BAA6       mov eax, large fs:0
:0049BAAC       push eax
:0049BAAD       mov large fs:0, esp
. . .
;
; проверяем выравнивание
;
:0049BAF5       mov ecx, [ebp+RequestMessage]       ; IN PPORT_MESSAGE
:0049BAF8       test cl, 3                          ; ВОТ ПРОВЕРКА НА КРАТНОСТЬ DWORD
:0049BAFB       jnz loc_4ED687
...
;
; вбрасываем исключение STATUS_DATATYPE_MISALIGNMENT, с которым разбирается обработчик SEH
;
:004ED687 loc_4ED687:
:004ED687       call _ExRaiseDatatypeMisalignment

. 1 . 2 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.053