        .data
foo_prints:
        .asciiz "foo is called\n"
bar_prints_enter:
        .asciiz "bar is called ENTER\n"
bar_prints_exit:
        .asciiz "bar is called EXIT\n"
main_prints_enter:
        .asciiz "main is called ENTER\n"
main_prints_exit:
        .asciiz "main is called EXIT\n"

        # C code:
        #
        # void foo() {
        #   printf("foo is called\n")
        # }
        # void bar() {
        #   printf("bar is called ENTER\n")
        #   foo()
        #   printf("bar is called EXIT\n")
        # }
        # void main() {
        #   printf("main is called ENTER\n")
        #   bar()
        #   printf("main is called EXIT\n")
        # }
        
        .text
foo:
        # print the message
        la $a0, foo_prints
        li $v0, 4
        syscall
        jr $ra

bar:
        # save the return address on the stack
        addi $sp, $sp, -4
        sw $ra, 0($sp)

        # print the message
        la $a0, bar_prints_enter
        li $v0, 4
        syscall

        # call foo
        jal foo

        # print the other message
        la $a0, bar_prints_exit
        li $v0, 4
        syscall

        # restore return address and return
        lw $ra, 0($sp)
        addi $sp, $sp, 4
        jr $ra

main:
        # print the message
        la $a0, main_prints_enter
        li $v0, 4
        syscall

        # call bar
        jal bar

        # print the other message
        la $a0, main_prints_exit
        li $v0, 4
        syscall

        # exit safely
        li $v0, 10
        syscall

