Is there an easier way to write a bubble sort algorithm in masm modular style? - algorithm

I wrote a bubble sort algorithm in assembly, I'm proud of myself, but at the same time I think my bubble sort is wrong.
Can someone let me know if it's right? And how do I make my program more modular so I can reuse it later?
.386
.model flat,stdcall
.stack 100h
printf proto c arg1:ptr byte, printlist:vararg
.data
array dword 8,9,10,40,80,0
fmtmsg2 db 0dh,0ah,0
fmtmsg1 db "%d ",0
.code
public main
main proc
mov ecx,0
mov edx,0
mov esi,offset array
innerloop:
inc ecx
cmp ecx,5
je outerloop
mov eax,[esi]
cmp eax,[esi + 4]
Jge noexchange
;exchange values
xchg eax,[esi+4]
mov [esi],eax
noexchange:
add esi,4
jmp innerloop
outerloop:
mov esi,offset array
;inner loop counter
mov ecx,0
;outer loop counter
inc edx
cmp edx,5
jne innerloop
;loop 3 counter
mov edx,0
;load array offset
mov esi,offset array
loop3:
mov eax,[esi]
push edx
invoke printf,addr fmtmsg1,eax
pop edx
add esi,4
inc edx
cmp edx,5
jne loop3
invoke printf,addr fmtmsg2
ret
main endp
end main

Your original algorithm works great (congratulations). It sorts an array in descending order, for example, if array is [1,2,3,4,5] the result is [5,4,3,2,1]. If you want it in ascending order, just change one instruction. I used Visual Studio 2010, but the code is the same (my changes are pointed by arrows, but you only need one change: "jbe") :
void death_reverse () {
int array[5] = { 5,4,3,2,1 }; // <=====================
__asm { mov ecx,0
mov edx,0
lea esi, array // <=====================
innerloop:
inc ecx
cmp ecx,5
je outerloop
mov eax,[esi]
cmp eax,[esi + 4]
Jbe noexchange // <=============== ASCENDING ORDER.
;exchange values
xchg eax,[esi+4]
mov [esi],eax
noexchange:
add esi,4
jmp innerloop
outerloop:
lea esi, array // <=====================
;inner loop counter
mov ecx,0
;outer loop counter
inc edx
cmp edx,5
jne innerloop
;loop 3 counter
mov edx,0
;load array offset
lea esi, array // <=====================
loop3:
mov eax,[esi]
push edx
invoke printf,addr fmtmsg1,eax
pop edx
add esi,4
inc edx
cmp edx,5
jne loop3
invoke printf,addr fmtmsg2
}
}

Related

segmentation fault in x86 trying to do bubble sort

I am trying to implement bubble sort in assembly. Here is my code. I keep getting segmentation fault. I have a function down below. I have been trying to figure this out but I couldn't find a compiler for x86 and I have been checking with my code to check what is wrong but to no avail.
here is my function code:
bubble:
push ebp
mov ebp, esp
push ecx
push edx
push edi
push esi
push ebx
push eax
mov eax, 0
mov ecx, [ebp+12] ; number of elements in the array
mov edx, [ebp+8]; address of array
mov edi, 0
mov esi, 0
dec ecx; n - 1
mov esi, 1
sortOuter:
cmp esi, 0
jg sort
sort:
mov esi, 0 ;count
check:
cmp edi, ecx ; i < n - 1
jl sortInner
sortInner:
mov ebx, [edx+edi*4] ; mov array[i+1] to ebx
cmp [edx], ebx ; cmp array[i] to array[i+1]
jle noswap
swap:
mov eax, ebx ; mov array[i+1] to eax
mov ebx, [edx] ; mov array[i] to array[i+1]
mov [edx], eax ; mov array[i+1] to array[i]
inc esi ; count++
noswap:
inc edi ; i++
jmp check
jmp sortOuter
done:
call print_nl
pop ebx
pop esi
pop edi
pop edx
pop ecx
mov esp, ebp
pop ebp
ret
The segmentation error comes from the infinite loop that you have created with
check:
cmp edi, ecx ; i < n - 1
jl sortInner
sortInner:
If EDI is less than ECX you jump to sortInner, but if it isn't you fall-through into sortInner. No matter, you always end up running the code at sortInner and because the memory addresses that the code uses keep growing, at some point you will be trying to read memory that you don't have access to, hence the segmentation error.
Now if you were to correct this, then there's a second infinite loop waiting.
sortOuter:
cmp esi, 0
jg sort
sort:
Other errors include:
Resetting ESI instead of EDI at the start of the inner loop
Not swapping elements at all but always writing the smallest value in the first array element
Forgetting to restore the register EAX
This is a working BubbleSort. Don't just copy it, but find out how it functions!
In an array with N elements we have to do N-1 comparisons at most (to have the greatest value bubble towards the rear).
Because the InnerLoop uses a counter that gets initialized from the ever decreasing OuterLoop counter, with each iteration of the OuterLoop the portion of the array that is processed in the InnerLoop gets smaller. The portion of the array that we then no longer process contains the greatest elements that have bubbled towards the end of the array, hence the name BubbleSort.
Provisions have been made for an empty array or an array that has but 1 element. Always include some code for the special cases!
bubble:
push ebp
mov ebp, esp
push ...
mov ecx, [ebp + 12] ; Number of elements in the array
sub ecx, 1 ; First time we do n = N-1
jbe Done ; Array is empty or has but 1 element
OuterLoop:
mov edx, ecx ; Current value of the OuterLoop counter (n)
mov esi, [ebp + 8] ; Address of array
InnerLoop:
mov eax, [esi]
mov ebx, [esi + 4]
cmp eax, ebx
jng NoSwap
mov [esi], ebx
mov [esi + 4], eax
NoSwap:
add esi, 4
dec edx
jnz InnerLoop
dec ecx ; Next times we do n = n-1
jnz OuterLoop
Done:
pop ...
pop ebp
ret

Finding Smallest Number in List

My goal in this code is to find the smallest number in the list. I used bubble sort method in this case; unfortunately, the code is not giving me the smallest/minimum number. Please take a look, Thanks:
include irvine32.inc
.data
input byte 100 dup(0)
stringinput byte "Enter any string: ",0
totallength byte "The total length is: ",0
minimum byte "The minimum value is: ",0
.code
stringLength proc
push ebp
mov ebp, esp
push ebx
push ecx
mov eax, 0
mov ebx, [ebp+8]
L1:
mov ecx, [ebx] ;you can use ecx, cx, ch, cl
cmp ecx, 0 ;you can use ecx, cx, ch, cl
JE L2
add ebx, 1
add eax, 1
jmp L1
L2:
pop ecx
pop ebx
mov ebp, esp
pop ebp
ret 4
stringLength endp
BubbleSort PROC uses ECX
push edx
xor ecx,ecx
mov ecx, 50
OUTER_LOOP:
push ecx
xor ecx,ecx
mov ecx,14
mov esi, OFFSET input
COMPARE:
xor ebx,ebx
xor edx,edx
mov bl, byte ptr ds:[esi]
mov dl, byte ptr ds:[esi+1]
cmp bl,dl
jg SWAP1
CONTINUE:
add esi,2
loop COMPARE
mov esi, OFFSET input
pop ecx
loop OUTER_LOOP
jmp FINISHED
SWAP1:
xchg bl,dl
mov byte ptr ds:[esi+1],dl
mov byte ptr ds:[esi],bl
jmp CONTINUE
FINISHED:
pop edx
ret 4
BubbleSort ENDP
main proc
call clrscr
mov edx, offset stringinput
call writeString
mov edx, offset input
call writeString
call stringLength
mov edx, offset input
mov ecx, sizeof input
call readstring
call crlf
mov edx,offset totallength
call writestring
call writedec
call crlf
mov edx, offset minimum
call crlf
call writeString
push offset input
call BubbleSort
mov edx, offset input
call writeString
call crlf
exit
main endp
end main
I haven't looked over your code, because sorting is an over complicated method for what you want to do. Not only that, but most of us don't pay too much attention to uncommented code. Just takes to long to figure out what you're trying to do.
Simply iterate through the entire list and start with 255 (FFH) in AL let's say. Each time you come across a number that is smaller than the one in AL, then replace it with that value and then when loop is finished, AL will have the lowest value.
If you need to know where it is in the list, you could maybe use AH which would be the difference between start address and current address. Knowledge of the instruction set is essential as finding the length of the string can be simplified by;
mov di, input ; Point to beginning of buffer
mov cx, -1 ; for a maximum of 65535 characters
xor al, al ; Looking for NULL
rep scasb
neg cx
dec cx ; CX = length of string.
Remember, ES needs to point to #DATA

Insertion sort in assembler doesn't sort

I'm trying to sort a array of numbers by Insertion sort but it not sort the numbers correctly. I've tried everything but it does not sort them As it should.
I would be happy if you could help me figure out where the problem and on how I can fix it thanks !!
section .rodata
MSG: DB "welcome to sortMe, please sort me",10,0
S1: DB "%d",10,0 ; 10 = '\n' , 0 = '\0'
section .data
array DB 5,1,7,3,4,9,12,8,10,2,6,11 ; unsorted array
len DB 12
section .text
align 16
global main
extern printf
main:
push MSG ; print welcome message
call printf
add esp,4 ; clean the stack
call printArray ;print the unsorted array
push ebp ;save old frame pointer
mov ebp,esp ;create new frame on stack
pusha
mov esi,array
mov ecx,8
OuterLoop:
mov ebx,ecx
InnerLoop:
add esi,ebx ;basically makes array[0] to array[ebx]
mov eax,[esi] ;eax=array[ebx]
sub esi,8
mov edx,[esi] ; edx=array[ebx-1]
add esi,8
cmp eax,edx ; if(eax<edx)
jle skip2 ; skip the loop
;else:
mov [esi],edx ;array[ebx]=array[ebx-1]
sub esi,8
mov [esi],eax ; array[ebx-1]=array[ebx]
add esi,8
sub esi,ebx ; return the array to its original state (array[0])
sub ebx,8
cmp ebx,0
jne InnerLoop
skip1:
add ecx,8
cmp ecx,96
jle OuterLoop
popa ;restore registers
mov esp,ebp ;clean the stack frame
pop ebp
push MSG ; print welcome message (to divide between the unsorted and sorted)
call printf
add esp,4 ; clean the stack
call printArray
mov eax, 1 ;exit system call
int 0x80
printArray:
push ebp ;save old frame pointer
mov ebp,esp ;create new frame on stack
pusha ;save registers
mov eax,0
mov ebx,0
mov edi,0
mov esi,0 ;array index
mov bl,byte[len]
add edi,ebx ; edi = array size
print_loop:
cmp esi,edi
je print_end
mov al ,byte[array+esi] ;set num to print in eax
push eax
push S1
call printf
add esp,8 ;clean the stack
inc esi
jmp print_loop
print_end:
popa ;restore registers
mov esp,ebp ;clean the stack frame
pop ebp ;return to old stack frame
ret
skip2:
sub esi,ebx ; return the array to the original state
jmp skip1
You're horribly mixing 3 sizes!
1. Array of bytes
2. Values of dwords
3. Steps of qwords
Once you've decided what size to use beware of this code. In its current qword form it does an extra iteration! (use jl OuterLoop)
cmp ecx,96
jle OuterLoop
Why don't you use MOVZX to EAX in this line? It's much cleaner.
mov al ,byte[array+esi] ;set num to print in eax
The same applies to
mov bl,byte[len]
By putting mov esi,array right after OuterLoop: you can avoid that ugly detour via SKIP2.

How do you do a selection sort in MASM Assembly?

So I'm trying to sort an array in ascending order, and it just doesn't seem to work for me. I know my swap procedure is wrong, and my minIndex procedure only works half the time, but the randomly filled array generates just fine.
Working Code Thanks to vitsoft:
include Irvine32.inc
; Constants
NUM_INTEGERS = 20
NUM_RANGE = 99d
TO_ENSURE_NOT_ZERO = 1d
.data
; Declare Arrays
; Declare Array of 20 Integers
array byte NUM_INTEGERS dup(?)
; Displayed Annotation for Unsorted Array
unsortedArrayText byte "Randomly Generated Array, Unsorted: ", 0dh, 0ah, 0
; Displayed Annotation for Sorted Array
sortedArrayText byte "Randomly Generated Array, Sorted from Lowest to Highest: ", 0dh, 0ah, 0
.code
main PROC
; Get Random Values for Array
call fillArrayRandomly
; Display Array with Annotation
mov edx, offset unsortedArrayText
call WriteString
mov ecx, offset array
push ecx
call displayArray
; Sort Array
mov esi, offset array
mov ecx, NUM_INTEGERS
call findMinimum
mov edi, offset array
mov ecx, NUM_INTEGERS
call selectionSort
; Display Sorted Array with Annotation
mov edx, offset sortedArrayText
call WriteString
mov ecx, offset array
push ecx
call displayArray
; Exit Program
exit
main endp
; Fill Array with Random Values
fillArrayRandomly PROC
; Set Counter to NUM_INTEGERS and Index to 0
mov eax, 0
mov ecx, NUM_INTEGERS
mov esi, 0
getRandomNumber:
; Fill Array with Random Numbers and Increment ESI for Offset
mov ah, NUM_RANGE
call RandomRange
add ah, TO_ENSURE_NOT_ZERO
testUniqueness:
mov al, array [esi]
cmp al, ah
jne uniqueNumber
loop getRandomNumber
uniqueNumber:
mov array [esi], ah
inc esi
loop getRandomNumber
ret
fillArrayRandomly ENDP
; Display Array
displayArray PROC
pushad
mov eax, 0
mov ecx, NUM_INTEGERS
mov esi, 0
display:
mov al, array[esi]
call WriteDec
mov al, TAB
call WriteChar
inc esi
loop display
popad
call Crlf
ret
displayArray ENDP
; Selection Sort
selectionSort PROC
dec ecx
mov ebx, edi
mov edx, ecx
startOuterLoop:
mov edi, ebx
mov esi, edi
inc esi
push ecx
mov ecx, edx
startInnerLoop:
mov al, [esi]
cmp al, [edi]
pushf
inc esi
inc edi
popf
jae doNotSwap
call swap
doNotSwap:
loop startInnerLoop
pop ecx
loop startOuterLoop
ret
selectionSort ENDP
; Find Minimum Index
findMinimum PROC
mov edi, esi
minimumIndex:
mov al, [esi]
cmp al, [edi]
jae skip
mov edi, esi
skip:
inc esi
loop minimumIndex
ret
findMinimum ENDP
; Swap
swap PROC
mov al, [esi - 1]
mov ah, [edi - 1]
mov [esi - 1], ah
mov [edi - 1], al
ret
swap ENDP
END main
LOAD EFFECTIVE ADDRESS computes address of 2nd operand and moves it to the first operand.
lea esi,[edi+1] can be replaced with
mov esi,edi
inc esi
if you don't mind that INC will also change ZERO flag.
You should learn cmpsb and other string instructions ASAP, they are very useful.
cmpsb can be replaced with
MOV AL,[ESI]
CMP AL,[EDI]
PUSHF
INC ESI
INC EDI
POPF
After selectionSort has been called, the minimal value will be in the first field of your array.
Nevertheless, if your assignment was to find a pointer to the minimal value of array, here you are:
findMinimum PROC ; Return EDI=offset of leftmost byte in array with minimal value
; Input: ESI is offset of an byte array, ECX is the size of array
MOV EDI,ESI ; Initialize pointer with so far minimal value
next:MOV AL,[ESI] ; Load next value
CMP AL,[EDI] ; Compare with minimal value so far
JAE skip
MOV EDI,ESI ; Value loaded from [ESI] was below, so ESI is better candidate
skip:INC ESI ; Advance offset in array
LOOP next
RET
findMinimum ENDP
.data
unsortedArrayText DB "Randomly Generated Array, Unsorted: ", 0dh, 0ah, 0
sortedArrayText DB "Randomly Generated Array, Sorted from Lowest to Highest: ", 0dh, 0ah, 0
array DB "An array of bytes (characters) which will be sorted"
NewLine DB 0dh, 0ah, 0
NUM_INTEGERS EQU NewLine - array ; Number of integers (characters) in array
.code
main PROC
; Display Array with Annotation
; mov edx, offset unsortedArrayText
; call WriteString
ConsoleWrite unsortedArrayText
; push offset array
; call displayArray
ConsoleWrite array
; Sort Array
; push offset array
; call selectionSort
MOV EDI,array
MOV ECX,NUM_INTEGERS
CALL selectionSort
; Display Sorted Array with Annotation
; mov edx, offset sortedArrayText
; call WriteString
ConsoleWrite sortedArrayText
; push offset array
; call displayArray
ConsoleWrite array
; Exit Program
;exit
TerminateProgram
main endp
; Selection Sort
selectionSort PROC ; Bubble sort ECX byte array pointed to with EDI
DEC ECX ; Number of compare is NUM_INTEGERS-1
MOV EBX,EDI ; Save array pointer to EBX
MOV EDX,ECX ; Save number of compare to EDX
OuterLoop:
MOV EDI,EBX ; Restore array pointer
LEA ESI,[EDI+1] ; Neibourghing field
PUSH ECX ; Save OuterLoop counter on stack
MOV ECX,EDX ; Initialize InnerLoop counter
InnerLoop:
CMPSB ; compare the first byte [EDI] with its neibourgh [ESI], advance EDI,ESI
JAE NoSwap
CALL swap
NoSwap:
LOOP InnerLoop
POP ECX ; Restore OuterLoop counter
LOOP OuterLoop
RET
selectionSort ENDP
swap PROC ; Swap bytes at [EDI-1] and [ESI-1]
MOV AL,[ESI-1]
MOV AH,[EDI-1]
MOV [ESI-1],AH
MOV [EDI-1],AL
RET
swap ENDP
This worked well, statically defined array was sorted in few miliseconds:
C:\ASM>bubblesortexample.exe
Randomly Generated Array, Unsorted:
An array of bytes (characters) which will be sorted
Randomly Generated Array, Sorted from Lowest to Highest:
()Aaaaabbcccdeeeefhhhiillnoorrrrrssstttwwyy
C:\ASM>

Unhandled exception at 0x00000005 in : 0xC0000005: Access violation reading location 0x00000005. when making a ret call

My program is supposed to read an integer n from the user and then calculate all the divisors and if they are prime or not. I am using the Irvine 32 library. Now this is the weird part, when I enter in an even number my program executes as it is supposed to. When I enter in and odd number my program gets the error which is the title of this post.
My main Proc:
main PROC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block displays greeting and newline;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edx, OFFSET greeting
call Writestring
call Crlf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block gets the integer from the user;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call GetInt
call Crlf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block gets calculates the divsiors and prime divisors.;
; It then puts them in to an array to get ready to display. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call CalcDivisors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block displays the results to the screen. ;
; in an n-1 by 3 table. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call Display_Results
exit
main ENDP
Now the Proc that has produces the error:
CalcDivisors PROC uses eax ebx ecx edx esi edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function calculates divisors then pushes them on to an array;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax,0
mov ecx,0
mov ebx,0
mov edx,0
mov esi,0
mov edi,0
mov ecx,n
sub ecx,1
mov eax,n
mov ebx,divisors
mov esi,OFFSET prime_arr
mov edi,OFFSET div_arr
push eax
Calc_Div:
call dumpregs
div ebx
call dumpregs
cmp edx,0
jz Calc_Prime_Div
inc ebx
mov edx,0
mov eax,n
loop Calc_Div
Calc_Prime_Div:
cmp ebx,2
jz Push_2_array
push ebx
push ecx
mov eax,0
mov eax,ebx
mov ecx,ebx
mov divisor_counter,ebx
sub ecx,2
mov ebx,0
mov ebx,prime_divisors
P1:
call dumpregs
div ebx
call dumpregs
cmp edx,0
jz Push_div_array
inc ebx
mov eax,divisor_counter
mov edx,0
loop P1
jmp Push_prime_array
Jump_above:
call dumpregs
loop Calc_div
call dumpregs
jmp foo
Push_prime_array:
pop ecx
pop ebx
mov [esi],ebx
mov eax,[esi]
call writedec
add esi,4
mov eax,0
mov eax,n
call dumpregs
inc ebx
call dumpregs
jmp jump_above
call dumpregs
Push_div_array:
pop ecx
pop ebx
mov [edi],ebx
mov eax,[edi]
call writedec
add edi,4
mov eax,0
mov eax,n
call dumpregs
inc ebx
jmp Jump_above
Push_2_array:
mov [esi],ebx
add esi,4
inc ebx
pop eax
jmp Jump_above
foo:
ret
CalcDivisors ENDP
Now the line that is giving me the exact error is the following:
foo:
ret
It is boggling my mind as to why it is crashing when I enter in an odd number for n and not crashing when n is even. Any suggestions?
It looks like you forget to pop some values from the stack. Check the number of push and pop instructions executed.

Resources