Home > Blockchain >  x86 Assembly - Finding the largest value in a sorted array
x86 Assembly - Finding the largest value in a sorted array

Time:10-25

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.

  • Related