Arrays in MASM Assembly (very confused beginner) - arrays

I have a pretty basic question:
How do you populate arrays in assembly? In high level programming languages you can use a for-loop to set a value to each index, but I'm not sure of how to accomplish the same thing assembly. I know this is wrong, but this is what I have:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD ?
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
mov ecx, LENGTHOF warray
L1:
mov ax, [edi] ;i want to move a number from warray to ax
movzx esi,ax ;i want to move that number into darray...
add edi, TYPE warray ;this points to the next number?
loop L1
call ExitProcess
main ENDP
END
Each time the loop runs, ax will be overwritten with the value of the array's index, right? Instead how do I populate darray with the array elements from warray? Any help would be very much appreciated...I'm pretty confused.

There are more than one way to populate an array and your code is almost working. One way is to use counter in the indirect address so you don't have to modify destination and source array pointers each loop:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD 4 dup (?) ; 4 elements
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
xor ecx, ecx ; clear counter
L1:
mov ax, [edi + ecx * 2] ; get number from warray
movzx [esi + ecx * 4], ax ; move number to darray
inc ecx ; increment counter
cmp ecx, LENGTHOF warray
jne L1
call ExitProcess
main ENDP
END
Of course this code could be modified to fill the array backwards to possibly save couple of bytes like you probably meant to do in your original code. Here is another way that has more compact loop:
ExitProcess PROTO
.data
warray WORD 1,2,3,4
darray DWORD 4 dup (?) ; 4 elements
.code
main PROC
mov edi, OFFSET warray
mov esi, OFFSET darray
mov ecx, LENGTHOF warray - 1 ; start from end of array
L1:
mov ax, [edi + ecx * 2] ; get number from warray
movzx [esi + ecx * 4], ax ; move number to darray
loop L1
; get and set element zero separately because loop terminates on ecx = 0:
mov ax, [edi]
movzx [esi], ax
call ExitProcess
main ENDP
END
You should also note that when working with arrays of the same type you can do simple copy very efficiently using repeat prefix with instructions like MOVSD:
ExitProcess PROTO
.data
array1 DWORD 1,2,3,4
array2 DWORD 4 dup (?)
.code
main PROC
mov esi, OFFSET array1 ; source pointer in esi
mov edi, OFFSET array2 ; destination in edi
mov ecx, LENGTHOF array1 ; number of dwords to copy
cld ; clear direction flag so that pointers are increasing
rep movsd ; copy ecx dwords
call ExitProcess
main ENDP
END

You're probably not "supposed to know" this, but anyway, there were (way back when) an instruction and an instruction prefix that were made to do exactly this.
Take a look here at this Microsoft page: HERE (click on it)
On that page scroll down until you find this phrase...
"...These instructions are remnants of the x86's CISC heritage and in recent processors are actually slower than the equivalent instructions written out the long way...."
What you do is...
Put the size of the array in Ecx
Point Edi at the start of the arry
Use the appropriate string instruction to populate it
The syntax (Masm/Tasm/etc.) will probably look something like this...
Mov Ecx, The_Length_Of_The_Array ;Figure this out somehow
Lea Edi, The_Target_You_Want_To_Fill ;Define this somewhere
Now, if you want to copy from one place to another, do this...
Lea Esi, The_Source_You_Want_To_Copy ;Whatever, define it
Cld ;This is the direction flag, make it inc
Rep Movsb ;Movsb means move byte for byte
Now, if you want to stuff the same value in each byte in the arrray do this...
Mov AL, The_Value_You_Want_To_Stuff ;Define this to your liking
Cld ;This is the direction flag, make it inc
Rep Stosb ;Stosb means store AL into each byte
Again, these instructions are, for reasons others will elucidate, not cool anymore and if you use them you will get cooties or something.
There are also string instructions for comparison, "Scanning", "Loading", and so on. They were once quite useful (and still are, but the "modern" gang today won't admit it) particularly with the Rep prefix added to them.
If this helps, but you need more detail, feel free to ask.

Related

Array that copies its contents to another array backwards is not working properly

When I run through this code it is my understanding that arrayA will be copied to arrayB backwards. So when I try to view what's in arrayB[1], it should be 6, but it's coming out to 0.
I know this code is inefficient. This is only an exercise to use the operators offset, sizeof and lengthof to avoid direct memory access and any use of constants. I'm a student, so the simplest fix is the best fix.
.386
.model flat,stdcall ; memory system
.stack 4096 ; declare stack memory size 4kb
ExitProcess proto,dwExitCode:dword
.data
arrayA word 01d, 05d, 06d, 02d
arrayB word 00d, 00d, 00d, 00d
.code
main proc
mov eax, 0
mov esi, offset arrayA
mov ecx, sizeof arrayA
mov ebx, lengthof arrayB
sub ebx, 1
L1:
mov ax, [esi]
add esi, type arrayA
mov arrayB[ebx], ax
sub ebx, 1
sub ecx, type arrayA
cmp ecx, 0
jne L1
mov ax, arrayB[1]
invoke ExitProcess,0
main endp
end main

Issue adding values in array x86

I'm trying to take an array, add all the values in it, and then display them. Unfortunately for me, even though the following code builds, the output doesn't return the value which I am expecting.
For instance, one time when I ran it, I got
-2112902102
and another time I got
-1280521519
I'm assuming there's some sort of logic to that, but it doesn't exactly help me.
INCLUDE Irvine32.inc
.386
.stack 4096
ExitProcess proto,dwExitCode:dword
.data
array SBYTE 26, -81, -104, -57
total_sum SWORD ?
.code
main proc
mov esi, OFFSET array
mov ecx, LENGTHOF array
mov total_sum, 0
mov ebp,0
L1:
add ebp, [esi]
inc esi
loop L1
mov edx, ebp
call WriteInt
invoke ExitProcess,0
main endp
end main
And yes, I know that total_sum isn't doing anything at this point, but I first want to figure the rest out before implementing total_sum.
As you have been hinted, the problem is that you add dwords instead of bytes. The simple solution is to sign extend the byte into a temporary register before summing. That is replace this:
add ebp, [esi]
With:
movsx edx, byte ptr [esi]
add ebp, edx
And of course for printing you need to use eax, so change mov edx, ebp to mov eax, ebp. Or you could just use that to do the summing up directly.

Assembly x86, looping and replace values in an array

Hey I need to make a program that loops through an array (1,2,3,4,5,6,7,8,9,10) and exchanges the element ‘i’ with element ‘i+5’ when ‘i' is under 4 When the program ends, the new array has the following values 6,7,8,9,10,1,2,3,4,5
and right now I have it looping through the array
.386
.model flat,stdcall
.stack 4096
ExitProcess proto,dwExitCode:dword
WriteDec PROTO
Crlf PROTO
DumpRegs PROTO
.data
arrayB WORD 1,2,3,4,5,6,7,8,9,10
.code
main proc
mov eax,0
mov edi,OFFSET arrayB ; address of arrayB
mov ecx,LENGTHOF arrayB ; loop counter
mov ax,0 ; zero the accumulator
L1:
mov ax,[edi] ; mov current edi value from array into ax
xchg arrayB, ax ;change the current ax register with the value in arrayB
add edi,TYPE arrayB ; point to next integer
loop L1
call DumpRegs
call WriteDec
call crlf
invoke ExitProcess,0
main endp
end main
But Im having trouble actually a) telling when the loop is under 4, and b) replacing the values correctly. Any help would be greatly appreciated
Edit: I do know I can use "cmp" to compare the ecx register
Your task description is inconsistent; you say the array should be 6,7,8,9,10,1,2,3,4,5 at the end, and that calls for exchanging all elements with index under 5 (elements 0 to 4), not under 4.
The LOOP command (which is not a good idea, but that's beside the point) uses ECX as an implicit counter. If ECX is nonzero, it decrements and jumps to the label, if it's zero, it doesn't. So you're looping for exactly LENGTHOF arrayB times; that's wrong, you want to loop for half that.
Also, the XCHG command is wrong. The destination for the exchange is not at arrayB, it's at the current index + 5. You figure out how to fix that.
Also, once you exchange ax with the index+5'th element, you still need to write the retrieved value of the index+5'th element back into the index'th position.
You are using edi to point to the elements of the array and store them in ax, one solution will be to use esi to point to the element+5 and store it in bx, then move bx into edi and move ax into esi (by the way, the loop should repeat half-array-length times) :
.386
.model flat,stdcall
.stack 4096
ExitProcess proto,dwExitCode:dword
WriteDec PROTO
Crlf PROTO
DumpRegs PROTO
.data
arrayB WORD 1,2,3,4,5,6,7,8,9,10
.code
main proc
;mov eax,0 ;◄■■ UNNECESSARY.
mov edi,OFFSET arrayB ; address of arrayB
mov ecx,5 ;◄■■ 10 ÷ 2 ("when ‘i' is under 4").
;mov ax,0 ;◄■■ UNNECESSARY.
L1:
mov ax,[edi] ; mov current edi value from array into ax
mov esi,edi
add esi,TYPE arrayB * 5 ;◄■■ ELEMENT "I+5".
mov bx,[esi] ;◄■■ BX = "I+5".
mov [edi],bx ;◄■■ EXCHANGE ONE REGISTER.
mov [esi],ax ;◄■■ EXCHANGE THE OTHER REGISTER.
add edi,TYPE arrayB ; point to next integer
loop L1
;----------------------------------------------
mov edi, OFFSET arrayB
mov ecx, LENGTHOF arrayB
DISPLAY_ARRAY:
xor eax, eax
mov ax, [edi]
call WriteDec
add edi,TYPE arrayB ; point to next integer
loop DISPLAY_ARRAY
;----------------------------------------------
call DumpRegs
call WriteDec
call crlf
invoke ExitProcess,0
main endp
end main
Edited the answer to add loop to display the array elements.

Looping backwards in Assembly x86

When you are looping backwards in Assembly x86, what is currently happening in the memory (Can you try to be visual, thanks)? The following code is what I am currently wondering about:
INCLUDE Irvine32.inc
.data
arrayb byte 1,2,3,4,5,6 ;6-7 bytes
len dword lengthof arrayb
space byte " ",0
x dword 3
.code
main PROC
mov edx,offset space
mov eax,0 ; clear ecx of garbage
mov ecx, len
mov esi,offset arrayb ; start of the array's memory
add esi,len ;This causes the array value to start at 6
dec esi ; esi goes from esi+5,esi+4,...,esi
myloop2:
mov al,[esi]
call writedec
call writestring
dec esi
loop myloop2
call crlf
In particular, why did I have to add 1 to esi? When you add 1 to the high speed memory transfer register esi, it seems that it causes the array value to start at 6. Why is that?Thank you.

How to move and display array values from one to another in Assembly Language?

I am trying to move the values in Array1 to Array2, and then display them. I have been working on this and could not figure it out at all. Would anyone please help me? Thanks
INCLUDE Irvine32.inc
INCLUDE macros.inc
.data
Array1 DWord 2,4,6,8,10
Array2 DWord 5 Dup(0)
.code
main PROC
mov edx, OFFSET Array1
mov esi, OFFSET Array2
mov ecx, LENGTHOF Array1
mov eax, 0
Call Dumpregs
Call Dumpregs
L1:
mWrite "Hello"
Call CRLF
Loop L1
Call Dumpregs
L2:
mov eax, [edx]
mov [esi], eax
add esi, 4
add edx, 4
Loop L2
exit
main ENDP
END main
Your L2 loop cannot produce the desired result since the preceding code wiped ECX clean (You used loop L1). To copy the array you need to re-initialize ECX. Also it's best to setup the pointers EDX and ESI close to this L2 loop because perhaps there is a risk of them being modified by all those preceding (macro)calls!
mov edx, OFFSET Array1
mov esi, OFFSET Array2
mov ecx,5
L2:
mov eax,[edx]
mov [esi],eax
add esi, 4
add edx, 4
loop L2

Resources