News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Having trouble with code

Started by sabernal, June 04, 2013, 08:30:25 AM

Previous topic - Next topic

sabernal

I have this code here which is supposed to fill an array with the digits that the user enters and then print them, but I'm new to masm32 and its giving me a lot of trouble, its getting into somekind of infinite loop and not printing anything that I enter into the array..

.386
.model flat,stdcall
option casemap :none
include\masm32\include\windows.inc
include\masm32\include\kernel32.inc
include\masm32\include\masm32.inc
include\masm32\include\user32.inc
includelib\masm32\lib\kernel32.lib
includelib\masm32\lib\masm32.lib
includelib\masm32\lib\user32.lib

.data
MsgNum db "Insert amount of digits -> ", 0
MsgDigit db "Inserte digit -> ", 0

.data?
numDigit db 2 dup (?)
digits dword 36 dup (?)
digit db 2 dup (?)
.code

start:

invoke StdOut, addr MsgNum
invoke StdIn, addr numDigit , 10
invoke atodw, addr numDigit
mov ebx, eax
mov edx, 0
get:
    push edx
    invoke StdOut, addr MsgDigit
    invoke StdIn, offset digit, 10
    invoke atodw, offset digit
    mov digits[edx*4], eax
    pop edx
    inc edx
    cmp edx, ebx
    jne get
   
mov ecx, 0
prnt:
    push ecx
    mov ebx, digits[ecx*4]
    invoke dwtoa, ebx,addr digit
    invoke StdOut, addr digit
    pop ecx
    inc ecx
    cmp edx, ecx
    jne prnt

invoke ExitProcess, 0



Im probably doing something really stupid but Im having a hard time trying to figure out what exactly

qWord

The buffers are to small - the StdIn function internally use ReadFile with the specified buffer size. The problem is that the line break is not correctly removed from the input stream, if the buffer is to small (for window a line break consist of two bytes: CR,LF == 13,10) - this cause garbage input for further reads.
For the first loop, EDX is used before it has been recovered from the stack. The second loop overwrites EBX that holds the requested digit count.

include \masm32\include\masm32rt.inc ; <- does default setup

.const
        szMsgNum        db "Insert amount of digits -> ", 0
        szMsgDigit      db "Inserte digit -> ", 0
.code
main proc ; advantage of using a PROC: local variables + the labels "get" and "prnt" are not global
LOCAL szNumDigits[128]:BYTE     ; generously buffer size!
LOCAL szDigit[128]:BYTE         ;
LOCAL digits[36]:ptr BYTE

        invoke StdOut, offset szMsgNum
        invoke StdIn, addr szNumDigits, LENGTHOF szNumDigits
        invoke atodw, addr szNumDigits
        mov ebx, eax
        xor edx,edx   ;mov edx, 0 ; using esi or edi would saves the PUSH/POP pair
        get:
            push edx
            invoke StdOut, offset szMsgDigit
            invoke StdIn, addr szDigit, LENGTHOF szDigit
            invoke atodw, addr szDigit
            pop edx                                             ; <-------
            mov digits[edx*4],eax
            inc edx
            cmp edx, ebx
            jne get
           
        xor ecx,ecx ; mov ecx,0
        prnt:
            push ecx
            mov edx, digits[ecx*4]                              ; <------
            invoke dwtoa, edx,addr szDigit
            invoke StdOut, addr szDigit
            pop ecx
            inc ecx
            cmp ecx,ebx
            jne prnt

        invoke ExitProcess, 0
       
main endp
end main
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

the buffers should be 256 bytes, as i recently learned - lol

watch the pointers and counters
EAX, ECX, and EDX are likely to be trashed when calling other routines
also - you were missing "end start" - the end directive should reference the entry point

otherwise, pretty good for a newbie   :t

.386
.model flat,stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib

.data
MsgNum db "Insert amount of digits -> ", 0
MsgDigit db "Inserte digit -> ", 0

.data?
numDigit db 256 dup (?)
digits dword 36 dup (?)
digit db 256 dup (?)
.code

start:

invoke StdOut, addr MsgNum
invoke StdIn, addr numDigit , 256
invoke atodw, addr numDigit
mov ebx, eax
mov edx, 0
get:
    push edx
    invoke StdOut, addr MsgDigit
    invoke StdIn, offset digit, 256
    invoke atodw, offset digit
    pop edx
    mov digits[edx*4], eax
    inc edx
    cmp edx, ebx
    jne get
   
mov ecx, 0
prnt:
    push ecx
    push edx
    mov ebx, digits[ecx*4]
    invoke dwtoa, ebx,addr digit
    invoke StdOut, addr digit
    pop edx
    pop ecx
    inc ecx
    cmp edx, ecx
    jne prnt

invoke ExitProcess, 0

end start

sabernal

Wow thanks for the help, I see what you guys are saying.. Reading the code "qWord" posted I see he wrote that esi or edi would save the push/pop bit, didnt know that, gonna have to read a bit more about asm hahaha thanks

dedndave

that's not really dictated by asm, per se
it's called the "Windows ABI" (Application Binary Interface)

it says that EBX, EBP, ESI, and EDI are preserved across function calls
EAX, ECX, and EDX may be trashed, and are often used to return results (specifically, EAX)
the direction flag should remain cleared (up direction) before calling a function

we generally write our subroutines to follow the same set of rules
that way, they can be used anywhere an API function can be