Search code examples
sortingassemblyx86procfasm

Sorting a list through a procedure in flat assembly


I'm pretty new to fasm and I just recently started learning about procedures. My problem is that I have a proc and I want it to sort my list in a certain way. But when I run my code it just seems to sort some random numbers from memory. I don't quite know why it happens and I would appreciate any help. Here's the code:

format PE gui 5.0
include 'D:\Flat Assembler\INCLUDE\win32a.inc'
entry start

section '.data' data readable writable
    mas1 dw 2, -3, 1, -1, 3, -2, 5, -5, -4, 4

    N = ($ - mas1) / 2
    numStr db N dup('%d  '), 0

    strStr db '%s', 0
    undefStr db 'undefined', 0
    buff db 50 dup(?)
    Caption db 'Result', 0


section '.code' code readable executable
start:

stdcall bubble, mas1

cinvoke wsprintf, buff, numStr
invoke MessageBox, 0, buff, Caption, MB_OK + MB_ICONINFORMATION
invoke ExitProcess, 0


proc bubble, mas:word
    mov ecx, 0
    mov ebx, 0

    outerLoop:
            cmp ecx, 10
            je done
            mov ebx, 2

    innerLoop:
            mov eax, 0
            mov edx, 0

            cmp [mas+ebx], 0 ;if(mas[j] > 0)
            jge continue     ;continue

            mov ax, [mas+ebx-2]

            cmp ax, [mas+ebx]
            jle continue
                mov dx, [mas+ebx]
                mov [mas+ebx-2], dx
                mov [mas+ebx], ax

            continue:
            cmp ebx, 18 ;10
            je innerDone
            add ebx, 2 ;inc ebx
            jmp innerLoop

    innerDone:
            inc ecx
            jmp outerLoop

    done:
    mov ecx, 0
    mov ebx, 0
    mov ebx, 18
    mov ecx, N
    print:
           mov eax, 0
           mov ax, [mas+ebx]
           cwde
           push eax
           sub ebx, 2
           loop print

    ret
    endp

section '.idata' import data readable writeable
    library kernel32,'KERNEL32.DLL',\
            user32,'USER32.DLL'

    include 'D:\Flat Assembler\INCLUDE\API\kernel32.inc'
    include 'D:\Flat Assembler\INCLUDE\API\user32.inc'

Solution

  • Error 1

    stdcall bubble, mas1
    ...
    proc bubble, mas:word
    

    The parameter mas1 is an address and is pushed to the stack as a dword. Therefore you should not limit the argument mas to a word.
    What your bubble procedure needs is the full address of the array. You get this via mov esi, [mas] that FASM will encode as if you would have written mov esi, [ebp+8]. EBP+8 is where the first argument (and in your program the only argument) resides, when the standard prologue push ebp mov ebp, esp is used.

    Error 2

    In your bubble procedure you push the resulting array to the stack hoping to have wsprintf use it from there, but once the bubble procedure executes its ret instruction, the epilogue code as well as the ret instruction itself will start eating your array and even return to the wrong address in memory!
    If you're going to return an array via the stack, then store it above the return address and the argument(s). That's why I wrote in my program below:

    sub esp, N*4                  ; Space for N dwords on the stack
    stdcall bubble, mas1
    

    Error 3

    cmp [mas+ebx], 0 ;if(mas[j] > 0)
    jge continue     ;continue
    

    Your BubbleSort is wrong because you don't allow positive numbers to get compared!
    Furthermore you make too many iterations that also continu for too long.


    I tested below program on FASM 1.71.22 Don't forget to change the paths!

    format PE gui 5.0
    include 'C:\FASM\INCLUDE\win32a.inc'
    entry start
    
    section '.data' data readable writable
        mas1 dw 2, -3, 1, -1, 3, -2, 5, -5, -4, 4
        N = ($ - mas1) / 2
    
        numStr db N-1 dup('%d, '), '%d', 0
        ;strStr db '%s', 0
        ;undefStr db 'undefined', 0
        buff db 50 dup(?)
        Caption db 'Result', 0
    
    
    section '.code' code readable executable
    start:
    
    sub esp, N*4                  ; Space for N dwords on the stack
    stdcall bubble, mas1
    
    cinvoke wsprintf, buff, numStr
    invoke MessageBox, 0, buff, Caption, MB_OK + MB_ICONINFORMATION
    invoke ExitProcess, 0
    
    
    proc bubble uses ebx esi, mas
    
        mov   esi, [mas]          ; Address of the array
        mov   ecx, (N-1)*2        ; Offset to the last item; Max (N-1) compares
    
      outerLoop:
        xor   ebx, ebx
    
      innerLoop:
        mov   ax, [esi+ebx]
        mov   dx, [esi+ebx+2]
        cmp   ax, dx
        jle   continue
        mov   [esi+ebx+2], ax
        mov   [esi+ebx], dx
      continue:
        add   ebx, 2
        cmp   ebx, ecx
        jb    innerLoop
    
        sub   ecx, 2
        jnz   outerLoop
    
        mov   ebx, (N-1)*2
      toStack:
        movsx eax, word [esi+ebx]
        mov   [ebp+12+ebx*2], eax
        sub   ebx, 2
        jnb   toStack
    
        ret
        endp
    
    section '.idata' import data readable writeable
        library kernel32,'KERNEL32.DLL',\
                user32,'USER32.DLL'
    
        include 'C:\FASM\INCLUDE\API\kernel32.inc'
        include 'C:\FASM\INCLUDE\API\user32.inc'
    

    Error 2 revisited

    IMO returning the resulting array through the stack would make better sense if your bubble procedure didn't modify the original array.
    But in your present code you do, so...
    Once you strike the toStack snippet from the bubble procedure, you can simply (after returning from the bubble procedure) push the word-sized elements of the array to the stack as dwords followed by using wsprintf.

      ...
    
    start:
      stdcall bubble, mas1
      mov   ebx, (N-1)*2
    toStack:
      movsx eax, word [mas1+ebx]
      push  eax
      sub   ebx, 2
      jnb   toStack
      cinvoke wsprintf, buff, numStr
    
      ...
    
      sub   ecx, 2
      jnz   outerLoop
      ; See no more toStack here!
      ret
    endp
    
      ...