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'
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.
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
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'
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
...