Search code examples
assemblyx86masmirvine32

My program won't sort arrays that are larger than 130


So my program is supposed to take in user input (an integer between 10 and 200) and print out an array of random numbers and print out a sorted version of that array. However, this only works when I enter in 130 or less.

I don't know what else I can do. It works but only half way. Is there any way to optimize this code? I have placed lines to help show which procedure I am having problems with.

****I ran debugger and I have left a comment where the program throws an exception error.*****

TITLE Program5    (Program5.asm)

INCLUDE Irvine32.inc

; (insert constant definitions here)
    MIN_INPUT = 10
    MAX_INPUT = 200
    LO_RANDOM = 100
    HI_RANDOM = 999

.data

; (insert variable definitions here)
intro           BYTE    "Fun with Arrays! by ", 0
instruction     BYTE    "This program generates random numbers in the range [100 .. 999], displays the original list, sorts the list, and calculates the median value. Finally, it displays the list sorted in descending order", 0

request         DWORD   10
ask_user        BYTE    "How many numbers should be generated? [10 ... 200]: ", 0
error           BYTE    "Invalid input", 0

title_1         BYTE    "The unsorted random numbers: ", 0
title_2         BYTE    "The sorted list: ", 0
space           BYTE    "   ", 0

mult            DWORD   0.5

temp            DWORD   0

list            DWORD   MAX_INPUT   DUP(?)

.code
main PROC

; (insert executable instructions here)
    call    randomize
    call    introduction

    push    OFFSET request ;passed by reference
    call    getData

    call    CrLf

    push    request ; passed by value
    push    OFFSET list ; passed by reference
    call    fillArray

    push    OFFSET list
    push    request
    push    OFFSET title_1
    call    displaylist

    call    CrLf

    push    OFFSET list
    push    request
    call    sortList

    call    CrLf
;
    push    OFFSET list
    push    request
    push    OFFSET title_2
    call    displaylist

    ;push   OFFSET list
    ;push   request
    ;call   displayMedian

    exit    ; exit to operating system
main ENDP

; (insert additional procedures here)
introduction PROC

    mov     edx, OFFSET intro
    call    WriteString
    call    CrLf
    mov     edx, OFFSET instruction
    call    WriteString
    call    CrLf
    ret 

introduction ENDP

getData PROC
;include parameter - request (reference)

    push    ebp ;Set up stack frame
    mov     ebp, esp

    ;get an integer from user
    mov     ebx, [ebp+8]    ;get address of request into ebx

    L1:
        mov     edx, OFFSET ask_user
        call    WriteString
        call    ReadDec

        cmp     eax, MIN_INPUT
        jl      errorMessage
        cmp     eax, MAX_INPUT
        jg      errorMessage

        cmp     eax, MIN_INPUT
        jge     endThis
        cmp     eax, MAX_INPUT
        jle     endThis

    errorMessage:
        mov     edx, OFFSET error
        call    WriteString
        call    CrLf
        jmp     L1

    endThis:
        mov     [ebx], eax
        pop     ebp
        ret     4 ; remove four more bytes from the stack (after ret @)
getData ENDP

fillArray PROC
;include parameters - request (value), array (reference)
    ; MAJORITY OF THE FOLLOWING CODE WAS EXTRACTED FROM LECTURE 20 SLIDES
    push    ebp
    mov     ebp, esp ;[ebp+4]
    mov     edi, [ebp+8] ; @list in edi
    mov     ecx, [ebp+12] ; value of request in ecx

    more:
        mov     eax, HI_RANDOM
        sub     eax, LO_RANDOM
        inc     eax
        call    RandomRange
        add     eax, LO_RANDOM

        mov     [edi], eax
        add     edi, 4
        loop    more

    endmore:
        pop     ebp
        ret     8
fillArray ENDP

;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
sortList PROC
;include parameters - array (reference), request (value)
    push    ebp
    mov     ebp, esp ;[ebp+4]
    mov     edi, [ebp+12] ; @list in edi
    mov     ecx, [ebp+8] ; value of request in ecx

    dec     ecx ; request - 1
    mov     ebx, 0 ; "k"

    ;for(k=0; k<request-1; k++) { 
       ;i = k; 
       ;for(j=k+1; j<request; j++) { 
          ;if(array[j] > array[i]) 
             ;i = j; 
       ;} 
       ;exchange(array[k], array[i]); 
    ;} 

    firstLoop:
        mov     eax, ebx ; "i = k"

        mov     edx, ebx ; "j = k"
        inc     edx ; "j = k + 1"
        push    ecx ; pushed the first loop's counter
        mov     ecx, [ebp+8] ; made the second loop's counter = request

        secondLoop:
            mov     esi, [edi + (edx * 4)] ; array[j] ; EXCEPTION WAS THROWN HERE
            cmp     esi, [edi + (eax * 4)] ; compare array[j] and array[i]
            jg      greater
            jle     lesser

            greater:
                mov     eax, edx
                inc     edx
                loop    secondLoop

            lesser:
                inc     edx
                loop    secondLoop

        push    edx
        push    esi
        push    [edi + (ebx * 4)] ; array[k]
        push    [edi + (eax * 4)] ; array[i]
        call    exchangeElements
        pop     [edi + (eax * 4)]
        pop     [edi + (ebx * 4)]
        pop     esi
        pop     edx
        pop     ecx ; set the 
        inc     ebx ; increment k in the first loop
        loop    firstLoop

    pop     ebp
    ret     8

sortList ENDP

exchangeElements PROC
    push    ebp
    mov     ebp, esp
    mov     esi, [ebp+12] ; array[k]
    mov     edx, [ebp+8] ; array[i]
    mov     [ebp+8], esi
    mov     [ebp+12], edx
    pop     ebp
    ret     
exchangeElements ENDP
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------

displayMedian PROC
    push    ebp
    mov     ebp, esp ;[ebp+4]
    mov     edi, [ebp+12] ; @list in edi
    mov     ecx, [ebp+8] ; value of request in ecx

    mov     eax, ecx
    mov     ebx, 2
    cdq
    div     ebx
    cmp     edx, 0
    je      isEven
    cmp     edx, 1
    je      isOdd

            ;def nlogn_median(l):
    ;l = sorted(l)
    ;if len(l) % 2 == 1:
        ;return l[len(l) / 2]
    ;else:
        ;return 0.5 * (l[len(l) / 2 - 1] + l[len(l) / 2])

    isEven:
        mov     esi, [edi + (eax - 1)]
        add     esi, [edi + (eax)]
        mov     eax, esi
        mov     ebx, 2
        cdq
        div     ebx
        call    WriteDec

    isOdd:
        mov     eax, [edi + (eax*4)]
        call    WriteDec

    pop ebp
    ret
displayMedian ENDP

displayList PROC
    push    ebp
    mov     ebp, esp ; [ebp+4]
    mov     ecx, [ebp+12] ; @request
    mov     edi, [ebp+16] ; @list
    mov     esi, 10

    mov     edx, [ebp+8] ; @title
    call    WriteString
    call    CrLf

    show:
        mov     eax, [edi]
        call    WriteDec
        mov     edx, OFFSET space
        call    WriteString
        add     edi, 4

        dec     esi
        cmp     esi, 0
        je      callClear

    loopAgain:
        loop    show

    jmp     endshow

    callClear:
        mov     esi, 10
        call    CrLf
        jmp     loopAgain

    endshow:
        pop     ebp
        ret     12

displayList ENDP

END main

UPDATE enter image description here

enter image description here


Solution

  • If you look at your registers, you'll see that edx is 0fA4h, which is larger than it should be at the line it crashes on. ecx is a negative number. This is a clue that your loop is executing after it should have stopped.

    The problem is that the greater branch will fall thru to the lesser branch. This will decrement ecx again, causing it to go negative and your loop will just keep running until you get the access violation.

    The quick fix is to put an unconditional jmp after the loop instruction under the greater label.

    A better fix is to combine the tails of the loops into a simpler conditional:

        cmp     esi, [edi + (eax * 4)] ; compare array[j] and array[i]
        jle     lesser
        mov     eax, edx
    lesser:
        inc     edx
        loop    secondLoop