|
|
| Посл.отвђт | Сообщен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 |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.053 |