3/11/16 Problem How do we allocate memory during the execution of a program written in C? Programs need memory for code and data such as Chapter 10 instructions, global and local variables, etc. Memory Model for Modern programming practices encourage many Program Execution (reusable) functions, callable from anywhere. Some memory can be statically allocated, since the Original slides by Chris Wilcox, size and type is known at compile time. Colorado State University Some memory must be allocated dynamically, size and type is unknown at compile time. 1 2 2 Motivation Goals Why is memory allocation important? Why not just What do we care about? use a memory manager? n Fast program execution Allocation affects the performance and memory n Efficient memory usage usage of every C, C++, Java program. n Avoid memory fragmentation Current systems do not have enough registers to n Maintain data locality store everything that is required. n Allow recursive calls Memory management is too slow and cumbersome n Support parallel execution to solve the problem. n Minimize resource allocation Static allocation of memory resources is too n Memory should never be allocated for functions inflexible and inefficient, as we will see. that are not executed. 3 3 4 1
3/11/16 Function Call Storage Requirements Consider the following code: Code must be stored in memory so that we can execute the function. // main program int a = 10; The return address must be stored so that control int b = 20 can be returned to the caller. c = foo(a, b); Parameters must be sent from the caller to the int foo(int x, int y) { callee so that the function receives them. int z; Return values must be sent from the callee to the z = x + y; caller, that’s how results are returned. return z; } Local variables for the function must be stored What needs to be stored? somewhere, is one copy enough? n Code, parameters, locals, globals, return values 5 5 6 6 Possible Solution: Possible Solution: Mixed Code and Data Mixed Code and Data Function implementation: Calling sequence foo JMP foo_begin # skip over data ST R1, foo_paramx # R1 has ‘x’ foo_rv .BLKW 1 # return value ST R2, foo_paramx # R2 has ‘y’ foo_ra .BLKW 1 # return address JSR foo # Function call foo_paramx .BLKW 1 # ‘x’ parameter LDR R3, foo_rv # R3 = return value foo_paramy .BLKW 1 # ‘y’ parameter Code generation is relatively simple. foo_localz .BLKW 1 # ‘z’ local foo_begin ST R7, foo_rv # save return Few instructions are spent moving data. … LD R7, foo_ra # restore return RET Can construct data section by appending foo_ 7 7 8 8 2
3/11/16 Possible Solution: Possible Solution: Mixed Code and Data Separate Code and Data Memory allocation: Advantages: foo_rv .BLKW 1 # foo return value n Code and data are close together foo_ra .BLKW 1 # foo return address n Conceptually easy to understand foo_paramx .BLKW 1 # foo ‘x’ parameter n Minimizes register usage for variables foo_paramy .BLKW 1 # foo ‘y’ parameter n Data persists through life of program foo_localz .BLKW 1 # foo ‘z’ local Disadvantages: bar_rv .BLKW 1 # bar return value bar_ra .BLKW 1 # bar return address n Cannot handle recursion or parallel execution bar_paramw .BLKW 1 # bar ‘w’ parameter n Code is vulnerable to self-modification Code for foo() and bar() are somewhere else n Consumes resource for inactive functions Function code call is similar to mixed solution 9 9 10 10 Possible Solution: Real Solution: Execution Stack Separate Code and Data Instructions are stored in code segment Advantages: Global data is stored in data segment n Code can be marked ‘read only’ Statically allocated memory uses stack n Conceptually easy to understand Dynamically allocated memory uses heap n Early Fortran used this scheme n Data persists through life of program Code n Code segment is write protected Disadvantages: Data n Initialized and uninitialized globals n Cannot handle recursion or parallel execution Heap n Heap can be fragmented n Consumes resource for inactive functions ↓ n Stack size is usually limited ↑ n Stack can grow either direction Stack (usual convention is down) 11 11 12 12 3
3/11/16 Execution Stack Stack Trace What is a stack? Example stack trace from gdb: main() calls A() calls B() calls C() calls D(). n First In, Last Out (FILO) data structure Breakpoint is set in function D(), note that main() n PUSH adds data, POP removes data is at the bottom, D() is at the top. n Overflow condition: push when stack full n Underflow condition: pop when stack empty (gdb) info stack n Stack grows and shrinks as data is added and removed #0 D (a=8, b=9) at stacktest.c:23 n Stack grows downward from the end of memory space #1 0x00400531 in C (a=7, b=8) at stacktest.c:19 n Function calls allocate a stack frame #2 0x0040050c in B (a=6, b=7) at stacktest.c:15 #3 0x004004e7 in A (a=5, b=6) at stacktest.c:11 n Return cleans up by freeing the stack frame #4 0x00400566 in main () at stacktest.c:29 n Corresponds nicely to nested function calls n Stack Trace shows current execution (Java/Eclipse) 13 13 14 14 Execution Stack Stack Requirements Consider what has to happen in a function call: n Caller must allocate space for the return value. Picture of stack during n Caller must pass parameters to the callee. program execution, same n Caller must save the return address. call stack as previous slide: D(8,9) n Caller must transfer control to the callee. n main() calls A(5,6) n Callee requires space for local variables. C(7,8) n A(5,6) calls B(6,7) n Callee must return control to the caller. B(6,7) n B(6,7) calls C(7,8) Parameters, return value, return address, and n C(7,8) calls D(8,9) A(5,6) locals are stored on the stack. The order above determines the responsibility and main() order of stack operations. 15 15 16 16 4
3/11/16 Execution Stack Stack Pointers Definition: A stack frame or activation record is the Clearly we need a variable to store the stack memory required for a function call: pointer (SP), LC3 assembly uses R6. Stack execution is ubiquitous, so hardware has a n Stack frame below contains the stack pointer, sometimes even instructions. ↑ function that called this function. Problem: stack pointer is difficult to use to Locals n Stack frame above contains the access data, since it moves around constantly. functions called from this function. Return Address Solution: allocate another variable called a frame n Caller allocates return value, pushes Return Value pointer (FP), for stack frame, uses R5. parameters and return address. Parameters n Callee allocates and frees local Where should frame pointer point? Convention variables, stores the return value. ↓ sets it between caller and callee data. 17 17 18 18 Execution Stack Execution Stack Definition: A stack frame or activation record is the In the previous solutions, the compiler allocated memory required for a function call: parameters and locals in fixed memory locations. Using an execution stack means parameters and n Locals are accessed by negative ↑ locals are constantly moving around. offsets from frame pointer. The frame pointer solves this problem by using fixed Locals n Parameters and return value are accessed by positive offsets. offsets instead of addresses. Return Address n Most offsets are small, this explains The compiler can generate code using offsets, Frame Pointer LDR/STR implementation. without knowing where the stack frame will reside. Return Value n Base register stores pointer, signed Frame pointer needs to be saved and restored offset accesses both directions. Parameters around function calls. How about the stack pointer? ↓ 19 19 20 20 5
3/11/16 Nested Calls Execution Stack Advantages: Definition: A stack frame or activation record is the memory required for a function call: n Code can be marked ‘read only’ n Conceptually easy to understand n Locals are accessed by negative n Supports recursion and parallel execution offsets from frame pointer. n No resources for inactive functions FP(D) n Parameters and return value are D(8,9) n Good data locality, no fragmenting accessed by positive offsets. FP(C) C(7,8) n Minimizes register usage n Most offsets are small, this explains FP(B) Disadvantages: B(6,7) LDR/STR implementation. n Base register stores pointer, signed n More memory than static allocation FP(A) A(5,6) offset accesses both directions. main() 21 21 22 22 Detailed Example Detailed Example Assume POP and PUSH code as follows: Main program to illustrate stack convention: MACRO PUSH(reg) .ORIG x3000 ADD R6,R6,#-1 ; Decrement SP MAIN LD R6,STACK ; init stack pointer STR reg,R6,#0 ; Store value LD R0,OPERAND0 ; load first operand END PUSH R0 ; PUSH first operand LD R1,OPERAND1 ; load second operand MACRO POP(reg) PUSH R1 ; PUSH second operand LDR reg,R6,#0 ; Load value JSR FUNCTION ; call function ADD R6,R6,#1 ; Increment SP LDR R0,R6,#0 ; POP return value END ADD R6,R6,#3 ; unwind stack ST R0,RESULT ; store result HALT 23 23 24 24 6
Recommend
More recommend