Assembly Count to Zero
Question
I am trying to teach myself Assembly (out of curiosity and interest of learning) and have developed some code that counts from five to 0. Thats all it does. I was wondering if the following code was efficient?
.386
.model flat, stdcall
.data
i dd 5
.code
main:
MOV cx, 5
lp:
LOOP lp
MOVZX eax, cx
RET
END main
Notice that I use the MOVZX
instruction to copy the value of cx
into eax
(what my compiler uses to return).
I do this because my program won't assemble if I simply use MOV
. Is using MOVZX
desireable? Or is there a more efficient way I should be doing this?
You will notice also in my code that I have i dd 5
my original plan was to MOV cx, i
but my compiler refuses to assemble when I attempt that. (MOVSX
yields the same result). So my second question is, how can I move the value of i
into the cx
register?
Solution
If you're writing for a 32-bit target, then use the ecx
register instead of the 16-bit cx
register. Then, you will be able to use mov eax, ecx
without the assembler complaining about operand sizes. Also, the loop
instruction implicitly uses ecx
so you'll want to make sure the whole register is initialised with 5, and not just the lower 16 bits.
After using ecx
, the instruction mov ecx, i
may work - but you didn't say what actual error you were getting when you tried that.
OTHER TIPS
Your code isn't very efficient, no. The LOOP instruction is old and rarely used anymore because it doesn't tend to perform as well as simply manually decrementing.
You can zero a register by XORing it with itself, and you can then load a number into it with an immediate ADD. I don't use assembly much, so I don't have the syntax down solidly and unfortunately can't post an example.
Here's a C example that's analogous to yours:
#include <stdio.h>
int i = 5;
int
main (int argc, char *argv[])
{
while (--i >= 0)
;
return 0;
}
Here's the Visual Studio assembler output (cl /Fa):
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _i
_DATA SEGMENT
_i DD 05H
_DATA ENDS
PUBLIC _main
_TEXT SEGMENT
_main PROC NEAR
; File x.c
; Line 7
push ebp
mov ebp, esp
$L342:
; Line 8
mov eax, DWORD PTR _i
sub eax, 1
mov DWORD PTR _i, eax
cmp DWORD PTR _i, 0
jl SHORT $L343
; Line 9
jmp SHORT $L342
$L343:
; Line 10
xor eax, eax
; Line 11
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END