#ассемблер #исключения
Мне нужно написать программу на ассемблере х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 я в неизмененном виде взял из вопроса.
Комментариев нет:
Отправить комментарий