Clemson University -- CPSC 231 -- Spring 2010 Run-time environment for a program different logical parts of program during execution stack - automatically allocated variables (local variables, subdivided into stack frames - one per procedure invocation) heap - dynamically allocated variables data - global variables (will see subdivisions of this section later) text - program code / instructions low addresses | . . . | +-------+ -. int g = 1; /* g placed in data */ | text | \ |-------| | program's int main(){ | data | | layout in int i; /* i alloc. on stack */ |-------| | memory ... | heap | | } |---|---| | | v | | | ... | | a dynamically allocated variable | ^ | | (i.e., malloc(), new, ...) |---|---| | will be placed in the heap | stack | / +-------+ -' | . . . | high addresses (note: some memory diagrams may be reversed, with high memory at top) Memory Stack storage for automatic variables, that is, for local variables that are allocated at the beginning of a procedure call and that are discarded at the end of the procedure call stack matches the LIFO behavior of nested procedure calls (incl. recursion) the collection of information related to a specific instance of calling a procedure is termed a "stack frame" two registers manage the stack %o6 = %sp - stack pointer (top of stack) - must be doubleword aligned %i6 = %fp - frame pointer (anchors current procedure's stack frame) | ^ | lower addresses | | | +-----------------+ %sp - stack pointer ->|.................| current stack frame - locals |.local variables.| accessed with addresses |.................| %fp - k +-----------------+ %fp - frame pointer ->|.................| older stack frames |.................| - represents call |.................| chain from main() |.................| +-----------------+ base of stack ->| | higher addresses the stack is located in high addresses in memory and grows toward small addresses, so pushing something on the stack decrements the stack pointer the save instruction makes room on the stack for local variables and other information in a stack frame Loads and stores load - different sizes, signed/unsigned distinction for smaller than word ld - load word ldsh - load halfword (w/ sign extension) lduh - load unsigned halfword ldsb - load byte (w/ sign extension) ldub - load unsigned byte store - different sizes st - store word sth - store halfword stb - store byte addressing modes - methods of forming a memory address SPARC has two addressing modes: [reg + reg] - one can be %g0 to have form [reg] [reg + disp] - displacement is sign-extended 13-bit constant typical form of load for accessing a local variable: ld [%fp-4], %o1 typical form of store for accessing a local variable: st %o1, [%fp-4] example void main(){ int a = 0; a = a + 1; } save %sp, -120, %sp ! make room on stack for new stack frame ! local variable a's address is %fp-20 st %g0, [%fp-20] ! a = 0; ! next three instructions perform a = a + 1; ld [%fp-20], %o0 ! 1. read a's value (from the stack) add %o0, 1, %o1 ! 2. add one st %o1, [%fp-20] ! 3. store new value back into a (into the stack) ret restore Pointers a pointer is the address of an object in memory a pointer is 32 bits in length (in SPARC v7 and v8) a pointer can be in a register or in a memory word example int main(){ int a; int *pa = &a; *pa = 5; return 0; } .global main ... main: save %sp, -120, %sp | | add %fp, -20, %g1 pa: | &a |<- fp-24 st %g1, [%fp-24] a: | 5 |<- fp-20 ld [%fp-24], %l0 | | mov 5, %l1 | | st %l1, [%l0] | | mov 0, %i0 |______| ret | |<- fp restore ... extended example with printfs int main(){ int a = 0; int *pa = &a; printf("address of a = 0x%08x and contents of a = 0x%08x\n",&a,a); printf("address of pa = 0x%08x and contents of pa = 0x%08x\n",&pa,pa); *pa = 5; printf("address of a = 0x%08x and contents of a = 0x%08x\n",&a,a); printf("address of pa = 0x%08x and contents of pa = 0x%08x\n",&pa,pa); return 0; } address of a = 0xffbff86c and contents of a = 0x00000000 address of pa = 0xffbff868 and contents of pa = 0xffbff86c address of a = 0xffbff86c and contents of a = 0x00000005 address of pa = 0xffbff868 and contents of pa = 0xffbff86c (addresses might differ when you run on other platforms; e.g., stack addresses begin with 0xffbec000 on 32-bit sun4u address space model) int gv = 0; int main(){ int lv = 0; int *phv = malloc(4); printf("address of main = 0x%08x\n",main); printf("address of global variable = 0x%08x\n",&gv); printf("address of heap variable = 0x%08x\n",phv); printf("address of local variable = 0x%08x\n",&lv); return 0; } address of main = 0x00010628 address of global variable = 0x00020994 address of heap variable = 0x000209a8 address of local variable = 0xffbff86c