Win32 очень низкий уровень сборки - проблема с запуском приложения - PullRequest
0 голосов
/ 24 февраля 2012

Я занят программированием win32-программы на ассемблере с формой и кнопками ... Проблема в том, что windows изменяет мои переменные в ram. Место было хранилище моих переменных hInstance и hwnd. Я нашел обходной путь, но это не элегантное решение. Я хотел бы знать, почему окна изменяют мои переменные, а также где можно найти документацию, описывающую запуск приложения.

MyWndProc: 
push EBP 
mov EBP, ESP 
mov eax, [EBP + 12] 
cmp eax, WM_DESTROY 
jne MyWndProc_j2 
push 0 
call PostQuitMessage 
jmp MyWndProc_j1 

MyWndProc_j2: 
cmp eax, WM_CREATE 
jne MyWndProc_j1 
mov eax, [EBP+8] 
push eax 
call CreateControls 
add esp, 4 

MyWndProc_j1: 
mov eax, [EBP + 20] 
push eax 
mov eax, [EBP + 16] 
push eax 
mov eax, [EBP + 12] 
push eax 
mov eax, [EBP + 8] 
push eax 
call DefWindowProcA 
pop EBP 
ret 

segment .data 

Wtitle db 'My Window',0 
ClassName db 'myWindowClass',0 

editClass db 'EDIT',0 
buttonName db 'OK',0 
buttonClass db 'BUTTON',0 
textName db 'My textbox',0 
textClass db 'edit',0 

formEdit db 'This is just a mem test', 0 

windowsVar1 dd 0 
windowsVar2 dd 0 
windowsVar3 dd 0 
windowsVar4 dd 0 
windowsVar5 dd 0 
windowsVar6 dd 0 
windowsVar7 dd 0 
windowsVar8 dd 0 

aMsg dd 0 
hwnd dd 0 
hwnd2 dd 0 
hwnd3 dd 0 
hInstance dd 0 
old_proc dd 0 
nCmdShow dd 0 
hfDefault dd 0 

MyWndProc - это функция обратного вызова из окон. При 27-м вызове из окон он изменяет последние 7 переменных. Если я переключу положение последних 8 переменных с помощью windowsVarx, то он все равно изменит hwnd, hwnd2 ... без изменения windowsVarx. Где х от 1 до 8

CreateControls: 
push EBP 
mov EBP, ESP 

push 0 
push 0 
call GetModuleHandleA 
push eax 
push IDC_MAIN_BUTTON 
mov eax, [EBP+8] ;hwnd 
push eax 
push 24 
push 100 
push 220 
push 50 
mov eax, WS_CHILD 
or eax, BS_DEFPUSHBUTTON 
or eax, WS_TABSTOP 
or eax, WS_VISIBLE 
push eax 
push buttonName 
push buttonClass 
push 0 
call CreateWindowExA 
mov [hwnd2], eax 

push DEFAULT_GUI_FONT 
call GetStockObject 
mov [hfDefault], eax 

push 0 
mov eax, [hfDefault] 
push eax 
push WM_SETFONT 
mov eax, [hwnd2] 
push eax 
call SendMessageA 

push 0 
push 0 
call GetModuleHandleA 
push eax 
push IDC_MAIN_EDIT 
mov eax, [EBP+8] ;hwnd 
push eax 
push 100 
push 200 
push 100 
push 50 
mov eax, WS_CHILD 
or eax, ES_MULTILINE 
or eax, ES_AUTOVSCROLL 
or eax, ES_AUTOHSCROLL 
or eax, WS_VISIBLE 
push eax 
push 0 
push editClass 
push WS_EX_CLIENTEDGE 
call CreateWindowExA 
mov [hwnd3], eax 

push 0 
mov eax, [hfDefault] 
push eax 
push WM_SETFONT 
mov eax, [hwnd3] 
push eax 
call SendMessageA 

push Wtitle 
push 0 
push WM_SETTEXT 
mov eax, [hwnd3] 
push eax 
call SendMessageA 

pop EBP 
ret 

Следующая функция - это цикл обработки сообщений, который собирает и отправляет.

MyMessageLoop:
push 0
push 0
push 0
push aMsg
call GetMessageA
cmp eax, 0
je MyMessageLoop_j1
push aMsg
call TranslateMessage
push aMsg
call DispatchMessageA
jmp MyMessageLoop
MyMessageLoop_j1:
ret

Ответы [ 4 ]

1 голос
/ 24 февраля 2012

Может показаться, что Windows изменяет ваши данные, но, как отмечали другие, более вероятно, что ошибка или какое-либо другое повреждение в вашем коде вызывают проблемы.

Для людей почти невозможно определитьПоведение всей вашей программы во время выполнения из фрагментов и программирования на ассемблере почти всегда вызывает проблемы, редко встречающиеся при использовании языков более высокого уровня.

Лучший совет - использовать отладчик и либо шагать по коду, либо устанавливать точка останова данных по изменяемым переменным.Точки останова данных предназначены для остановки вашей программы по инструкции, которая выполняет модификацию данных.

Вы также можете посмотреть, какие фактические значения данных перезаписывают ваши переменные - это может дать вам некоторое представление о том, гдеили почему память перезаписывается.

Причина сарказма людей заключается в том, что во втором предложении вы предполагаете, что Windows виновата в том, что ваша программа не работает.Во многих ситуациях обвинение в операционной системе является хорошим признаком того, что разработчик чего-то не понимает или не хочет признавать, что они допустили ошибку.Конечный результат - почти всегда кто-то другой, указывающий на ошибку.

1 голос
/ 24 февраля 2012

Ваше объяснение проблемы не совсем понятно.Но вы должны помнить, что, вызывая системный вызов, вы действительно можете получить разные значения в своих регистрах.Я не знаю о Windows, но в amd64 Linux ядро ​​(которое выполняет системный вызов) требуется только для сохранения значений регистров r12 и выше.Значения во всех других регистрах могут быть изменены и поэтому, скорее всего, не будут одинаковыми после возврата из системного вызова.

Чтобы исправить это, просто сохраните переменные в стеке вашей функции перед вызовом системы..

0 голосов
/ 26 февраля 2012

С чего мне начать?Форматирование вашего кода очень трудно читать.Надеюсь, универ не научит вас этому.В любом случае, ваш WindowProc был ОЧЕНЬ неправ.После КАЖДОГО сообщения, которое вы обрабатываете, вы НЕ вызываете DefWindowProc, большинство сообщений, которые вы просто возвращаете 0 в eax.

После вашего вызова CreateControls вам не нужно добавлять esp, 4 до концаиз CreateControls вы делаете ret 4 или ret 4 * NumOfParamsPassed.

Я исправил ваш WindowProc, и теперь окно отображается.Я также удалил много ненужных мовов.

MyWndProc:
    push    ebp
    mov     ebp, esp

    mov     eax, dword ptr[ebp + 3 * 4] ; same as [ebp + 12]
    cmp     eax, WM_CREATE
    je      _CREATE
    cmp     eax, WM_CLOSE
    je      _CLOSE

PassThrough:    
    push    dword ptr[ebp + 5 * 4]; same as [ebp + 20]
    push    dword ptr[ebp + 4 * 4]; same as [ebp + 16]
    push    dword ptr[ebp + 3 * 4]; same as [ebp + 12]
    push    dword ptr[ebp + 2 * 4]; same as [ebp + 8]
    call    DefWindowProc
    jmp     _DONE

_CLOSE:
    push    0
    call    PostQuitMessage
    jmp     _RET0

_CREATE:
    push    dword ptr[ebp + 2 * 4]
    call    CreateControls
    ;add     esp, 4

_RET0:
    xor     eax, eax

_DONE:
    pop     ebp
    ret     4 * 4 ; <----- you were missing this!!!!!
0 голосов
/ 25 февраля 2012

Почему вы добавляете 4 в esp после вызова CreateControls? Вы помещаете 1 стек в стек, разве CreateControls не очищает сам стек? Вы написали эту функцию? Если он настраивает стек с помощью что-то вроде ret 4 * 1, то добавление esp, 4 все испортило. Этот фрагмент кода ничего не делает для нас, плюс там так много ненужных mov и jmps там

@ Дэвид Хеффернан, спасибо. Я только начал писать все свои программы на ассемблере более 10 лет назад и хорошо знаю, как и какие регистры нужно сохранять и когда вам НЕ нужно их сохранять, просто потому, что компилятор сохраняет все регистры пролог не означает, что это правильно.

...