I am working with nested loops in assembly. The desired output should be "ABCD" (new line) "EFGH" (new line) "HIJK" (new line) "LMNO" but currently I am not getting any output. The whole loop will execute but nothing will appear in the console.
INCLUDE Irvine32.inc
.data
ALPHA byte "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"
count byte 4 ; inner loop counter
.code
main proc
mov esi, OFFSET ALPHA
mov ecx, 4 ;outer loop counter
mov ebx, 0 ; inner counter
call part1
main endp
;-----------------------------------------------------------------------------
;part1 proc
;print 4x4 letter matric
;Receives EBX: arr address ECX: outer loop counter
;Returns EAX: full array
;-----------------------------------------------------------------------------
part1 PROC USES ebx ecx edx esi
L1:
cmp ecx, 4 ; test outer loop count
je next ; yes?
call Crlf ; print new line
inc ecx
L2: ;inner loop
cmp ebx, ecx ;
mov eax, [esi] ; mov next letter
call WriteChar ; write it
inc esi ; point to the next element
inc ebx
loop L2 ; loop
next:
call Crlf
ret
part1 ENDP
end main
Your code does nothing what you describe.. let me step over single instruction with you, how the execution happens (this is not source code, but sequential write-down of instructions as they will be executed by CPU, with some minimal comments of important parts):
mov esi, OFFSET ALPHA
mov ecx, 4
mov ebx, 0
call part1
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning into main
; there is no more code in main, so the CPU continues
; with next memory interpreting it as machine code
; with a bit of luck (no padding between ENDP/PROC, or NOPs)
; the "part1" code follows after main, so it will get executed
cmp ecx, 4
je next ; jump is taken, because ecx == 4
call Crlf
... internal implementation of Crlf by Irvine32 ending with RET
ret ; part1 "ret" returning out of your code completely
; in some environments that may work as clean exit from app
; in others that ret will go to whatever address is at stack and crash
You should be capable to verify this in your debugger. I wonder what made you think the "The whole loop will execute" and "nothing will appear in the console", as clearly only minimal part of loop is being executed, and there should be two new lines in console appearing.
How to fix your code ... first add some kind of exit to the end of the main, if you are building win32 executables, then I think the standard way to exit Irvin32 programs is to use ExitProcess
(check working examples of Irvine32 package). I think something like invoke ExitProcess, 0
may work, invoke
is some kind of predefined macro which will expand into mov + call
instructions, but I don't have windows and/or Irvine32 to check myself.
Then make your mind, how you want actually to track the loops. For example put outer counter into ecx
and inner counter into ebx
, and because you know the size if fixed 4x4, do the count-down in do { ..; --counter; } while (counter);
style, which fits assembly way of coding naturally (but it doesn't check counter validity at first iteration, so this is good style only for case where counter is always valid value).
Like for example:
part1 PROC USES eax ebx ecx esi
mov ecx, 4
outerLoop:
mov ebx, 4 ; reset inner counter (for every outer loop)
innerLoop:
mov al, [esi] ; load next letter
call WriteChar
inc esi ; point to next element
dec ebx ; --innerCounter
jnz innerLoop
call Crlf ; print new line after 4 chars
dec ecx ; --outerCounter
jnz outerLoop
ret
part1 ENDP
Now this should produce in console something like this:
A,B,
C,D,
E,F,
G,H,
And that's because you did define the ALPHA
as one long string, including the commas, etc... You probably did want something like
ALPHA byte 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'
or the equivalent
ALPHA byte "ABCDEFGHIJKLMNOP"
both of them producing 16 bytes with values 65, 66, 67, ... ('A' == 65
).
Also in your original code the:
mov eax, [esi] ; mov next letter
will load four bytes. The WriteChar
does ignore the upper 24 bits of eax
and will use only bottom 8 bits (the "al
"), and you are incrementing esi
only by one, so in the end this is harmless bug, but you should understand how it works. mov al,[esi]
will fetch only 8 bits from memory, which is enough in this case, when working with characters.