About a year has passed since I took computer organization and I’m a bit disappointed of how much of the material faded from my memory. I only realized this while reading about Exception Control Flow (ECF) in the book Computer Systems: A programmer’s perspective, when the authors mentioned:
As with a procedure call, the processor pushes a return address on the stack before branching to the handler
Section 8.1 Exceptions
I had to pause for a moment because despite a handful of assembly programs — one of them where I implemented quicksort — I totally forgot how, in assembly, how the return address gets handled. But after reviewing my own assembly program that I wrote earlier this year, I realized that the syscall directs the processor to store the PC value into the ra (return address) register. Then, it’s the callee’s responsiblity to then save that value on the stack and after its routine finishes, call jr (jump return).
Here’s some sample code
main:
la $a0, numbers # Load the address numbers into $a0, the first argument
li $a1, 0 # Load 0 into $a, the second argument
lw $t0, length # Load the length of the array into temporary register $t0
sub $a2, $t0, 1 # Subtract 1 from the length of the array and store into $a3, the first argument
jal quicksort
li $v0, 10
syscall
quicksort:
quicksort_if:
bge $a1, $a2, quicksort_end_if # CHeck if low < high
quicksort_body:
addi, $sp, $sp, -24 # Update the stack pointer, allocating enough room for savin the 6 registers
sw $ra, 0($sp) # Store return address on the stack
sw $s0, 4($sp) # Store $s1 on the stack
sw $s1, 8($sp) # Store $s2 on the stack
sw $s2, 12($sp) # Store $s3 on the stack
sw $s3, 16($sp) # Store $s3 on the stack
sw $s4, 20($sp) # Store $s3 on the stack
move $s0, $a0 # Store $a0 (address of array) into $s0
move $s1, $a1 # Store $a1 (low) into $s1
move $s2, $a2 # Store $a2 (high) into $s2
jal partition # Call the subprogram partition
move $s4, $v0 # Store pivot -1 into $a2
move $a0, $s0 # Store $s0, array, into $a0
move $a1, $s1 # Store $s1, low, into $a1
move $a2, $s4 # Store pivot position in $a2
sub $a2, $a2, 1 # Subtract 1 from $a2 (i.e. pivot - 1)
jal quicksort # First call to quicksort (i.e. quickSort(array, low, pivotPosition - 1)
move $a0, $s0 # Store array into $a0
move $a1, $s4 # Move pivot into $a1
add $a1, $a1, 1 # Add 1 to $a1 (i.e. pivot + 1)
move $a2, $s2 # Move high (i.e. $s2) into $a2
jal quicksort # Second call to quicksort (i.e. quickSort(array, pivotPosition + 1, high)
lw $ra, 0($sp) # Restore the return address from the stack and back into $ra
lw $s0, 4($sp) # Restore $s0 from the stack
lw $s1, 8($sp) # Restore $s1 from the stack
lw $s2, 12($sp) # Restore $s2 from the stack
lw $s3, 16($sp) # Restore $s2 from the stack
lw $s4, 20($sp) # Restore $s2 from the stack
addi $sp, $sp, 24 # Pop the call frame