News:

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

need help getting one of my first programs to work

Started by *DEAD*, August 09, 2006, 02:33:27 PM

Previous topic - Next topic

*DEAD*

hi again, im completely new to masm, but im trying to make a few programs to give me an excuse to learn asm. Right now, im trying to make a program for doing fractorials, and i seem to be having trouble with the mul operand


    .486                           
    .model flat, stdcall                 
    option casemap :none                 
   
    include \masm32\include\windows.inc   
    include \masm32\macros\macros.asm   

    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    .code                     

start:     

    call main           

    exit

main proc
    LOCAL count:DWORD
    LOCAL countto:DWORD
    LOCAL fract:DWORD
 
    mov count, 0
    mov fract, 1
    mov countto, sval(input("factorial of: "))
    print chr$(13,10)

    loopbegin:
       inc count
       mul fract, count                         ;line 39
       cmp count, countto                   ;line 40
       je loopexit
       jmp loopbegin

    loopexit:
    print str$(fract)
    ret

main endp

end start   

i get the errors
fract.asm(39) : error A2008: syntax error :   
fract.asm(40) : error A2070: invalid instruction operand

i had a program before which counted from 0 - whatever using essentially the same loop design.
just
cmp var1, 100
instead of
cmp count, countto

thanks for any help avalible


hutch--

The CMP line is the easiest, you cannot do a direct compare from one memory opernd to another as there is no opcode in x86 to do that. You must copy one of the two memory operands to a register to perform the comparison.

The MUL line is a bit more complicated, it normally takes one operand while the other value is in the AL, AX or EAX register depending on the data size to be multiplied. here is a quick example.


main proc

    LOCAL var   :WORD

    cls

    mov var, 6              ; put a value into "var"
    mov eax, 12             ; load EAX with another value
    mul var                 ; multiply EAX by var

    print str$(eax),13,10   ; display the return value in EAX

    ret

main endp


Something to keep in mind with assembler instructions is the operand type, you have 3 possibles,

1. a register                 ; EAX for example
2. a memory operand   ; var
3. an immediate value  ; 1234  as a direct number.

The operand that you can put with instructions are dictated by the available opcodes.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

TNick

mul takes just 1 operand, and it multiplies it with eax. so:


inc count
xor  edx, edx
mov eax, fract
mul count


cmp can compare register against register, register against memory, memory or register against an immediate value, but never memory against memory

Youcan write your loop like this:


mov   ecx,  count
loopbegin:
      inc ecx
     xor edx, edx
     mul fract
      cmp ecx, countto
      je loopexit
      jmp loopbegin





raymond

TNick is not helping much except for the comparison of the count.

1st, there is NO need to zero EDX before a multiplication (only before a division and, even then, not always).

2nd, one of the registers must contain one of the parameters for the multiplication. The EAX register is the dedicated one with the mul mnemonic, and the result is then a 64-bit value in the EDX:EAX pair.

With the mul mnemonic, the other parameter can be another register or a memory variable (the mul mnemonic will not accept an immediate value).

With 32-bit assembly, there is no single mnemonic to multiply numbers greater than 32 bits. Once you get a factorial exceeding 32 bits (13!), you will not be able to continue generating further factorials with a single multiplication. Even displaying that first factorial exceeding 32 bits cannot be done the same way as for the previous ones.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

*DEAD*

thanks everyone, i knew that after i went past 32 bits id be in trouble, i just needed something to practice asm, so i chose fractorials as it was releatively easy and didnt require floating points. I have two last questions though.

is
xor edx, edx
faster than
mov edx, 0

and also, i know i wont be able to use it anyway because my variable is only 32 bits, but how would i string the edx:eax together to get the 64 bit answer. thanks

raymond

Quotebut how would i string the edx:eax together to get the 64 bit answer

EAX is the low dword portion while EDX is the high dword portion. If you want to store them in memory in the proper order as a QWORD, the content of EAX must be at the lower address. Ex.:

.data
myqword dq ?

.code
mov edi,offset myqword
mov [edi],eax
mov [edi+4],edx

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

TNick

raymond,

thanks for correcting me. You are right. I have no excuse!
:(

*DEAD*

#7
why is the eax moved into myqword first, and edx second. i though that mul gave an edx:eax pair, so i would have though it would be edx, then eax like:

0000 0000
^edx ^eax

or is that not how the pointer works, does it work backward or something

edit, ive made a program which i think will multiply higher numbers, im not sure yet, im getting another operand error that i cant seem to figure out. its the offset, and as far as i can tell its used in the exact same way as raymonds little example was.


    .code                     

start:     

    call main           

    exit


main proc
    LOCAL count:DWORD
    LOCAL countto:DWORD
    LOCAL fractl:DWORD
    LOCAL fracth:DWORD
    LOCAL carry:DWORD
    LOCAL fract:QWORD
       
      mov count, 0
      mov fractl, 1
      mov fracth, 0
      mov countto, sval(input("factorial of: "))

      loopbegin:
  inc count                    ; add one to count

        mov eax, fractl
        mul count                    ; multiply the first 4 bits of fract
        mov fractl, eax              ; move first 4 bits into fractl
        mov carry, edx               ; move bits over 4 bits into carry to be added onto the next 4 bits
        mov eax, fracth
        mul count                    ; multiply the second lot of 4 bits
        add eax, carry               ; add extra bits from the previous multiplication
        mov fracth, eax              ; move second lot of 4 bits into fracth
        push edi                     ; save edi
        mov edi, offset fract        ; doesnt like it, give error "error A2098: invalid opperand offset
        mov eax, fracth             
        mov [edi], eax               ; mov fracth into the upper portion of fract
        add edi, 4                   ; add 4 to edi
        mov eax, fractl             
        mov [edi], eax               ; mov fractl into ther lower portion of fract
        pop edi                      ; restore edi
        mov eax, countto
  cmp count, eax               ; compare count to countto
  je loopexit                  ; if count = countto exit
  jmp loopbegin                ; jump to top of loop

loopexit:
      print str$(fract)
    ret

main endp


end start       

raymond

You cannot use "offset" with LOCAL variables, only with global variables for which the assembler knows the address at compile time. Use "lea edi,fract" instead.

And you would be storing the fracl and frach in the wrong order; fracl goes at the lower address in the qword.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Mark Jones

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

*DEAD*

thanks raymond and everyone else, the help is really appreciated, and i am sorry for asking really noobish questions, i havent had read enough material yet to answer them myself yet. now i have one last question that should sum everything up. I get to the print str$(fract) alright, but then it tells me i have a type mismatch (yes i do actually know what this one is, lol). How do i display a qword. ive tried looking though the the windows.inc and masm32.inc for something  with a print ..... command but if there was one in there i must have missed it.

hutch--

DEAD,

have a look in the High level Help file in masm32 for the "C Runtime Conversions" that were written by Greg Lyons. You have conversions in both directions. The functions are in the MSVCRT.DLL that is part of the OS from early win95 onwards.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php