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.
Related
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
I'm trying to print the contents of an array by using assembly language as below.
I could compile the code, but I could not run it.
How should I fix the code to print the contents of an array?
TITLE arrayFill_example (arrayFill_ex.asm)
INCLUDE Irvine32.inc
.data
count = 5
array DWORD count DUP(?)
arraySize = ($ - array) / 4
.code
; saves the general-purpose registers, retrieves the parameters, and fills the array
ArrayFill PROC
push ebp
mov ebp,esp
pushad ; save registers
mov esi,[ebp+12] ; offset of array
mov ecx,[ebp+8] ; array length
cmp ecx,0 ; ECX == 0?
je L2 ; yes: skip over loop
L1:
mov eax,10000h ; get random 0-FFFFh
call RandomRange ; from the link library
mov [esi],ax ; insert value in array
add esi,TYPE WORD ; move to next element
loop L1
L2: popad ; restore registers
pop ebp
ret 8 ; clean up the stack
ArrayFill ENDP
main PROC
push OFFSET array ; passed by reference
push count ; passed by value
call ArrayFill
; for showing array contents
mov eax, 0
mov esi, array
mov ecx, arraySize
L1:
mov eax, array[esi * TYPE array]
call WriteInt
call Crlf
add esi, 4
loop L1
exit
main ENDP
END main
Specifically this part is not working for me...
; for showing array contents
mov eax, 0
mov esi, array
mov ecx, arraySize
L1:
mov eax, array[esi * TYPE array]
call WriteInt
call Crlf
add esi, 4
loop L1
Problem 1
array DWORD count DUP(?)
With this definition the array contains dwords. But your program just fills the array with words using:
mov [esi],ax ; insert value in array
add esi,TYPE WORD ; move to next element
Better write:
mov [esi], eax ; insert value in array
add esi, 4 ; move to next element
Problem 2
mov esi, array
...
mov eax, array[esi * TYPE array]
These lines are redundantly referring to the array. That's adding a pointer to a pointer, giving the wrong address! (Or actually, mov esi, array loaded the first element, not the address, because that's how MASM syntax works.)
mov esi, OFFSET array gives you the address in esi. From there, [esi] is the first element, array[esi] is similar to C array[ (intptr_t)array ] (but just a byte offset without scaling by the element size). The resulting address is unlikely to be valid.
Just use one or the other, indexing with small integers, or a pointer increment. Getting a pointer into a register is usually good, as in:
mov esi, OFFSET array
mov ecx, arraySize
L1:
mov eax, [esi]
call WriteInt
call Crlf
add esi, 4
loop L1
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.
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
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.