News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

How many errors did I make?

Started by frktons, July 22, 2010, 11:20:30 PM

Previous topic - Next topic

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

dedndave

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

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

ecube

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.

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

ecube

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

frktons

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.
Mind is like a parachute. You know what to do in order to use it :-)

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

dedndave

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

frktons

Mind is like a parachute. You know what to do in order to use it :-)

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

dedndave

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

frktons

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
Mind is like a parachute. You know what to do in order to use it :-)

frktons

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?
Mind is like a parachute. You know what to do in order to use it :-)

dedndave

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]