I'm trying to print a triangle like this: in assembly. The formula to find the number of stars in each row is: 2 * x + 1. Here is my code so far. I seem to be looping infinitely.
.data
prompt BYTE "Please enter the number of rows in the pyramid: ", 0
numRows DWORD ?
count DWORD 0
.code
main PROC
mov edx, OFFSET prompt
call WriteString
call ReadInt
mov numRows,eax
mov ecx,numRows + 1 ; Let ecx = numRows + 1
L1:
inc count ; Increment count
mov eax,ecx
L2:
sub eax,count ; eax = eax - count
mov al, ' ' ; Print spaces
call WriteChar
loop L2
L3:
mov ebx,count ; ebx = count
add ebx,count ; ebx = ebx + count
sub ebx,1 ; 2x - 1
mov al, '*' ; Printing the star pattern
call WriteChar
loop L3
call CrLf
loop L1
exit
main ENDP
END main
Where am I going wrong?
While this is not full answer, it got too long for a comment, and it should help you tremendously, because:
http://kipirvine.com/asm/debug/index.htm
This is basically the thing you should study first (and too broad+long to be part of this answer).
After you will know how to use debugger, you may take a look what your code is doing, for example one of first problems you will hit:
mov ecx,numRows + 1
doesn't do what you think it does, you can't use math expressions in assembly, you have to write them as single instructions.Only some instructions allow for some kind of very strict and limited math expression, like
mov
has for addressing-memory modes, which is actually what you get when you compile that:mov ecx,[numRows + 1]
= fetching value from +1 address.numRows
is DWORD, so if the user did enter 10, the memory looks like this (starting atnumRows
address:0A 00 00 00 00 00 00 00
- the first 4 bytes were set bymov numRows,eax
(which Irvine writes without[]
around memory reference, which is IMO very bad style/taste) 5th byte is atcount
address, which is defined bycount DWORD 0
line, so 4 zeroed bytes. Now themov ecx,[numRows + 1]
will thus fetch the 4 zeroes from memory, starting just after the0A
byte, and "leaking" one byte intocount
.Also math expressions are allowed in compile-time sense, i.e.
add eax,12+13*14
is OK, producing single constant during assembling. But you should read through docs like this to have idea which combination of arguments is legal,mov ecx,label + 1
can be either an immediate constant load (in NASM) = "address + 1", or memory load (value from address+1) in MASM, neither doing "value + 1".To do what you want you need to:
But as the eax already contains
numRows
value, you can avoid fetching the memory, so in this particular case this is enough:But as this math expression is trivial enough to fit one of possible addressing modes, you can exploit the
LEA
instruction to think it is calculating memory address, while it will just calculate your expression instead:This works, even if the eax+1 is illegal address into memory, but
LEA
will not try to read the address, it will just calculate it and store into destination register....etc, etc... the point here for you is:
1) learn to debug your code (this is absolutely essential to get anywhere further)
2) ditch the Irvine style and use
[]
rigorously around every memory dereference, i.e. around "variables", this would make you scratch your head probably sooner, if you would writemov ecx,[numRows]+1
(if you have idea whichmov
operands are legal, you should feel this doesn't look good).3) try to move your thinking in terms of "variables" toward lower level "memory -> address -> content (bytes)", the "variables" way will sometimes limit you in seeing opportunities how to manipulate your data at byte/bits level to achieve results you need in simpler way.