1 / 40

Implementing Subprograms with Stack-Dynamic Local Variables

This chapter discusses the implementation of subprograms with stack-dynamic local variables and covers topics such as call semantics, parameter passing methods, return values, and the physical structure of a running program.

timmons
Download Presentation

Implementing Subprograms with Stack-Dynamic Local Variables

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 10 Implementing Subprograms

  2. Chapter 10 Topics • The General Semantics of Calls and Returns • Implementing “Simple” Subprograms • Implementing Subprograms with Stack-Dynamic Local Variables • Nested Subprograms • Blocks • Implementing Dynamic Scoping

  3. The General Semantics of Calls • The subprogram call and returnoperations of a language are together called subprogram linkage • General semantics of a subprogram call • Parameter passing methods • Stack-dynamic allocation of local variables • Save the execution status of calling program (the caller) • Transfer of control and arrange for the return • If subprogram nesting is supported, we must consider the access to non-local variables

  4. The General Semantics of Returns • General semantics issues of subprogram: • In mode and in-out mode parameters must have their values returned • De-allocation of stack-dynamic local variables • Restore the execution status of the caller • Return the control back to the caller

  5. Parameter-passing methods

  6. Implementing “Simple” Subprograms • Call Semantics:- Save the execution status of the caller- Pass the parameters- Pass the return address to the callee- Transfer control to the callee

  7. Implementing “Simple” Subprograms (continued) • Return Values: • If pass-by-value-result (in-out mode) parameters are used, replace the current values of those parameters to their corresponding actual parameters • If it is a function, move the functional value to a return value, so that it can be passed to the caller • Restore the execution status of the caller • Transfer control back to the caller • Required storage: • Status information, parameters, return address, return value for functions

  8. Implementing “Simple” Subprograms • Two separate parts: • the actual code • the non-code part (local variables and data that can change) • The format, layout, of the non-code part of an executing subprogram is called an activation record • An activation record instance is a concrete example of an activation record • Contains the collection of data for a particular subprogram

  9. Physical Structure of a Running Program

  10. Calculating a Factorial (1 of 3) This function calculates the factorial of integer n. A new value of n is saved in each stack frame: int function factorial(int n) { if(n == 0) return 1; else return n * factorial(n-1); } As each call instance returns, the product it returns is multiplied by the previous value of n.

  11. Calculating a Factorial (2 of 3) Factorial PROC push ebp movebp,esp moveax,[ebp+8] ; get n cmp eax,0 ; n < 0? ja L1 ; yes: continue mov eax,1 ; no: return 1 jmp L2 L1: deceax push eax ; Factorial(n-1) call Factorial ; Instructions from this point on execute when each ; recursive call returns. ReturnFact: movebx,[ebp+8] ; get n mulebx ; eax = eax * ebx L2: pop ebp ; return EAX ret 4 ; clean up stack Factorial ENDP See the program listing

  12. Calculating a Factorial (3 of 3) • Suppose we want to calculate 12! • The diagram shows the first few stack frames created by recursive calls to Factorial • Each recursive call uses 12 bytes of stack space.

  13. An Activation Record for “Simple” Subprograms • More complex activation record • The compiler must generate code to cause implicit allocation and de-allocation of local variables • Recursion must be supported • By adding the possibility of multiple simultaneous activations of a subprogram Passed Parameters Return address One activation record instance Saved EBP Local variables Stack top

  14. Implementing Subprograms with Stack-Dynamic Local Variables: Activation Record • The activation record format is static, but its size may be dynamic --- Two registers are required • ESP – Stack Pointer register • Used by PUSH and POP instructions, points to top of stack • EBP – Base Pointer register • Used to reference parameters and local variables on the stack • An activation record instance is dynamically created when a subprogram is called • Activation record instances reside on the run-time stack Passed Parameters Return address One activation record instance Saved EBP Local variables Stack top

  15. Function Call Recap • You might already forgot how to invoke a function call. Let’s learn from a examples • One of the most confusing concepts in Assembly Language • Parameter passing in assembly language is different • For assembly language function calls • Place all parameters in stack • Call the function • Do computing in the function • The function return the result back to the caller function

  16. Stack Parameters • Consider the following max procedure int max ( int x, int y, int z ) { int temp = x; if (y > temp) temp = y; if (z > temp) temp = z; return temp; } Calling procedure: mx = max(num1, num2, num3) Stack Parameters pushlnum3 pushlnum2 pushlnum1 call max movl %eax, mx In the following slides, we will use a lot of stack operations

  17. Stack high addr Used Unused EBP + 16 EBP + 12 EBP + 8 EBP + 4 EBP ESP ESP ESP ESP ESP ESP EBP Using the Base Pointer Register • EBP is used to allocate parameters on the stack • Like any other register, EBP must be saved before use • max: • pushl%EBP • movl %ESP,%EBP • subl $12, %ESP • movl 8(%EBP),%EAX, • cmp 12(%EBP),%EAX • jgel1 • movl 12(%EBP),%EAX • l1:cmp 16(%EBP),%EAX • jgel2 • movl 16(%EBP),%EAX • l2: pop %EBP • ret Passing Parameters on the stack pushlnum3 pushlnum2 pushlnum1 callmax movl%EAX,mx addl $12, %ESP num3 num2 num1 Return Addr Saved EBP

  18. Stack high addr Used Unused EBP + 16 EBP + 12 EBP + 8 EBP + 4 EBP ESP ESP ESP ESP ESP ESP EBP Using the Base Pointer Register • EBP is used to allocate parameters on the stack • Like any other register, EBP must be saved before use • max: • pushl%EBP • movl %ESP,%EBP • subl $12, %ESP • movl 8(%EBP),%EAX, • cmp 12(%EBP),%EAX • jgel1 • movl 12(%EBP),%EAX • l1:cmp 16(%EBP),%EAX • jgel2 • movl 16(%EBP),%EAX • l2: pop %EBP • ret Passing Parameters on the stack pushlnum3 pushlnum2 pushlnum1 callmax movl%EAX,mx addl $12, %ESP num3 num2 num1 Return Addr Saved EBP

  19. Reasons of Using the Stack • We use %ebpand %esp to support all possible operations of stack /* inttest.c - An example of returning an integer value */ #include <stdio.h> int main() { inti = 2; intk = 3; intj = square_add(i, k); printf("The square of %d is %d\n", i, j); j = square(10, 3); printf("The square of 10 is %d\n", j); return 0; } • # square.s - Returns an integer • .type square_add, @function • .globlsquare_add • square_add: • pushl%ebp • movl %esp, %ebp • movl 8(%ebp), %eax • imull %eax, %eax • addl 12(%ebp), %eax • movl %ebp, %esp • popl %ebp • ret

  20. Revised Semantic Call/Return Actions • Caller’s Actions: • Create an activation record instance • Save the execution status of the current program unit • Pass the parameters and compute • Save the return address of the caller • Transfer control to the callee • Callee’s Prologue Actions: • Save the old EP/BP in the stack as the dynamic link and create the new value • Allocate local variables

  21. Revised Semantic Call/Return Actions (continued) • Callee’s Epilogue Actions : • If there are pass-by-value-result or out-mode parameters, the current values of those parameters are moved to the corresponding actual parameters • If the subprogram is a function, the return value is moved to a place, which is accessible to the caller • Restore the stack pointer (SP) by setting it to the value of the current EP-1 (BP-1) and set the EP (BP) to the old dynamic link • Restore the execution status of the caller • Transfer control back to the caller

  22. An Example Without Recursion void fun1(float r) { int s, t; ... fun2(s); ... } void fun2(int x) { int y; ... fun3(y); ... } void fun3(int q) { ... } void main() { float p; ... fun1(p); ... } main calls fun1 fun1 calls fun2 fun2 calls fun3

  23. Stack V.S. Heap • The Stack • The Heap • Stack vs Heap Pros and Cons • Stack • Heap • Examples • When to use the Heap?

  24. Stack v.s. Heap • So far we have seen how to declare • Basic type variables such as int,double, etc, and complex types such as arrays and structs. • The way we have been declaring them so far is to put • What is the stack? • It's a special region of your computer's memory that stores temporary variables created by each function (including the main() function)..

  25. Stack v.s. Heap • The stack is a "FILO" (first in, last out) data structure, that is managed and optimized by the CPU quite closely. • Every time a function declares a new variable, it is "pushed" onto the stack. • Every time a function exits, all of the variables pushed onto the stack by that function, are freed (that is to say, they are deleted). • Once a stack variable is freed, that region of memory becomes available for other stack variables.

  26. Stack Characteristics • The advantage of using the stack to store variables, is that: • You don't have to allocate memory by hand, or free it once you don't need it any more. • Because the CPU organizes stack memory so efficiently, reading from and writing to stack variables is very fast.

  27. Stack Characteristics • A key to understanding the stack is the notion that when a function exits, all of its variables are popped off of the stack (and hence lost forever). • Thus, stack variables are localin nature. This is related to a concept we saw earlier known as variable scope, or local vs global variables. • A common bug in C programming is attempting to access a variable that was created on the stack inside some function, from a place outside of that function (i.e. after that function has exited).

  28. Stack Characteristics • Another feature of the stack is that there is a limit (varies with OS) on the size of variables that can be store in the stack. • This is not the case for variables allocated on the heap. • To summarize the stack: • the stack grows and shrinks as functions push and pop local variables • there is no need to manage the memory yourself, variables are allocated and freed automatically • the stack has size limits • stack variables only exist while the function that created them, is running

  29. Stack Example #include <stdio.h> doublemultiplyByTwo (double input) { double twice = input * 2.0; return twice; } intmain (intargc, char *argv[]) { intage = 30; double salary = 12345.67; doublemyList[3] = {1.2, 2.3, 3.4}; printf("double your salary is %.3f\n", multiplyByTwo(salary)); return 0; } These three variables are pushed into the stack as soon as the main() function allocates them As soon as main() function exits, these three variables are popped off of the stack, and is gone forever. double your salary is 24691.340

  30. Stack Example #include <stdio.h> doublemultiplyByTwo (double input) { double twice = input * 2.0; return twice; } intmain (intargc, char *argv[]) { intage = 30; double salary = 12345.67; doublemyList[3] = {1.2, 2.3, 3.4}; printf("double your salary is %.3f\n", multiplyByTwo(salary)); return 0; } These three variables are pushed into the stack as soon as the main() function allocates them As soon as main() function exits, these three variables are popped o ffof the stack, and is gone forever. double your salary is 24691.340

  31. Heap Operations • The heap is a region of your computer's memory that is not managed automatically for you, and is NOTas tightly managed by the CPU. It is a more free-floating region of memory (and is larger). • To allocate memory on the heap, you must use malloc() or calloc(),which are built-in C functions.

  32. Heap Operations • Once you have allocated memory on the heap, you are responsible for using free() to deallocate that memory once you don't need it any more. • If you fail to do this, your program will have what is known as a memory leak. That is, • Memory on the heap will still be set aside • and won‘t be available to other processes. • There is a tool called valgrind that can help you detect memory leaks.

  33. Heap: Unlike Stack • Unlike the stack, • The heap does not have size restrictions on variable size (apart from the obvious physical limitations of your computer). • Heap memory is slightly slower to be read from and written to, because one has to use pointers to access memory on the heap. • Unlike the stack, variables created on the heap are accessible by any function, anywhere in your program. Heap variables are essentially global in scope.

  34. Heap Example #include <stdio.h> #include <stdlib.h> double *multiplyByTwo (double *input) { double *twice = malloc(sizeof(double)); *twice = *input * 2.0; return twice; } intmain (intargc, char *argv[]) { int*age = malloc(sizeof(int)); *age = 30; double *salary = malloc(sizeof(double)); *salary = 12345.67; double *myList = malloc(3 * sizeof(double)); myList[0] = 1.2; myList[1] = 2.3; myList[2] = 3.4; double *twiceSalary = multiplyByTwo(salary); printf("double your salary is %.3f\n", *twiceSalary); free(age); free(salary); free(myList); free(twiceSalary); return 0; } Using malloc() to allocate memory on the heap The content of heap shall be accessed by pointers Using free() to deallocate it

  35. Stack Pros and Cons Stack • very fast access • don't have to explicitly de-allocate variables • space is managed efficiently by CPU, memory will not become fragmented • local variables only • limit on stack size (OS-dependent) • variables cannot be resized

  36. Heap Pros and Cons Heap • variables can be accessed globally • no limit on memory size • relatively slower access • no guaranteed efficient use of space, memory may become fragmented over time as blocks of memory are allocated, then freed • you must manage memory (you're in charge of allocating and freeing variables) • variables can be resized using realloc()

  37. When to use the Heap? , and when should you use the stack? • If you need to allocate a large block of memory (e.g., a large array, or a big struct), and you need to keep that variable around a long time (like a global), then • You should consider heap. • If you are dealing with relatively small variables that only need to persist as long as the function using them is alive, then • You should consider stack, it's easier and faster.

  38. When to use the Heap? , and when should you use the stack? • If you need variables like arrays and structs that can change size dynamically (e.g. arrays that can grow or shrink as needed) then • You should consider heap, and use dynamic memory allocation functions like malloc(),calloc(), realloc() and free() to manage that memory "by hand".

  39. Summary • Activation record instances contain formal parameters and local variables among other things • Static chains are the primary method of implementing accesses to non-local variables in static-scoped languages with nested subprograms • Access to non-local variables in dynamic-scoped languages can be implemented by use of the dynamic chain or thru some central variable table method

  40. Assignment Six • Activation record instances contain formal parameters and local variables among other things • Static chains are the primary method of implementing accesses to non-local variables in static-scoped languages with nested subprograms • Access to non-local variables in dynamic-scoped languages can be implemented by use of the dynamic chain or thru some central variable table method

More Related