Hello I am new to assembly and I'm struggling to get a two-part program to work. I am using Visual Studio for this x86 assembly.
Part I) My first goal is to count up to 13, adding each value on the way there. Ex, 0+1+2+3...+13=91. I want to store that total in totall.
Part 2) Secondly, I want to count up by the powers of 2 from 2^0 to 2^6. Ex, 0,1,2,4,8,32,64. I think* I am doing that but I am not storing each value as I go. I want to store these in consecutive memory locations.
I have this so far,
.586
.MODEL FLAT
.STACK 4096
.DATA
num1 BYTE 13 ;Initialize number to count to
totall BYTE 0 ;Total of all counted numbers
temp BYTE 0 ;Temp for loop adding
shiftme BYTE 1 ;Start of counting 2^0 so I can reach 2^6
.CODE
main PROC
;code here
increment: ;Increment label
inc temp ;Increment temp by 1
mov eax, temp
add totall, eax ;Add temp+totall and store in totall
cmp eax, num1 ;Compare for jump
jne increment ;Jump if not equal
;this part should store each value 1,2,4,8,32.. in consecutive memory locat
shiftallthethings: ;Shift label
shl shiftme, 1 ;Shifting bits to the left one
cmp shiftme, 64 ;Comparing for the jump
jne shiftallthethings ;Jump if not equal to
ret
main ENDP
END
Questions to help me understand.
Any help is GREATLY appreciated, thanks.
First of all, in answer to your questions:
How does one store values in consecutive memory locations?
In MASM32, you can either directly do a mov
like mov sum_addr, eax
(as long as the data types have the same size) or you can pass around data pointers. In the example I wrote, a pointer to total
is passed to the function. The function then writes a value to the memory pointed to by that pointer (i.e. contents of total
). Not quite sure what you mean by consecutive memory locations. If you mean pointer arithmetic, I can show you an example of that too.
Am I using the jump and label instructions correctly?
Yes, that seems to be fine. An alternative which I have use is anonymous labels. This is appropriate when the label is trivial and is fairly close by. It's personal preference. If you feel a label name is more appropriate, feel free to use that too.
Do I need to use specific registers like eax to perform these problems? Why?
MASM32 follows the call convention of Win32 (stdcall), so it's good for you to do that too. In terms of register preservation, it means that all functions are expected to preserve registers except for eax
, ecx
and edx
which are deemed trashable. Return values are stored in eax
or eax
and edx
if more than 4 bytes is required.
In terms of the code you have written, you have a few problems such as attempting to move different size data types into each other. For example, if you move a byte
into a dword
, you must extend it to be of the same size first.
mov eax, temp
That will not compile because temp
is only 1 byte long, whereas eax
is 4 bytes. You could do instead:
movzx eax, temp
This zero-extends temp
before doing the move. Here is some code I've thrown together which might teach you a few things. It uses macros (not sure if you want to learn those yet), but otherwise demonstrates idiomatic MASM32 parameter passing and return values.
include \masm32\include\masm32rt.inc
.DATA
total DWORD 0 ;Total of all counted numbers
.CODE
; takes in address of total and writes the value there
sum PROC sum_addr:DWORD
xor eax, eax
xor ecx, ecx
@@:
inc ecx
add eax, ecx
cmp ecx, 13
jnz @b
mov edx, sum_addr
mov dword ptr ds:[edx], eax
print ustr$(eax), 13, 10
mov edx, sum_addr
mov eax, dword ptr ds:[edx]
ret
sum ENDP
start:
push offset total ; pass address of total
call sum
print ustr$(eax), 13, 10 ; demonstrating how to use return values
print ustr$(total), 13, 10 ; testing result got stored properly
ret
end start
END
The code is not optimised but should be easily understandable. Notice how I have tried to use registers as much as possible (this is more efficient than constantly dealing with memory if we have enough registers).