here's an example i found in ww.cs.clemson.edu/~mark/231/19
Clemson University -- CPSC 231 -- Fall 2001 19 Non-stack variables global variable - a variable declared/defined in one source file that is available to routines in other source files external variable - a variable needed by but not defined in the current source file static variable - a local variable that must retain its value between procedure calls variable type "global" "static" "automatic" dynamic -------- -------- ----------- ------------------ scope/visibility global local local global or local lifetime program program fn. call from alloc to free Program sections reflect different logical parts of program text - program code data - initialized variables bss (block started by symbol) - uninitialized variables stack - automatically allocated variables (local variables) and other stack frame entries heap - dynamically allocated variables | . . . | +-------+ -. int x = 1; /* x placed in data */ | text | \ int y; /* y in placed bss */ |-------| | program's int main(){ | data | | layout in int z; /* z alloc. on stack */ |-------| | memory ... | bss | | y = 2; /* code put in text */ |-------| | ... | heap | | return 0; /* retval in reg %o0 */ |---|---| | } | . V . | | | . . . | | a dynamically allocated variable will | . ^ . | | placed in the heap |---|---| | | stack | / a local variable declared with the +-------+ -' keyword "static" in C will be placed | . . . | in data if initialized, else in bss different protection -- text is read-only; data, bss, the heap, and the stack are read-write; a special rodata section is read-only the assembler maintains a separate location counter for the first three program sections above (the stack and heap do not have to be declared in the assembly program) pseudo-ops can be used to switch back and forth among the sections in the source code, but the assembler will gather like kinds of regions into separate memory sections .section ".text" - assembler switches to the text section location counter (the assembler starts in text section by default) .section ".data" - assembler switches to the data section location counter .word - followed by a list of initialized values .byte - followed by a list of initialized values (an ASCII character code is recognized by a single character placed in double quotes) .ascii - character string in double quotes .asciz - null-terminated character string, useful for strings when using routines from the C library .section ".bss" - assembler switches to the bss section location counter .skip - advances location counter a given number of bytes .section ".rodata" - read-only initialized data section .align - variables of word size must be aligned (.align 4) .global - allows symbol to be referenced beyond current source file (also, you need to declare a symbol global for gdb to be able to use it) example int x = 1; int y; int main(){ int z; printf( "variable x from data section has value %d\n", x ); y = 2; printf( "variable y from bss section has value %d\n", y ); z = 3; printf( "local variable z has value %d\n", z ); return 0; } .global main main: save %sp,-104,%sp /* load value from initialized non-stack variable "x" */ set x,%o0 ld [%o0],%o1 set fmt1,%o0 call printf nop /* place value into uninitialized non-stack variable "y" */ mov 2,%o1 set y,%o0 st %o1,[%o0] /* load value from non-stack variable "y" */ set y,%o0 ld [%o0],%o1 set fmt2,%o0 call printf nop /* place value into local variable "z" on stack */ /* note that the address of "z" is not z but %fp-4 instead */ mov 3,%o0 st %o0,[%fp-4] /* load value from local variable "z" on stack */ /* note that the address of "z" is not z but %fp-4 instead */ ld [%fp-4],%o1 set fmt3,%o0 call printf nop /* place return value in %i0 here, will be in %o0 for caller */ clr %i0 ret restore .section ".data" x: .word 1 .section ".bss" y: .skip 4 .section ".rodata" fmt1: .asciz "variable x from data section has value %d\n" fmt2: .asciz "variable y from bss section has value %d\n" fmt3: .asciz "local variable z has value %d\n" in C++ programs, the library initializers (i.e., startup code) should run first, then application constructors, then the application program, then application destructors, and finally the library finalizers (exit code). so, a C++ compiler may generate four additional program sections: .init - followed by pointers to library initializers .ctor - followed by pointers to application constructors .dtor - followed by pointers to application destructors .fini - followed by pointers to library finalizers C++ allows overloaded function names, so the compiler and/or linker need to use mangled names, e.g., for fn(int x), the function name becomes fn__i for fn(float x), the function name becomes fn__f additionally, templates in C++ can cause problems with missing routines or superfluous routines. some C++ compilers require a trial linking step to cause the linker to generate error messages indicating the missing routines, and then those versions of the template are generated.