static int Lookup( List h, int searchKey ) { if ( h == null ) return 0; // Not found is represented by 0 else if ( h.key == searchKey ) return (h.value); else return Lookup( h.next, searchKey ); } static void main( ) { searchVlaue = Lookup(head, searchKey); } |
Notice that:
|
push parameters (head and searchKey) on the stack bl Lookup add sp, sp, #8 // Clean up the parameters from the stack |
|
|
Stack frame of the Lookup( ) method: SP FP -----> +---------------------+ | old Frame Pointer | +---------------------+ | Return Address | +---------------------+ | head | addr(n) = FP + 8 +---------------------+ | searchKey | addr(n) = FP + 12 +---------------------+ |
You can see that the Lookup( ) function will:
main: // High level programming statement: // // searchValue = Lookup(head, searchKey) /* ------------------------------------------------- Pass parameter searchKey (using stack) ------------------------------------------------- */ movw r0, #:lower16:searchKey movt r0, #:upper16:searchKey ldr r0, [r0] // r0 = searchKey push {r0} // Pass searchKey using the program stack /* ------------------------------------------------- Pass parameter head (using stack) ------------------------------------------------- */ movw r0, #:lower16:head movt r0, #:upper16:head ldr r0, [r0] // r0 = head push {r0} // Pass head using the program stack /* ------------------------------------------------------ call Lookup(k) ------------------------------------------------------ */ bl Lookup add sp, sp, #8 // Clean up the parameters /* ----------------------------------------------------------------- Save return value (in r0) to variable searchValue ----------------------------------------------------------------- */ movw r1, #:lower16:searchValue // Do NOT use r0 !!! movt r1, #:upper16:searchValue // (Because r0 contains the return value) str r0, [r1] // This will store return value in searchValue |
/* ============================================================= Lookup(h, searchKey) int Lookup( List h, int searchKey ) { if ( h == null ) return 0; // Not found is represented by 0 else if ( h.key == searchKey ) return (h.value); else return Lookup( h.next, searchKey ); } Stack frame structure for Lookup( ) is: FP----> +-----------+ | old FP | +-----------+ | ret addr | +-----------+ FP+8 | h | +-----------+ FP+12 | searchKey | +-----------+ ============================================================= */ Lookup: /* ================================== Prelude: build stack frame ================================== */ push {lr} push {fp} mov fp, sp sub sp, sp, #0 // 0 local variables // if ( h == null ) ldr r0, [fp,#8] // r0 = h cmp r0, #0 bne else1 // return(0) in r0 mov r0, #0 /* ===================================================== Postlude: de-allocate locals, restore FP and return ===================================================== */ mov sp, fp pop {fp} pop {pc} else1: // if ( h.key == searchKey ) ldr r0, [fp,#8] // r0 = h ldr r0, [r0,#0] // r0 = h.key ldr r1, [fp,#12] // r1 = searchKey cmp r0, r1 bne else2 // return (h.value); in register r0 !!! ldr r0, [fp,#8] // r0 = h ldr r0, [r0,#4] // r0 = h.value /* ===================================================== Postlude: de-allocate locals, restore FP and return ===================================================== */ mov sp, fp pop {fp} pop {pc} else2: // Call Lookup( h.next, searchKey ) ldr r0, [fp,#12] // r0 = searchKey push {r0} // Pass searchKey as parameter on stack ldr r0, [fp,#8] // r0 = h ldr r0, [r0,#8] // r0 = h.next push {r0} // Pass h.next as parameter on stack // Call Lookup( ) with parameters: h.next and searchKey on stack bl Lookup add sp, sp, #8 // Clean up parameters // It just happens that Lookup( ) return its value in r0 // So we don't need to do anything // return (Lookup( )'s return value ); already in register r0 !!! /* ===================================================== Postlude: de-allocate locals, restore FP and return ===================================================== */ mov sp, fp pop {fp} pop {pc} |
How to run the program:
|
The main program passes the variables head and searchKey to the Lookup method by pushing the value of variables head and searchKey onto the system stack with the following instruction:
// Pass searchKey using the stack movw r0, #:lower16:searchKey movt r0, #:upper16:searchKey // r0 = addr(searchKey) ldr r0, [r0] // r0 = searchKey push {r0} // Pass searchKey on the stack // Pass head using the stack movw r0, #:lower16:head movt r0, #:upper16:head // r0 = addr(head) ldr r0, [r0] // r0 = head push {r0} // Pass head on the stack |
This will create the following stack structure:
+---------------------+ <------------ Stack pointer (SP) | head | +---------------------+ | searchKey | +---------------------+ |
The main program calls the Lookup function with a bl instruction:
bl Lookup |
This will save the return address to main( ) in the LR register and jump to the Lookup method
The Lookup( ) function will start running, so let's take a look at the Lookup( ) function
The prelude of the Lookup function consists of these instructions:
/* ========================================================== Function Prelude: complete the stack frame structure ========================================================== */ push {lr} // Save LR (return address) push {fp} // Save FP (used by caller) mov fp, sp // Mark the stack top location before // allocating any local variables sub sp, sp, #0 // Allocate 0 int variables on the stack // (I could omit this instruction....) |
I will explain what each one does below.
Make sure that you realise that the structure of the stack frame is like this when the prelude of the Lookup( ) method is executed:
+---------------------+ <------------ Stack pointer (SP) | head | +---------------------+ | searchKey | +---------------------+ |
This instruction will save the return address in the LR register on the program stack.
The program stack now looks like this:
+---------------------+ <------------ Stack pointer (SP) | return address | +---------------------+ | head | +---------------------+ | searchKey | +---------------------+ |
This will save the frame pointer on the stack and the program stack now looks like this:
+---------------------+ <------------ Stack pointer (SP) | old Frame Pointer | +---------------------+ | return address | +---------------------+ | head | +---------------------+ | searchKey | +---------------------+ |
This will make the frame pointer FP points to the stack frame that is being built:
+---------------------+ <------------ Frame pointer FP & Stack pointer SP | old Frame Pointer | point to the same location.... +---------------------+ | return address | +---------------------+ | head | +---------------------+ | searchKey | +---------------------+ |
The will enable the Lookup( ) to use offset from the frame pointer to access the parameters and local variables that are stored in the program stack
The subtract instruction is used to allocate local variables on the program stack
But since Lookup( ) has no local variables, this instruction does nothing to the stack pointer SP... (and we could omit it - I left it in to keep the discussion uniform)
We have now completed the stack frame:
+---------------------+ <---- Frame pointer FP & Stack pointer SP | old Frame Pointer | point to the same location.... +---------------------+ | return address | +---------------------+ | head | +---------------------+ | searchKey | +---------------------+ |
When the prelude is finish, the stack frame is complete and the actual function can begin.
+---------------------+ <-------------- Frame pointer FP | old Frame Pointer | (4 bytes) +---------------------+ | return address | (4 bytes) +---------------------+ | head | <--- offset = 8 +---------------------+ | searchKey | <--- offset = 12 +---------------------+ |
So base register (FP) + offset 8 will let you access h (= head)
And base register (FP) + offset 12 will let you access searchKey
That's why you see the use of the following instructions in Lookup( ) to get the parameter:
ldr r0, [fp,#8] // r0 = h and ldr r0, [fp,#12] // r0 = searchKey |
It is no different from how the main program calls the Lookup function.
The Lookup method can call the Lookup method by passing the parameter on the program stack and then use bl Lookup to call the Lookup method.
But make sure you pop the parameter from the stack after the Lookup function returns - because the parameter has not been cleaned up.
The following is the program fragment where Lookup calls Lookup(h.next, searchKey) by passing the parameters h.next and searchKey on the stack:
// Call Lookup( h.next, searchKey ) ldr r0, [fp,#12] // r0 = searchKey push {r0} // Pass searchKey as parameter on stack ldr r0, [fp,#8] // r0 = h ldr r0, [r0,#8] // r0 = h.next push {r0} // Pass h.next as parameter on stack // Call Lookup( ) with parameters: h.next and searchKey on stack bl Lookup add sp, sp, #8 // Clean up parameters |