The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: frktons on July 22, 2010, 11:20:30 PM

Title: How many errors did I make?
Post by: frktons on July 22, 2010, 11:20:30 PM
I feel a little disappointed, trying do write a very simple
routine in MASM32 and getting a lot of errors during assembling.

Here is the code. How many errors did I make?


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Dividing a number by ten and display result and remainder
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

include \masm32\include\masm32rt.inc

.data

     dd    div_result 0
     dd    remain      0
     dd    ten            10
     dd    num          17345


.code

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    xor     edx, edx
    mov   eax, num
    mov   ecx, ten
    idiv   ecx
    mov   div_result, eax
    mov   remain, edx
    mov   ecx, num

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; display results
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    print "Original number: ", str$(ecx), 13, 10, 13, 10
    print "Number after division by ten: ",str$(eax),13,10,13,10
    print "Remainder: ",str$(edx),13,10
    inkey "Press any key to close..."


    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Title: Re: How many errors did I make?
Post by: Magnum on July 22, 2010, 11:28:19 PM
For starters, your data should be in this format.

Name   size       Value

ex.

Number dw  1234
Title: Re: How many errors did I make?
Post by: frktons on July 22, 2010, 11:33:06 PM
Quote from: Magnum on July 22, 2010, 11:28:19 PM
For starters, your data should be in this format.

Name   size       Value

ex.

Number dw  1234

OK thanks, I changed in this way:

     div_result dw 0
     remain      dw 0
     ten            dw 10
     num          dw 17345


Still a lot of errors, maybe less than before.  :P
What else I made wrong?

Well according to masm I have to define the variables in this way:

     div_result dd 0
     remain      dd 0
     ten            dd 10
     num          dd 17345


And the errors are in the use of the macro print.
Title: Re: How many errors did I make?
Post by: KeepingRealBusy on July 22, 2010, 11:38:49 PM
I don't believe idiv gives you a remainder, just the quotient, but I do not use idiv so I may be wrong.
Title: Re: How many errors did I make?
Post by: frktons on July 22, 2010, 11:40:12 PM
Quote from: KeepingRealBusy on July 22, 2010, 11:38:49 PM
I don't believe idiv gives you a remainder, just the quotient, but I do not use idiv so I may be wrong.

The error is in the use of print macro the remain of the code
should be fine now.
Title: Re: How many errors did I make?
Post by: KeepingRealBusy on July 22, 2010, 11:44:06 PM
I looked it up, idiv does return a remainder.

Dave.
Title: Re: How many errors did I make?
Post by: frktons on July 22, 2010, 11:45:27 PM
Quote from: KeepingRealBusy on July 22, 2010, 11:44:06 PM
I looked it up, idiv does return a remainder.

Dave.

Yes Dave, That is correct. I have only to understand what I did
wrong with the print macro.
Title: Re: How many errors did I make?
Post by: jj2007 on July 22, 2010, 11:46:24 PM
print expects dwords, i.e. dd, not dw
in addition, you can't use literal text followed by str$. Split it as follows:

    print "Original number: "
    print str$(ecx), 13, 10, 13, 10
    print "Number after division by ten: "
    print str$(eax),13,10,13,10
    print "Remainder: "
    print str$(edx),13,10
    inkey "Press any key to close..."
Title: Re: How many errors did I make?
Post by: frktons on July 22, 2010, 11:53:01 PM
Quote from: jj2007 on July 22, 2010, 11:46:24 PM
print expects dwords, i.e. dd, not dw
in addition, you can't use literal text followed by str$. Split it as follows:

    print "Original number: "
    print str$(ecx), 13, 10, 13, 10
    print "Number after division by ten: "
    print str$(eax),13,10,13,10
    print "Remainder: "
    print str$(edx),13,10
    inkey "Press any key to close..."


Great, finally it assembled! but the result is very poor:

Original number: -1040318464

Number after division by ten: 30

Remainder: 1170728
Press any key to close...


Something is still wrong.  ::)
Title: Re: How many errors did I make?
Post by: frktons on July 22, 2010, 11:58:15 PM
OK I found the error, the correct version is:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Dividing a number by ten and display result and remainder
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

include \masm32\include\masm32rt.inc

.data

    div_result dd 0
    remain      dd 0
    ten            dd 10
    num          dd 17345


.code

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    xor     edx, edx
    mov    eax, num
    mov    ecx, ten
    idiv    ecx
    mov   div_result, eax
    mov   remain, edx
    mov   ecx, num

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; display results
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


    print "Original number: "
    print sstr$(num), 13, 10, 13, 10
    print "Number after division by ten: "
    print sstr$(div_result),13,10,13,10
    print "Remainder: "
    print sstr$(remain),13,10,13,10
    inkey "Press any key to close..."


    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


Now let's move a step further, I'm still very confused about declaring and
calling procedures in MASM.
I know we can push the parameters to pass, and pop them, or we can pass
them directly in the calling.
But I am not able to do either of them.

Could someone please use this code and make a procedure with the
instructions to divide, and the call to it passing the parameters?

Thanks
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 12:24:40 AM
you can combine the print and chr$ macros to handle literal strings
it is convenient, but you can't make multiple use of the string
        print   chr$('Hello',32,'World',13),10
i tried to show different ways to combine ASCII numerics, as well
the chr$() macro actually creates the null-terminated string and returns its' address for the print macro

here is one way to make the proc...
IDivide PROTO   :DWORD,:DWORD


IDivide PROC    dwDividend:DWORD,dwDivisor:DWORD

;Returns: EAX = Quotient
;         EDX = Remainder

        mov     eax,dwDividend
        xor     edx,edx
        idiv dword ptr dwDivisor
        ret

IDivide ENDP
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 12:44:38 AM
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Dividing a number by ten and display result and remainder
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

IDivide PROTO   :DWORD,:DWORD

        INCLUDE \masm32\include\masm32rt.inc

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Data Area
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

        .DATA

num        dd 17345

        .DATA?

div_result dd ?
remain     dd ?

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Code Area
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

        .CODE

_main   PROC

;divide "num" by 10

        INVOKE  IDivide,num,10
        mov     div_result,eax
        mov     remain,edx

; display results

        print   chr$('Dividend:  ')
        mov     eax,num
        print   str$(eax),13,10,13,10

        print   chr$('Quotient:  ')
        mov     eax,div_result
        print   str$(eax),13,10,13,10

        print   chr$('Remainder: ')
        mov     eax,remain
        print   str$(eax),13,10,13,10

;wait for a keypress and terminate

        inkey   "Press any key to close..."
        exit

_main   ENDP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Signed Integer Division Routine
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

IDivide PROC    dwDividend:DWORD,dwDivisor:DWORD

;Returns: EAX = Quotient
;         EDX = Remainder

        mov     eax,dwDividend
        xor     edx,edx
        idiv dword ptr dwDivisor
        ret

IDivide ENDP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
        END     _main
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 05:54:55 AM
Thanks Dave, it looks pretty clear  :U

So when I declare the procedure prototype I only declare the generic
data type to be passed:

IDivide PROTO   :DWORD,:DWORD


Any reason it is before the include:

IDivide PROTO   :DWORD,:DWORD

INCLUDE \masm32\include\masm32rt.inc

or it is the same?

When I call the procedure I just use the names of the variables:

INVOKE  IDivide,num,10


And the procedure is defined with both data type and name of variables:

IDivide PROC    dwDividend:DWORD,dwDivisor:DWORD
......
IDivide ENDP


Till now it looks pretty much like the C way of doing the same thing,
except I don't know if you can declare a return value as well or you just
take care of the address, registers to pass.

Well, now a little doubt about the difference between call and invoke.

Are they the same or they use different syntax and are used in different ways
for different purposes?

And the final doubt: if I use the old way of pushing and popping the
data between the calls by myself, how would I do that in this specific case?  ::)

Thanks for your patience.

Edit: a problem during assemblying time:

Microsoft (R) Macro Assembler Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Assembling: C:\masm32\examples\dividebythe_dave.asm
C:\masm32\examples\dividebythe_dave.asm(5) : error A2119:language type must be s
pecified
C:\masm32\examples\dividebythe_dave.asm(62) : error A2112:PROC and prototype cal
ling conventions conflict
_
Assembly Error
. . .


Well I had to change the order of include and proc prototype
in order to have it compiling successfully:

INCLUDE \masm32\include\masm32rt.inc

IDivide PROTO   :DWORD,:DWORD


And now it works fine:

Dividend:  17345

Quotient:  1734

Remainder: 5

Press any key to close...




Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 06:38:10 AM
I discovered a thread from 2004 that deals with call and invoke
better if I have a look:

call vs invoke (http://www.masm32.com/board/index.php?topic=239.0")

:P

Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 06:54:54 AM
yes - i should have caught that   :bg
but, i am pretty sure the PROTO must come before the INVOKE
PROTO is the difference between CALL and INVOKE (other than how the parms are pushed on the stack)
for INVOKE, the name must be pre-defined - not so for CALL

i used the constant 10, only because it is always the same value in this case
and, i wanted to demonstrate that a constant or a variable can be used as a parm
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:43:21 AM
Quote from: dedndave on July 23, 2010, 06:54:54 AM
yes - i should have caught that   :bg
but, i am pretty sure the PROTO must come before the INVOKE
PROTO is the difference between CALL and INVOKE (other than how the parms are pushed on the stack)
for INVOKE, the name must be pre-defined - not so for CALL

i used the constant 10, only because it is always the same value in this case
and, i wanted to demonstrate that a constant or a variable can be used as a parm


Thanks Dave. Your example was so clean, beginner friendly and somewhat
perfect that inverting the position of include and proto was
negligible stuff.  :P
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 02:29:01 PM
here is an exercise for you
the results display is essentially the same code, repeated 3 times
you could put that code in a PROC, and use INVOKE with the address of the string and the value to display
or, you could just make a simple loop to display the 3 lines
you could do both   :bg
although, if you put it in a loop, there may not be much advantage to making a PROC, also
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 02:34:48 PM
Quote from: dedndave on July 23, 2010, 02:29:01 PM
here is an exercise for you
the results display is essentially the same code, repeated 3 times
you could put that code in a PROC, and use INVOKE with the address of the string and the value to display
or, you could just make a simple loop to display the 3 lines
you could do both   :bg
although, if you put it in a loop, there may not be much advantage to making a PROC, also
Good suggestion Dave, as I find some free time and neurons in my disconnected brain
I'm goint to give it a try.  :P
Title: Re: How many errors did I make?
Post by: ecube on July 23, 2010, 02:42:39 PM
you make a C proc like so

whatever proto C :DWORD

whatever proc C val1:DWORD

ret
whatever endp


good thing about about the c calling convention(cdecl) is the caller is the one who adjusts the stack instead of the function itself like stdcall(what the regular procs use), meaning you can specify unlimited parameters. All windows api is stdcall minus wsprintf, i'm not sure why windows went with stdcall in 32bit, for 16bit they used pascal calling convention which is the same thing as cdecl only the params are pushed the opposite direction.
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 02:46:29 PM
Quote from: E^cube on July 23, 2010, 02:42:39 PM
you make a C proc like so

whatever proto C :DWORD

whatever proc C val1:DWORD

ret
whatever endp


good thing about about the c calling convention(cdecl) is the caller is the one who adjusts the stack instead of the function itself like stdcall(what the regular procs use), meaning you can specify unlimited parameters. All windows api is stdcall minus wsprintf, i'm not sure why windows went with stdcall in 32bit, for 16bit they used pascal calling convention which is the same thing as cdecl only the params are pushed the opposite direction.

Thanks E^cube.

It would be better if you add some more lines of asm code in order to make
me understand what you mean, I'm not that smart for the time being.  :P
Title: Re: How many errors did I make?
Post by: ecube on July 23, 2010, 02:54:29 PM
a cdecl function looks like this

push p3
push p2
push p1
call myfunc
add esp, 12  <---see the stack is adjust after the call

myfunc proc C p1,p2,p3
ret
myfunc endp


a stdcall function looks like

push p3
push p2
push p1
call myfunc

myfunc proc p1,p2,p3
;whatever
retn 12        <---see the stack is adjusted inside, u don't need to do this yourself, unless u turn off the epilog, as masm does it for u
myfunc endp
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 03:11:41 PM
Quote from: E^cube on July 23, 2010, 02:54:29 PM
a cdecl function looks like this

push p3
push p2
push p1
call myfunc
add esp, 12  <---see the stack is adjust after the call

myfunc proc C p1,p2,p3
ret
myfunc endp


a stdcall function looks like

push p3
push p2
push p1
call myfunc

myfunc proc p1,p2,p3
;whatever
retn 12        <---see the stack is adjusted inside, u don't need to do this yourself, unless u turn off the epilog, as masm does it for u
myfunc endp


This is a way of using something C-like inside MASM you mean.
OK. Thanks.
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 10:55:12 PM
And here we have the exercise my assembly master Dave
gave me:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Dividing a number by ten and display result and remainder
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

INCLUDE \masm32\include\masm32rt.inc

IDivide PROTO   :DWORD,:DWORD
Display_num PROTO :DWORD,:DWORD


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Data Area
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.DATA

num        dd 17345
str1       db "Dividend: ",0
pstr1      dd str1
str2       db "Quotient: ",0
pstr2      dd str2
str3       db "Remainder: ",0
pstr3      dd str3

.DATA?

div_result dd ?
remain     dd ?

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Code Area
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.CODE

_main   PROC

;divide "num" by 10

        INVOKE  IDivide,num,10
        mov     div_result,eax
        mov     remain,edx
        Invoke  Display_num,num,pstr1
        Invoke  Display_num,div_result,pstr2
        Invoke  Display_num,remain,pstr3

;wait for a keypress and terminate

        inkey   "Press any key to close..."
        exit

_main   ENDP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; ; display results
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Display_num PROC    numx:DWORD,ptrx:DWORD

        print   ptrx
        mov     eax,numx
        print   str$(eax),13,10,13,10
        ret

Display_num ENDP


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Signed Integer Division Routine
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

IDivide PROC    dwDividend:DWORD,dwDivisor:DWORD

;Returns: EAX = Quotient
;         EDX = Remainder

        mov     eax,dwDividend
        xor     edx,edx
        idiv dword ptr dwDivisor
        ret

IDivide ENDP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
        END     _main
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««


and strange enough it seems to work  :P
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 11:00:18 PM
very nice, Frank   :U

don't need the pointers, though...
str1    db "Dividend:  ",0
str2    db "Quotient:  ",0
str3    db "Remainder: ",0
;
;
;
        Invoke  Display_num,num,offset str1
        Invoke  Display_num,div_result,offset str2
        Invoke  Display_num,remain,offset str3


if you were to use the loop method, then you might want the pointers in a table
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:01:31 PM
Quote from: dedndave on July 23, 2010, 11:00:18 PM
very nice, Frank   :U

Thanks Master  :bg
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:12:52 PM
Quote from: dedndave on July 23, 2010, 11:00:18 PM

don't need the pointers, though...

str1    db "Dividend:  ",0
str2    db "Quotient:  ",0
str3    db "Remainder: ",0
;
;
;
        Invoke  Display_num,num,offset str1
        Invoke  Display_num,div_result,offset str2
        Invoke  Display_num,remain,offset str3


if you were to use the loop method, then you might want the pointers in a table

Well That is an improvement as well.  :U and a new thing to keep in
mind.  I was thinking about the loop and the table for the pointers, but
I'm not sure how to do it.

Could you show me how to apply that modification to the code?

Thanks
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 11:14:59 PM
here is one way...
DsplyTbl   dd str1
num        dd 17345
           dd str2
div_result dd ?
           dd str3
remain     dd ?

str1       db "Dividend:  ",0
str2       db "Quotient:  ",0
str3       db "Remainder: ",0

;
;
;

        mov     edx,offset DsplyTbl
        mov     ecx,3

Dsply:  push    ecx
        push    edx
        mov     eax,[edx]
        print   eax
        mov     edx,[esp]
        mov     eax,[edx+4]
        print   str$(eax),13,10,13,10
        pop     edx
        pop     ecx
        add     edx,8
        dec     ecx
        jnz     Dsply


after looking at it, the INVOKE method looks a lot cleaner   :lol
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:19:48 PM
Quote from: dedndave on July 23, 2010, 11:14:59 PM
here is one way...
DsplyTbl   dd str1
num        dd 17345
           dd str2
div_result dd ?
           dd str3
remain     dd ?

str1       db "Dividend:  ",0
str2       db "Quotient:  ",0
str3       db "Remainder: ",0

;
;
;

        mov     edx,offset DsplyTbl
        mov     ecx,3

Dsply:  push    ecx
        push    edx
        mov     eax,[edx]
        print   eax
        mov     edx,[esp]
        mov     eax,[edx+4]
        print   str$(eax),13,10,13,10
        pop     edx
        pop     ecx
        add     edx,8
        dec     ecx
        jnz     Dsply


after looking at it, the INVOKE method looks a lot cleaner   :lol

Yeah, the procs tend to organize the code in a better fashion, but
it is good to know there are less elegant ways too.  :P

Thanks for this example.  :U
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:23:18 PM
Is there any reason you intermixed the pointers with the
numbers putting them before the numbers themselves?

DsplyTbl   dd str1
num        dd 17345
           dd str2
div_result dd ?
           dd str3
remain     dd ?


Would it be the same if the pointers are put after the numeric variables?
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 11:25:27 PM
in the loop - the string pointer is used first, is all
they could be swapped with no real difference
the loop would need to be modified slightly - so the string pointer is [edx+4] and the value is [edx]
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:28:53 PM
Quote from: dedndave on July 23, 2010, 11:25:27 PM
in the loop - the string pointer is used first, is all
they could be swapped with no real difference
the loop would need to be modified slightly - so the string pointer is [edx+4] and the value is [edx]

Well it is a question of correctly addressing the locations of memory
we need, so if we change the position, the offset changes accordingly.

Good - thanks
Title: Re: How many errors did I make?
Post by: dedndave on July 23, 2010, 11:34:00 PM
your INVOKE code is still cleanest - lol
Title: Re: How many errors did I make?
Post by: frktons on July 23, 2010, 11:38:30 PM
Quote from: dedndave on July 23, 2010, 11:34:00 PM
your INVOKE code is still cleanest - lol

That is because I don't understand it otherwise  :lol