#ассемблер #исключения
Мне нужно написать программу на ассемблере х64 в VS 2017, Windows 10. Нужно ввести в окошко строку, а программа должна заменить * на пробелы и вывести в строку результат. Пример нашей преподавательницы запускается, но при нажатии на кнопку RUN происходит исключение по адресу. Не знаете, в чем проблема? Сама она тоже не знает. Код ниже. Заранее спасибо. ExitProcess PROTO DlgProc PROTO :QWORD,:QWORD, :QWORD, :QWORD PostQuitMessage PROTO GetModuleHandleA PROTO DialogBoxParamA PROTO GetDlgItemTextA PROTO SendDlgItemMessageA PROTO include windows.inc .data DName db "dial",0 hinst dq ? result_buffer db 20 dup ("0") hwnd dq 0 uMsg dq 0 wParam dq 0 lParam dq 0 .code main proc sub rsp, 56 mov rcx,0 call GetModuleHandleA mov hinst,rax mov rcx,hinst lea rdx, DName mov r8,0 lea r9,DlgProc mov dword ptr [rsp+32], 0 call DialogBoxParamA mov rcx,0 call ExitProcess main endp DlgProc proc q:QWORD,w:QWORD, e:QWORD, r:QWORD cmp edx, WM_CLOSE ;10h je Exit_Button cmp edx, WM_COMMAND ;111h je go_button jne End_it go_button: cmp r8,4 je Exit_Button cmp r8,3 je next jne End_it next: mov hwnd,rcx mov uMsg,rdx mov wParam,r8 mov lParam,r9 mov rdx,1 lea r8,result_buffer mov r9,20 call GetDlgItemTextA mov rcx, hwnd mov rdx, uMsg mov r8, wParam mov r9, lParam mov hwnd,rcx mov rcx,rax lea rsi,result_buffer m1: cmp byte ptr [rsi],'*' je m2 jne m3 m2: mov byte ptr [rsi],' ' m3: inc rsi loop m1 mov rcx,hwnd mov rdx,2 mov r8,LB_DELETESTRING ; 182h - LB_DELETESTRING mov r9,0 lea rsi,result_buffer mov qword ptr [rsp+32],rsi call SendDlgItemMessageA mov rcx, hwnd mov rdx, uMsg mov r8, wParam mov r9, lParam mov rdx,2 mov r8,LB_ADDSTRING ; 182h - LB_DELETESTRING mov r9,0 lea rsi,result_buffer mov qword ptr [rsp+32],rsi call SendDlgItemMessageA jmp End_it Exit_Button: mov rcx,0 call PostQuitMessage End_it: mov rax,0 ret DlgProc endp end Файл RSRC.RC dial DIALOG 0, 0, 309, 95 CAPTION "mY dialog" BEGIN EDITTEXT 1, 48,7,222,14 ListBox 2,48,24,222,14 PUSHBUTTON "Run", 3, 167,41,50,14 PUSHBUTTON "Exit",4, 220,41,50,12 LTEXT "Input string:", -1, 7,10,40,8 END Ошибка в отладчике:
Ответы
Ответ 1
В коде две проблемы, приводящих к вылетам: Не проверяется что введена пустая строка (значение, возвращенное из GetDlgItemTextA, равно нулю), из-за чего при первом попадании на инструкцию loop 0 в регистре rcx превращается в -1, получаем "бесконечный" цикл и попытку записи за пределы секции данных. В начале процедуры DlgProc нужно выделить на стеке место под параметры процедуры SendDlgItemMessageA, при выходе из DlgProc стек восстановить. Из-за того что это не выполнено, скорее всего при выполнении SendDlgItemMessageA (которое происходит только при нажатии кнопки "Run") происходит затирание каких-то данных вызывающего кода, при выходе из процедуры происходит вылет. Вот рабочий код, адаптированный под fasm, с моими замечаниями: include 'win64a.inc' format MS64 COFF public main extrn PostQuitMessage extrn SendDlgItemMessageA extrn GetModuleHandleA extrn GetDlgItemTextA extrn DialogBoxParamA extrn ExitProcess section '.data' readable writeable DName db "dial",0 result_buffer db 20 dup ("0") section '.code' code readable executable main: sub rsp, 5*8 ; место под 5 параметров для вызова DialogBoxParamA mov rcx,0 call GetModuleHandleA mov rcx, rax ; [hinst] mov rdx, DName mov r8, 0 mov r9, DlgProc mov dword [rsp+32], 0 call DialogBoxParamA mov rcx,0 call ExitProcess proc DlgProc hwnd, uMsg, wParam, lParam ; место под параметры на стеке выделено как раз для того, ; чтобы можно было сохранить там значения тех же параметров из регистров mov [hwnd], rcx mov [uMsg], rdx mov [wParam], r8 mov [lParam], r9 sub rsp, 5*8 ; резервируем на стеке место под 5 параметров для вызова SendDlgItemMessageA cmp edx, WM_CLOSE ; 10h je Exit_Button cmp edx, WM_COMMAND ; 111h je go_button jne End_it go_button: cmp r8,4 je Exit_Button cmp r8,3 ; je next ; лишняя проверка jne End_it ; next: mov rdx,1 mov r8, result_buffer mov r9,20 call GetDlgItemTextA ; Не нужно постоянно гонять параметры между памятью и регистрами ; mov rcx, hwnd ; mov rdx, uMsg ; mov r8, wParam ; mov r9, lParam ; mov hwnd,rcx test rax, rax ; не забываем проверить, что введена не пустая строка jz End_it mov rcx, rax mov rsi, result_buffer m1: cmp byte [rsi], '*' ; je m2 ; лишняя проверка jne m3 ; m2: mov byte [rsi], '+' ; заменяю на +, чтобы была заметнее разница m3: inc rsi loop m1 mov rcx, [hwnd] mov rdx, 2 ; ListBox mov r8, LB_DELETESTRING ; 182h - LB_DELETESTRING mov r9, 0 mov qword [rsp+32], result_buffer ; mov qword ptr [rsp+32], offset result_buffer для masm call SendDlgItemMessageA ; mov rcx, hwnd ; mov rdx, uMsg ; mov r8, wParam ; mov r9, lParam mov rcx, [hwnd] mov rdx,2 mov r8, LB_ADDSTRING mov r9,0 mov qword [rsp+32], result_buffer call SendDlgItemMessageA jmp End_it Exit_Button: mov rcx,0 call PostQuitMessage End_it: mov rax,0 add rsp, 5*8 ; восстанавливаем стек ret endp Для компиляции нужен fasm, а также GoRC и GoLink (см. The Go tools for Windows + Assembler, к языку Go не имеют никакого отношения). Для отладки использовал x64dbg. Собственно, компиляция: fasm dialog.asm gorc /machine X64 rsrc.rc golink dialog.obj rsrc.res user32.dll kernel32.dll /entry main Ну и наконец скриншот (состояние после ввода текста и нажатия на кнопку Run): P.S. "криво расставленные котлы" авторские, rsrc.rc я в неизмененном виде взял из вопроса.
Комментариев нет:
Отправить комментарий