Привет всем читателям форума. Начинаю свои первые шаги в программировании и встал колом. Ниже приведённый код это можно сказать индикатор моих знаний. Пытаюсь в учебных целях сделать консольный калькулятор Win32. Пока, что сдесь только вывод на консоль и попытка создать процедуры для начальной арифметики. Данные ввожу прямо в исходный код. Застопорилось же всё когда я обнаружил, что когда я в переменные ввожу четырёхзначные числа результат отображаеться в консоли,а когда малые числа даже с нулями впереди отображается пустая консоль. Уже сколько бьюсь, но ни как не могу понять, что не так. Предпалогаю, что есть какой то неучтённый хитрый нюанс связанный с типами данных. Просветите пожалуйста. Код (Text): .586 .model flat,stdcall include C:\masm32\include\windows.inc include C:\masm32\include\user32.inc include C:\masm32\include\kernel32.inc include C:\masm32\include\masm32.inc includelib C:\masm32\lib\user32.lib includelib C:\masm32\lib\kernel32.lib includelib C:\masm32\lib\masm32.lib get_in_hndl proto get_out_hndl proto write_con proto read_con proto my_add proto out_math proto my_sub proto my_mul proto out_math64 proto .data std_output_hndl equ -11 std_input_hndl equ -10 in_hndl DD 0 out_hndl DD 0 ;--------------------------------------------------------------------------------------------- str_out_txt DD " ",13,10,0 len_str_out_txt equ $-str_out_txt con_titl DB "Console application",0 buf_str_out_txt DD 0 ch_write_con DD 0 ;----------------------------------------------------------------------------------------------- buf_for_read DB ? len_buf_for_read DD 1 ch_read_con DD 0 ;----------------------------------------------------------------------------------------------- X DD -2347 Y DD 5584 Z DD 0 f_t DB "%d",0 Z64 DQ 0 ;----------------------------------------------------------------------------------------------- .code start: invoke FreeConsole invoke AllocConsole test eax,eax jz exi_t invoke SetConsoleTitle,ADDR con_titl test eax,eax jz exi_t invoke get_in_hndl invoke get_out_hndl invoke out_math ;invoke out_math64 exi_t: invoke CloseHandle,in_hndl invoke CloseHandle,out_hndl invoke FreeConsole invoke ExitProcess,0 ;=================================================================== get_in_hndl proc push eax invoke GetStdHandle,std_input_hndl mov in_hndl, eax pop eax Ret get_in_hndl EndP get_out_hndl proc push eax invoke GetStdHandle,std_output_hndl mov out_hndl, eax pop eax Ret get_out_hndl EndP write_con proc push ecx push ebx mov ebx,offset str_out_txt mov ecx, len_str_out_txt invoke WriteConsole,out_hndl,ebx,ecx,ch_write_con,0 pop ebx pop ecx Ret write_con EndP read_con proc invoke ReadConsole,in_hndl,ADDR buf_for_read,len_buf_for_read,ch_read_con,0 Ret read_con EndP my_add proc push eax mov ax, word ptr X add word ptr Y, ax mov ax, word ptr X+2 adc word ptr Y+2, ax mov EAX, dword ptr Y mov dword ptr Z, eax pop eax Ret my_add EndP out_math proc invoke my_add invoke wsprintf,ADDR str_out_txt,ADDR f_t,dword ptr Z invoke write_con invoke read_con Ret out_math EndP my_sub proc push eax mov ax, word ptr X sub word ptr Y, ax mov ax, word ptr X+2 sbb word ptr Y+2, ax mov EAX, dword ptr Y mov dword ptr Z, eax pop eax Ret my_sub EndP my_mul proc push eax push edx mov eax, X mov edx ,Y imul edx mov dword ptr Z64, eax mov dword ptr Z64+4, edx pop edx pop eax Ret my_mul EndP out_math64 proc invoke my_mul invoke wsprintf,ADDR str_out_txt,ADDR f_t,dword ptr Z64 ,dword ptr Z64+4 push ebx push ecx mov ebx,offset str_out_txt mov ecx, len_str_out_txt invoke write_con pop ecx pop ebx invoke read_con Ret out_math64 EndP end start Прикрепил исходник. Зарание благодарен за ответ.
my_add Код (Text): push eax mov eax,[x] add [y],eax mov [z],eax pop eax ret my_sub Код (Text): neg [x] call my_add neg [x] ret прикрепите *.exe файл
При замене на консоли вместо ответа выходит "Х" с "+" или "-" ,но это мелочи связанные с тем, что для ответа есть третяя переменная "Z", ввёл её просто что бы не запутаться, потом уберу. И подход к вычетанию красивый, я бы даже сказал элигантный. Но при маленьких числах всё равно выходит пустая консоль. Прилогаю ...ЕХЕ .
Код (Text): CPU Disasm Address Hex dump Command Comments ;004010AE /$ 51 push ecx 004010AF |. 50 push eax 004010B0 |. A1 3D304000 mov eax,[dword ds:Console1.40303D] 004010B5 |. 0105 41304000 add [dword ds:Console1.403041],eax ;004010BB |. 8B0D 41304000 mov ecx,[dword ds:Console1.403041] ;004010C1 |. 890D 45304000 mov [dword ds:Console1.403045],ecx 004010BB |. 8B0D 41304000 mov eAx,[dword ds:Console1.403041] 004010C1 |. 890D 45304000 mov [dword ds:Console1.403045],eAx 004010C7 |. 58 pop eax ;004010C8 |. 59 pop ecx 004010C9 \. C3 retn CPU Disasm Address Hex dump Command Comments ;00401079 |. FF35 30304000 push [dword ds:Console1.403030] 00401079 |. 68 30304000 push offset Console1.00403030 0040107E |. 90 nop
Я так понимаю Код (Text): mov eax,[dword ds:Console1.40303D] add [dword ds:Console1.403041],eax mov ecx,[dword ds:Console1.403041] mov [dword ds:Console1.403045],ecx mov eAx,[dword ds:Console1.403041] mov [dword ds:Console1.403045],eAx это Код (Text): mov eax, [X] add [Y], eax ; Как у меня mov ecx, [Y] mov [Z], ecx mov eax, [Y] ;откуда это mov [Z], eax Откуда два последних "mov"? Хотя на результат не влияет и это скорее подсказка как убрать дополнительный ЕСХ, но почему ассемблер так завернул? А Код (Text): push [dword ds:Console1.403030] push offset Console1.00403030 nop это судя по всему передача параметров в WriteConsole. Только я всё равно не могу увязать как поподают данные в параметр offset str_out_txt в процедуре wsprintf. И как попадают данные в offset str_out_txt в процедуре WriteConsole? А главное почему данные одного размера попадают, а данные другого размера нет. Не пинайте пожалуйста сильно если ответ окажется очевидным. Для новичка в ассемблере очевидного черезвычайно мало.
Mars 1. Уберите FreeConsole и AllocConsole - это просто лишнее. 2. CloseHandle для stdin и stdout тоже лишнее. 3. В функции WriteConsole и ReadConsole 3-м (начиная с 0) параметром передается на значение переменной, а ее адрес, вследствие чего они могут не выводить или не вводить данные из/в консоль. 4. Для унификации вместо ReadConsole и WriteConsole можно использовать соответственно ReadFile и WriteFile
Всё лишнее убрал. По поводу параметров я и передавал адрес просто через регистры. Может ReadConsole и WriteConsole это вообще неудачный или нетипичный выбор? Тогда прошу совета как использовать ReadFile и WriteFile. В методологическом плане конечно. То есть: открыть файл; прочитать информацию; занести в переменную и.т.д. Самым схемотичным образом.
Mars Код (Text): 0040106B /$ 51 PUSH ECX 0040106C |. 53 PUSH EBX 0040106D |. BB 08304000 MOV EBX,Console1.00403008 ; ASCII " " 00401072 |. B9 10000000 MOV ECX,10 00401077 |. 6A 00 PUSH 0 ; /pReserved = NULL 00401079 |. FF35 30304000 PUSH DWORD PTR DS:[403030] ; |pWritten = NULL 0040107F |. 51 PUSH ECX ; |CharsToWrite => 10 (16.) 00401080 |. 53 PUSH EBX ; |Buffer => Console1.00403008 00401081 |. FF35 04304000 PUSH DWORD PTR DS:[403004] ; |hConsole = NULL 00401087 |. E8 02010000 CALL <JMP.&kernel32.WriteConsoleA> ; \WriteConsoleA 0040108C |. 5B POP EBX 0040108D |. 59 POP ECX 0040108E \. C3 RETN 0040108F /$ 6A 00 PUSH 0 ; /pReserved = NULL 00401091 |. FF35 39304000 PUSH DWORD PTR DS:[403039] ; |pRead = NULL 00401097 |. FF35 35304000 PUSH DWORD PTR DS:[403035] ; |ToRead = 1 0040109D |. 68 34304000 PUSH Console1.00403034 ; |Buffer = Console1.00403034 004010A2 |. FF35 00304000 PUSH DWORD PTR DS:[403000] ; |hConsole = NULL 004010A8 |. E8 D5000000 CALL <JMP.&kernel32.ReadConsoleA> ; \ReadConsoleA 004010AD \. C3 RETN по адресу 00401079 и 00401091 написано push dword ptr [offset], а должно быть push offset
Спасибо за файлы. Я даже не предпалогал, что есть такие большиевозможности для форматирования, и пример достаточно понятный попробую реализовать. Тогда останется организовать только ввод данных, но это будет уже следующий гранитный камушек. И ещё вопрос. Все исходники что я смотрел имели большой размер и в общем я так понимаю не для делающих первые шаги. В этм плане выше указанный wsprintf можно сказать самое, что надо. Может есть где ещё такие небольшие и обучающие программки. Смотрел в исходниках на VASM, мне явно туда рановато. Мой поталок консоль и я так думаю не скоро до него допрыгну
Mars по поводу Read/Write-File push 0 push offset n push n push offset s push STD_OUTPUT_HANDLE call GetStdHandle push eax call WriteFile вывод в консоль
Что то я совсем запутался или у моей машины мозги сломались вместе с моими. Я взял файл из проектов из книжки с точно такой же задачей и в итоге у автора после запуска ЕХЕ все отлично а у меня после компиляции ситуация не изменилась. Даже боюсь чего нибудь предположить. Пробывал с командной строки, WinAsm Studio, RedAsm. Результат один единственный но не такой какой нужен мне. Попробую прикрепить пример из книжки.
Mars и опять у вас все та же проблема. вы передаете значение из переменной, а надо ее адрес. напишите наконец-то уже слово offset между push и именами ваших злополучных переменных.