The flow of control in a subroutine call
 

Review: Control flow

  • Control flow (or flow of control) = the order in which the statements (= instructions in the program are executed

 

The control flow in a subroutine call:

   function f1( )               function f2( )
   {                   +------->{         
       ...             |            ...  |
       ...             |            ...  |
       ...       call  |            ...  |
       f2( ) ----------+            ...  |
       ...   <--------------+       ...  |
       ...                  |       ...  V 
       ...                  +------ return;
   }                             }
   

Can the subroutine call control flow be implemented with the branch instruction ?

Consider the control flow in the following function call A( ):

   main( )                A( )
   {             +------->{
      ...        |           ...
      A( ); -----+           ...
      ...  <-------+         ...
      ...          |
                   +-------- ...
   }                      }

Can we implement the control flow using branch instrucions ???

 main:                     A:







   

Can the subroutine call control flow be implemented with the branch instruction ?

Consider the control flow in the following function call A( ):

   main( )                A( )
   {             +------->{
      ...        |           ...
      A( ); -----+           ...
      ...  <-------+         ...
      ...          |
                   +-------- ...
   }                      }

Yes, here is the solution:

 main:                     A:
        ...	  +------->  ...
        ...	  |          ...
	b  A  ----+	     ...
   Ret: ...  <--------+	     ...
        ...	      |	     ...
                      +----- b Ret
 
  

Why the branch instruction cannot be used to implement subroutine call

Consider another control flow in the following two function calls A( ):

   main( )                        A( )
   {              +--------->--+->{
      ...         |            |     ...
      A( ); ------+            |     ...
      ...  <------ return 1    |     ...
      ...                      |     ...
      ...                      |     ...
      ...                      |   }
      A( ); -------------------+
      ...  <------ return 2
      ...
   }   

The function A( ) can only branch to a fixed return location with branch instruction

 main:                     A:
        ...	  +------->  ...
        ...	  |          ...
	b  A  ----+	     ...
   Ret: ...  <--------+	     ...
        ...	      |	     ...
        ...           +----- b Ret
        ...
        b  A 
             <---- cannot return here with  b Ret 

Lessons learned from these function call + return examples

  • Return address:

    • Return address = the memory address of the instruction that follows the subroutine call instruction

  • When calling a subroutine, we must save (= remember) the return address

       main( )                        A( )
       {              +--------->--+->{
          ...         |            |     ...
          A( ); ------+            |     ...
          ...  <-- return addr 1   |     ...
          ...                      |     ...
          ...                      |     ...
          ...                      |   }
          A( ); -------------------+
          ...  <-- return addr 2 
          ...
       }   

  • The subroutine/function must jump to the return address when finished

Analogy of the function call + return program flow

  • When a subroutine is called:

    • Remember the location (= address) where you came from

      I.e.: left a bread crumb to mark where you came from

  • When a subroutine returns:

    • Use the return address to go back

      I.e.: go back to the last bread crumb