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
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.
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
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
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
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
raymond,
thanks for correcting me. You are right. I have no excuse!
:(
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
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
Quote from: *DEAD* on August 10, 2006, 08:13:02 AM
is
xor edx, edx
faster than
mov edx, 0
Hi DEAD, yes typically this is the case.
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.
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.