I posted two days ago about an issue I was having in x86 Assembly (which thankfully I was able to fix (for the most part) with sorting from least to greatest using the bubble-sort method. I was successfully able to sort the two arrays that I have (shown below in the snippet of the data section of my code), but selecting the greatest value in each of the arrays has become an issue.
INCLUDE Irvine32.inc
.data
Array1 DWORD 0C0D12AFh, 00030256h, 0FFAABBCCh, 0F700F70h, 00000000h, 0E222111Fh, 0ABCDEF01h, 01234567h
Array2 DWORD 61A80000h, 024F4A37h, 0EC010203h, 0FAEEDDCCh, 2C030175h, 84728371h, 63AA5678h, 0CD454443h, 22222222h, 61B1C2D3h, 7A4E96C2h, 81002346h, 0FDB2726Eh, 65432100h, 0FFFFFFFFh
The issue either lies in the section before I call the procedure to select the greatest value (in the main procedure of my code):
.code
main PROC
.....
; display Array1 get and display greatest value in Array1
call displayArray1 ; display Array1 (sorted)
call Crlf ; skip line
mov esi,OFFSET Array1 ; point to start of Array1
mov ecx,LENGTHOF Array1-4 ; number of units
call getLargest ; find largest value in Array1 and
; display it
; display Array2 get and display greatest value in Array2
call displayArray2 ; display Array2 (sorted)
call Crlf ; skip line
mov esi,OFFSET Array2 ; point to start of Array2
mov ecx,LENGTHOF Array2-4 ; number of units
call getLargest ; find largest value in Array2 and
; display it
exit ; exit the program
main ENDP
where I first call the procedures to display both arrays after sorting them, and then follow up with moving the array pointers into registers and adjust ECX to stop one position short of the last value in the array--mov ecx,LENGTHOF Array1-4
and mov ecx,LENGTHOF Array2-4
--or my issue lies in the getLargest procedure itself (where an array is scanned for its greatest value (which in this case should be the final value of the array)):
;-------------------------------------------------------
getLargest PROC
;
; Finds and returns a statement of what the greatest
; value in an array is.
; Receives: nothing
; Returns: statement of largest value in array
;-------------------------------------------------------
mov eax,[esi] ; move pointer into EAX
sift:
cmp [esi 4],eax ; compare next value and EAX
jng skip ; if EAX >= [ESI 4], skip
mov eax,[esi 4] ; else, mov [ESI 4] into EAX
skip:
add esi,4 ; increment ESI by 4
dec ecx ; decrement ECX
jnz sift ; if ECX not zero, jump back to sift
mov ebx,eax ; signed maximum
quit:
; display largest unsigned integer
mov edx,OFFSET largestUnsignedS
call WriteString ; display largestUnsignedF string
mov eax,ebx
call WriteHex ; display largest unsigned value
mov edx,OFFSET largestUnsignedF
call WriteString ; display largestUnsignedS string
call Crlf ; skip line
ret
getLargest ENDP
Currently, I am receiving output that says that the largest value in Array1
is 0F700F70h (when it should be FFAABBCCh) and the largest value in Array2
is 7A4E96C2h (when it should be FFFFFFFFh). I believe that the procedure is either stopping a few positions short of the final position of each array (due to syntax) or the procedure runs the correct number of times, but it fails to make a jump between the sift
and skip
loops at the proper times.
The good news is that I'm not receiving errors (as the build process would have failed), but I am not receiving the correct output for getLargest. Essentially what I'm wondering is if I need to fix what I'm sending to ECX in main
or if I need to fix my loops in getLargest.
CodePudding user response:
Quoting from my previous answer:
A code that finds the largest element could look like this:
mov eax, 80000000h ; Smallest signed dword More: cmp [esi], eax jng Skip mov eax, [esi] Skip: add esi, 4 dec ecx jnz More mov ebx, eax ; The signed maximum
Your new getLargest proc builds on this and even optimizes it by using the first array element to initialize EAX. This can shave off 1 iteration of the loop. To this effect, you have chosen to pass a smaller count in the ECX register. The error is in mov ecx, LENGTHOF Array1-4
. Since LENGTHOF
gives you the number of array elements, you want to subtract 1.
Essentially what I'm wondering is if I need to fix what I'm sending to ECX in main or if I need to fix my loops in getLargest.
I would not have changed the ECX argument:
- It confuses a bit more, the reader that sees this fixup
- It's different from how you invoke the BubbleSort proc
- In the proc, the decrement can detect the trivial cases of 0 or 1 element(s)
My suggestion
; IN (ecx,esi)
getLargest PROC
xor eax, eax
dec ecx
js quit ; return 0 for empty array
mov eax, [esi] ; Arr[0]
jz quit ; return Arr[0] for single-element array
sift:
cmp [esi 4], eax ; compare next value and EAX
jng skip ; if EAX >= [ESI 4], skip
mov eax, [esi 4] ; else, mov [ESI 4] into EAX
skip:
add esi, 4
dec ecx
jnz sift ; if ECX not zero, jump back to sift
quit:
mov ebx, eax ; signed maximum
...
Improve your comments
getLargest PROC ; Receives: nothing
nothing - Your proc does receive the ECX and ESI registers.
mov eax,[esi] ; move pointer into EAX
pointer - You are loading the value of the first array element. To me, your arrays don't look like they could be containing pointer material.
Signed vs Unsigned
Currently, I am receiving output that says that the largest value in Array1 is 0F700F70h (when it should be FFAABBCCh) and the largest value in Array2 is 7A4E96C2h (when it should be FFFFFFFFh)
Your expectations here are wrong! Since your sifting code is using the signed conditional branch instruction jng
JumpIfNotGreater, numbers like FFAABBCCh and FFFFFFFFh are considered negative numbers and will not make it 'largest'.
So to have the program sift through arrays of unsigned values, instead use the unsigned conditional branch instruction jna
JumpIfNotAbove.