My task was to implement Quick Sort in assembly from pseudocode.
;*******************************************************************************
; This program implements the Quick Sort algorithm and sorts an array
;
; Author: William
; Date: 4/6/18
TITLE Quick Sort
.386
.model flat, stdcall
.stack 4096
; prototype from Kernel32 lib
ExitProcess PROTO, dwExitCode:DWORD
.data
; An array of 25 random integers to be sorted
array DWORD 43, 91, 97, 63, 52,
58, 99, 19, 33, 26,
77, 11, 41, 89, 27,
99, 98, 68, 26, 5,
73, 47, 46, 59, 21
.code
;-------------------------------------------------------------------------------
; _partition@12 (A , p, r)
;
; Quicksort subroutine
;
; Entry: A @ ebp + 8 ; pointer to array being sorted
; p @ ebp + 12 ; integer index to start of sub-array
; r @ ebp + 16 ; integer index to end of sub-array
;
; Local: x ; The pivot
; i ; index of smaller element
;
; Exit: the index of the pivot stored in eax
;-------------------------------------------------------------------------------
_partition@12:
; set up stack, save regs
push ebp
mov ebp, esp
push ebx
push ecx
push edx
push esi
push edi
; Load function parameters into registers and initialize local variables
mov ebx, [ebp + 8] ; A stored in ebx
mov ecx, [ebp + 12] ; p stored in ecx
mov edx, [ebp + 16] ; r stored in edx
mov esi, [ebx + edx * 4] ; x initialized to A[r]
lea edi, [ecx - 1] ; i initialized to p - 1
; Loop from index p to r - 1
mov eax, ecx ; j (loop count) initialized to p
L2: cmp eax, edx
jnl endL2
; If A[j] <= x
cmp [ebx + eax * 4], esi
jnle endIf1
inc edi ; i = i + 1
; swap A[i] with A[j]
mov ecx, [ebx + edi * 4]
xchg ecx, [ebx + eax * 4]
mov [ebx + edi * 4], ecx
endIf1:
inc eax
jmp L2
endL2:
; swap A[i + 1] with A[r]
inc edi ; i = i + 1
mov ecx, [ebx + edi * 4]
xchg ecx, [ebx + edx * 4]
mov [ebx + edi * 4], ecx
mov eax, edi ; return i + 1
; clean up stack, restore regs
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp
ret 12
;-------------------------------------------------------------------------------
; _quickSort@12 (A , p, r)
;
; Sorts array of DWORD integers
;
; Entry: A @ ebp + 8 ; pointer to array to being sorted
; p @ ebp + 12 ; integer index to start of sub-array
; r @ ebp + 16 ; integer index to end of sub-array
;
;-------------------------------------------------------------------------------
_quickSort@12:
; set up stack, save regs
push ebp
mov ebp, esp
push ebx
push ecx
push edx
; Load function parameters into registers
mov ebx, [ebp + 8] ; A stored in ebx
mov ecx, [ebp + 12] ; p stored in ecx
mov edx, [ebp + 16] ; r stored in edx
; if (p < r)
cmp ecx, edx
jnl endIf2
;q = Partition(A, p, r)
push edx
push ecx
push ebx
call _partition@12 ; q stored in eax
;Quicksort(A, p, q - 1)
dec eax
push eax
push ecx
push ebx
call _quickSort@12
;Quicksort(A, q + 1, r)
add eax, 2
push edx
push eax
push ebx
call _quickSort@12
endIf2:
; clean up stack, restore regs
pop edx
pop ecx
pop ebx
pop ebp
ret 12
main:
push 24
push 0
push OFFSET array
call _quickSort@12
; array is sorted, but code does not
; print it to the console
INVOKE ExitProcess, 0
END main
This was the pseudocode I used:
Partition(A, p, r)
x = A[r]
i = p - 1
for j = p to r - 1
if A[j] <= x
i = i + 1
exchange A[i] with A[j]
exchange A[i + 1] with A[r]
return i + 1
Quicksort(A, p, r)
if p < r
q = Partition(A, p, r)
Quicksort(A, p, q - 1)
Quicksort(A, q + 1, r)
I took the advice given to me on my last post and loaded all function parameters into registers instead of reading and writing to memory over and over. All criticism is appreciated.
push edx
,mov edx, [ebp + 16]
, andpop edx
from _partition@12? Passing parameters on the stack is a common way to call functions, and there are benefits to using a known and understood parameter passing protocol. But it's not the only way, or even the fastest. For a pure asm program (such as this), passing (some of) the parameters in registers might be useful. \$\endgroup\$