Overview of general memory structure
The general structure of memory (based on the memory addresses of global variables, static locals, functions and instructions, heap dynamic variables, local variables, and parameters) apppears to be as shown below.
Each of the different aspects of memory organization will be discussed in greater detail in later sections.
Memory Address Content description ~0x800000000000 +----------------------+ | main's stack frame | | nested call1 frame | STACK | nested call2 frame | | | | | | | | | | | | v v | ........... | ^ ^ | | | | | | | | | | | HEAP | third dynamic req. | | second dynamic req. | | first dynamic req. | ~0x000010000000 +----------------------+ | | | ^ ^ | | | | | | | | | | etc. for all statics | see the note below for static local GLOBALS | second static local | constants, as similar rules | first static local | apply for static local variables +----------------------+ | | | uninitialized global | note that different placement rules | vars and consts | are in place for uninitialized | ^ ^ | constants/variables than for | | | | those which have been initialized | | | | | etc. for all globals | | second global var | | first global var | ~0x000000600000 +----------------------+ | | | ^ ^ | | | | | CONSTANTS | | | | note static local constants | static local consts | for later functions appear | global constants | at lower addresses, and | ^ ^ | within a function the first | | | | static goes at the lowest CODE | | | | address | etc. for all funcs | | second function | | first function | ~0x000000400000 +----------------------+
Placement and alignment of contants
Shown here in a code snippet with corresponding output, illustrating how the different
constant types get grouped relative to the code segments.
Note the uninitialized global variables/constants are being split off from the rest, otherwise padding is used to handle memory-alignment while maintaining the original ordering.
#include <stdio.h> /* where are relative locations of global vars, constants, static const, etc */ int u = 0; static const int v = 1; const int w = 2; int x = 3; static const int y = 4; const int z = 5; /* are global variables rearranged or padded */ char gCu1; /* uninitialized global variables */ char gCu2; /* uninitialized global variables */ char gC0 = 7; char gC1 = 1; long gL1 = 2; int gI1 = 3; char gC2 = 4; short gS1 = 5; long gL2 = 6; /* are global constants rearranged or padded */ const char kCu1; /* uninitialized global constants */ const char kCu2; /* uninitialized global constants */ const char kC0 = 7; const char kC1 = 1; const long kL1 = 2; const int kI1 = 3; const char kC2 = 4; const short kS1 = 5; const long kL2 = 6; void f1() { printf("global var alignment/rearrangement test\n"); printf(" uninit char1 %p, uninit char2 %p\n", &gCu1, &gCu2); printf(" char0 %p, char1 %p, long1 %p, int1 %p\n", &gC0, &gC1, &gL1, &gI1); printf(" char2 %p, short1 %p, long2 %p\n", &gC2, &gS1, &gL2); printf("global const alignment/rearrangement test\n"); printf(" uninit char1 %p, uninit char2 %p\n", &kCu1, &kCu2); printf(" char0 %p, char1 %p, long1 %p, int1 %p\n", &kC0, &kC1, &kL1, &kI1); printf(" char2 %p, short1 %p, long2 %p\n", &kC2, &kS1, &kL2); } void f2(); int main() { static const int a = 0; const int b = 1; int c = 2; static const int d = 3; const int e = 4; int f = 5; PRINTFS: printf("f1: %p, f2: %p, main: %p, PRINTFS: %p\n", f1, f2, main, &&PRINTFS); printf("a: %p, b: %p, c: %p\n", &a, &b, &c); printf("d: %p, e: %p, f: %p\n", &d, &e, &f); printf("u: %p, v: %p, w: %p\n", &u, &v, &w); printf("x: %p, y: %p, z: %p\n", &x, &y, &z); f1(); } void f2() { } | f1: 0x40054c, f2: 0x4006f0, main: 0x40061c, PRINTFS: 0x400640 a: 0x400934, b: 0x7ffe829d59dc, c: 0x7ffe829d59d8 d: 0x400938, e: 0x7ffe829d59d4, f: 0x7ffe829d59d0 u: 0x600cc4, v: 0x4007b0, w: 0x4007b4 x: 0x600ca0, y: 0x4007b8, z: 0x4007bc global var alignment/rearrangement test uninit char1 0x600cc9, uninit char2 0x600ccb char0 0x600ca4, char1 0x600ca5, long1 0x600ca8, int1 0x600cb0 char2 0x600cb4, short1 0x600cb6, long2 0x600cb8 global const alignment/rearrangement test uninit char1 0x600cca, uninit char2 0x600cc8 char0 0x4007c0, char1 0x4007c1, long1 0x4007c8, int1 0x4007d0 char2 0x4007d4, short1 0x4007d6, long2 0x4007d8 |
Data sizes
The dataSizes routine gives us the following information about the
size of various data elements:
Doh! Forgot to include code to show that 8 byte alignment is also required for structs and arrays, regardless of what data types their fields/elements are, but unions can align on whatever is appropriate for their largest field. E.g. char c; char C_arr[5] = "test"; printf("c:%p, char arr:%p\n", &c, C_arr); /* pads to 8 */ char c2; long arr[3] = { 1, 2, 3 }; printf("c2:%p, long arr:%p\n", &c2, arr); /* pads to 8 */ char c3; union { char c; } x; printf("c3:%p, char union:%p\n", &c3, &x); /* fits anywhere */
Data ordering and alignment
The dataAlign() and revAlign() functions give us insight into the order in which parameters and local variables are stored on the stack.
The examineStack() function gives us insight into the ordering of local variables compared to block locals.
The mask() and examineStack() functions give us insight into the location of static local variables.
The main() routine gives us insight into the location of global variables.
#include <stdio.h> typedef struct { char c; } charStr; typedef struct { int i; } intStr; typedef struct { char c1, c2, c3; } multiCharStr; typedef struct { int d1, d2, d3; } multiIntStr; int main() { charStr s1, s2, s3; printf("address of sequential single-char structs:\n"); printf(" s1: %p, s2: %p, s3: %p\n", &s1, &s2, &s3); multiCharStr m1, m2, m3; printf("address of sequential three-char structs:\n"); printf(" m1: %p, m2: %p, m3: %p\n", &m1, &m2, &m3); charStr i1, i2, i3; printf("address of sequential single-int structs:\n"); printf(" i1: %p, i2: %p, i3: %p\n", &i1, &i2, &i3); multiIntStr n1, n2, n3; printf("address of sequential three-int structs:\n"); printf(" n1: %p, n2: %p, n3: %p\n", &n1, &n2, &n3); intStr i4, s4, i5, s5; printf("address of alternating single-char/single-int structs:\n"); printf(" i4: %p, s4: %p, i5: %p, s5: %p\n", &i4, &s4, &i5, &s5); } | address of sequential single-char structs: s1: 0x7ffd3f17d46f, s2: 0x7ffd3f17d46e, s3: 0x7ffd3f17d46d address of sequential three-char structs: m1: 0x7ffd3f17d460, m2: 0x7ffd3f17d450, m3: 0x7ffd3f17d440 address of sequential single-int structs: i1: 0x7ffd3f17d43f, i2: 0x7ffd3f17d43e, i3: 0x7ffd3f17d43d address of sequential three-int structs: n1: 0x7ffd3f17d430, n2: 0x7ffd3f17d420, n3: 0x7ffd3f17d410 address of alternating single-char/single-int structs: i4: 0x7ffd3f17d400, s4: 0x7ffd3f17d3f0, i5: 0x7ffd3f17d3e0, s5: 0x7ffd3f17d3d0 |
As shown in dataAlign(), parameters are not necessarily stored in the order declared!. In dataAlign the declared parameter order is (pre, b, c, d, a, post), but when we print their addresses we find the order in memory is (pre, b, c, a, d, post).
We also find that the static locals appear as a group immediately following the block of globals.
Both globals and static locals appear to be stored in the same order as they appear in the code (within their respective sections).
Run time stack content/organization
The stack is thus growing "down" from high memory addresses to low, with main's stack space appearing above, and functions called from main appearing immediately below it.
As we can see, the same stack space is being re-used for calls to various functions from main, thus more-or-less confirming our expectation that the runtime stack really is behaving in stack-like fashion (i.e. popping off the space for completed function calls, and reusing that space when pushing space for a subsequent function call).
On examining the addresses, we notice a gap of 96 bytes between the last parameter of main and the first local variable in examineStack, thus examineStack has also been designed to display the values in that gap in 8-byte chunks.
Examining the output of the two functions leads us to the structure below for the stack frames.
Of note, we find that block locals are treated seperately from variables with full function scope, and some interesting content being stored on the stack in addition to the expected parameters, locals, and return locations.
+----------------------------------+ | x | main's local variables | y | in the order declared | z | | p | | u | | s | | arr | +----------------------------------+ | argc | main's parameters | argv | in the order declared +----------------------------------+ | pointer 14 bytes above main's x | | the value 9 (???) | the "mystery gap", | pointer 8 bytes above main's x | appears to be accessors | pointer to main's local var y | to the previous stack frame, | code address of point of call | plus the addresses of the | ptr to 32 bytes above main's x | complex data items that were | pointer to static var maskLocal | passed-by-value from main | pointer to static var maskLocal | | pointer to just above main | i.e. u and s's contents were | pointer to main's struct s | passed, but here are their | pointer to main's union u | addresses as well? | pointer to just above main | +----------------------------------+ | c | examineStack's locals | ptr | (not static locals | d | and not block locals yet) | e | | h | | i | | j | +----------------------------------+ | f | | g | | k | | l | examineStack's block locals +----------------------------------+ | a | examineStack's parameters | b | +----------------------------------+
Parameter passing mechanisms
These are investigated in the passingDefaults() function, as called from the main routine.
Here we see that primitive data types are passed by value.
Passing arrays appears to the programmer to act as pass by reference since the array "variable" is the address of the first array element, hence array contents are not copied onto the stack and back.
Unions are shown to be passed by value.
The most interesting component is the passing of structs, which are passed by value (i.e. their contents copied onto the stack) but it appears that the address of the original struct is also passed to the function!
For the function passingDefaults(long, struct, union, long[3], long) we find the stack contents look like this:
+----------------------------------+ | struct field 5 value | | struct field 4 value | | struct field 3 value | | struct field 2 value | | struct field 1 value | +----------------------------------+ | ptr to struct in main | | ptr to struct in main | | ptr to this location (?) | | ptr to static var maskLocal | +----------------------------------+ | first long | +----------------------------------+ | union value | +----------------------------------+ | array address | +----------------------------------+ | last long | +----------------------------------+
Analysis of dynamically-allocated memory
As shown in mallocTesting() combined with chMallocTest(), there appears to be 8 bytes of overhead associated with each allocated chunk (with the overhead stored after the section the programmer is shown), and the chunks are allocated in multiples of 32 bytes. Thus requests up to 24 bytes take 1 32-byte chunk, requests up to 56 bytes take 2, up to 88 bytes take 3, etc.
The chunks are allocated from a seperate memory area than globals, code, and the stack, and this grows upwards in memory (towards the stack, which is growing down).
As shown in freeTest(), when we deallocate chunks that were previously allocated, the first 8 bytes of the chunk is overwritten with a pointer to the previous free chunk, while the rest of the chunk appears unchanged.
As we see at the end of freeTest(), when multiple blocks of space are freed and new requests come in, the first block selected is the most recently freed block.
Location/ordering of instructions
As shown in the main routine and the instructions() routine, the executable instructions are stored in a seperate area of memory, in the order the functions appear in the source code starting in the vicinity of address 0x0400000.
Most instructions appear to take 8 bytes. Those that take more (e.g. the loop) presumably require multiple machine code instructions to implement the single C instruction.
assign5.c | #include <stdio.h> #include <stdlib.h> #include <string.h> /* global variables */ long globalx = 5; long globaly = 9; /* mask all but the bottom 8 bytes when printing addresses */ long* mask(long *ptr) { static long maskLocal = 3; if (ptr == 0) return (&maskLocal); return (long*)( ((long)(ptr))&0x00ffffffff); } typedef struct { char cFld; short sFld; int iFld; char cFld2; long lFld; long lFld2; } FwdStr; typedef struct { long lFld; long lFld2; int iFld; short sFld; char cFld; char cFld2; } RevStr; typedef union { char cFld; short sFld; int iFld; long lFld; float fFld; double dFld; } unionCombo; void examineBlock(long *ptr) { int i = 0; while (i < 8) { printf("%x", (*ptr)); if (i == 7) printf("\n"); else printf(":"); i++; ptr++; } } long* init() { long* ptr = (long*)malloc(7*sizeof(long)); long i = 0; while (i < 7) { ptr[i] = i; i++; } return ptr; } void freeTest() { /* request a series of eight blocks of memory, each will grab a 64-byte block * then free blocks 1, 4, 5, 8 * then request four more blocks and see if you get them back */ long *ptr1 = init(); long *ptr2 = init(); long *ptr3 = init(); long *ptr4 = init(); long *ptr5 = init(); long *ptr6 = init(); long *ptr7 = init(); long *ptr8 = init(); long *ptr0 = ptr1; ptr0--; long *ptr9 = &(ptr8[8]); printf("\nAllocated blocks:\n"); printf(" 1:%p, 2:%p,\n", mask(ptr1), mask(ptr2)); printf(" 3:%p, 4:%p,\n", mask(ptr3), mask(ptr4)); printf(" 5:%p, 6:%p,\n", mask(ptr5), mask(ptr6)); printf(" 7:%p, 8:%p,\n", mask(ptr7), mask(ptr8)); printf("contents just prior to block 1: %x\n", (*ptr0)); printf("block 1 contents as 8 longs:"); examineBlock(ptr1); printf("block 2 contents as 8 longs:"); examineBlock(ptr2); printf("block 3 contents as 8 longs:"); examineBlock(ptr3); printf("block 4 contents as 8 longs:"); examineBlock(ptr4); printf("block 5 contents as 8 longs:"); examineBlock(ptr5); printf("block 6 contents as 8 longs:"); examineBlock(ptr6); printf("block 7 contents as 8 longs:"); examineBlock(ptr7); printf("block 8 contents as 8 longs:"); examineBlock(ptr8); printf("contents just after block 8: %x\n", (*ptr9)); printf("\nFreeing blocks 1, 4, 5, 8\n"); free(ptr1); free(ptr4); free(ptr5); free(ptr8); printf("contents just prior to block 1: %x\n", (*ptr0)); printf("block 1 contents as 8 longs:"); examineBlock(ptr1); printf("block 2 contents as 8 longs:"); examineBlock(ptr2); printf("block 3 contents as 8 longs:"); examineBlock(ptr3); printf("block 4 contents as 8 longs:"); examineBlock(ptr4); printf("block 5 contents as 8 longs:"); examineBlock(ptr5); printf("block 6 contents as 8 longs:"); examineBlock(ptr6); printf("block 7 contents as 8 longs:"); examineBlock(ptr7); printf("block 8 contents as 8 longs:"); examineBlock(ptr8); printf("contents just after block 8: %x\n", (*ptr9)); printf("\nRequesting replacements for 1, 4, 5, 8\n"); ptr1 = (long*)malloc(7*sizeof(long)); ptr4 = (long*)malloc(7*sizeof(long)); ptr5 = (long*)malloc(7*sizeof(long)); ptr8 = (long*)malloc(7*sizeof(long)); printf("Newly allocated blocks:\n"); printf(" 1:%p, 4:%p,\n", mask(ptr1), mask(ptr4)); printf(" 5:%p, 8:%p,\n", mask(ptr5), mask(ptr8)); printf("contents just prior to block 1: %x\n", (*ptr0)); printf("block 1 contents as 8 longs:"); examineBlock(ptr1); printf("block 2 contents as 8 longs:"); examineBlock(ptr2); printf("block 3 contents as 8 longs:"); examineBlock(ptr3); printf("block 4 contents as 8 longs:"); examineBlock(ptr4); printf("block 5 contents as 8 longs:"); examineBlock(ptr5); printf("block 6 contents as 8 longs:"); examineBlock(ptr6); printf("block 7 contents as 8 longs:"); examineBlock(ptr7); printf("block 8 contents as 8 longs:"); examineBlock(ptr8); printf("contents just after block 8: %x\n", (*ptr9)); } void chMallocTest(int size) { char *c = (char*)malloc(size*sizeof(char)); int i = 0; char ch = 'a'; while (i < (size-1)) { c[i] = ch; ch++; i++; } c[i] = '\0'; long *ptr = (long*)(&c); printf(" num chars:%2d\n", size); printf(" bytes 0-31: "); for (i=0; i <32; i++) { if (i < (size-1)) printf("%c", c[i]); else printf(" %x", (0x00ff & (int)(c[i]))); } if (size > 24) { printf("\n bytes 32-63:"); for (i=32; i <64; i++) { printf(" %x", (0x00ff & (int)(c[i]))); } } printf("\n"); } void mallocTesting() { int i; printf("\nTesting char mallocs\n"); for (i = 1; i <= 5; i++) chMallocTest(i); /* skipping 6..18 as they reveal nothing new, * showing 24-27 as they show the breakpoint * going from 24 byte request to 25 byte request */ for (i = 24; i <= 27; i++) chMallocTest(i); } void passingDefaults(long pre, FwdStr s, unionCombo u, long arr[], long post) { printf("\nParameter values and locations:\n"); printf(" long[-1] value:%ld, addr:%p\n", pre, mask((long*)(&pre))); printf(" s{0,1,2,3,4,5} addr:%p\n", mask((long*)(&s))); printf(" s.cFld value:%ld, addr:%p\n", s.cFld, mask((long*)(&(s.cFld)))); printf(" s.sFld value:%ld, addr:%p\n", s.sFld, mask((long*)(&(s.sFld)))); printf(" s.iFld value:%ld, addr:%p\n", s.iFld, mask((long*)(&(s.iFld)))); printf(" s.cFld2 value:%ld, addr:%p\n", s.cFld2, mask((long*)(&(s.cFld2)))); printf(" s.lFld value:%ld, addr:%p\n", s.lFld, mask((long*)(&(s.lFld)))); printf(" s.lFld2 value:%ld, addr:%p\n", s.lFld2, mask((long*)(&(s.lFld2)))); printf(" union[5] value:%ld, addr:%p\n", u.lFld, mask((long*)(&u))); printf(" array[12,10,9] value:%p, addr:%p\n", mask(arr), mask((long*)(&arr))); printf(" long[7] value:%ld, addr:%p\n", post, mask((long*)(&post))); } void instructions() { INSTR_YDEF: ; int y = 1; INSTR_XDEF: ; int x; INSTR_LOOP: for (x = 0; x < 3; x++) { INSTR_INLOOP: y = x; } INSTR_PRINTF1: printf("\nInstruction addresses:\n"); INSTR_PRINTF2: printf(" function: %p\n", instructions); printf(" nop/ydef/init:%p\n", &&INSTR_YDEF); printf(" nop/xdef: %p\n", &&INSTR_XDEF); printf(" loop: %p\n", &&INSTR_LOOP); printf(" in loop: %p\n", &&INSTR_INLOOP); printf(" printf1: %p\n", &&INSTR_PRINTF1); printf(" printf2: %p\n", &&INSTR_PRINTF2); printf(" return: %p\n", &&INSTR_RETURN); INSTR_RETURN: return; } void dataSizes() { printf("\nData type sizes\n"); printf(" char:%d, short:%d, int:%d, long:%d, float:%d, double:%d\n", sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(float), sizeof(double)); printf(" char*:%d, int*:%d, double*:%d, char**:%d\n", sizeof(char*), sizeof(int*), sizeof(double*), sizeof(char**)); printf(" FwdStruct:%d, RevStruct:%d\n", sizeof(FwdStr), sizeof(RevStr)); printf(" unionCombo:%d\n", sizeof(unionCombo)); printf("\nField alignment in structs\n"); FwdStr f; RevStr r; printf(" Fwd: char:%p, short:%p, int:%p, char:%p, long:%p, long:%p\n", mask((long*)(&(f.cFld))), mask((long*)(&(f.sFld))), mask((long*)(&(f.iFld))), mask((long*)(&(f.cFld2))), mask((long*)(&(f.lFld))), mask((long*)(&(f.lFld2)))); printf(" Rev: long:%p, long:%p, int:%p, short:%p, char:%p, char:%p\n", mask((long*)(&(r.lFld))), mask((long*)(&(r.lFld2))), mask((long*)(&(r.iFld))), mask((long*)(&(r.sFld))), mask((long*)(&(r.cFld))), mask((long*)(&(r.cFld2)))); } void dataAlign(char pre, char a, short b, int c, long d, long post) { char f; short g; int h; long i; printf("Fwd parameter addesses:\n"); printf(" char:%p, char:%p, short:%p, int:%p, long:%p, long:%p\n", mask((long*)(&pre)),mask((long*)(&a)), mask((long*)(&b)), mask((long*)(&c)), mask((long*)(&d)), mask((long*)(&post))); printf("Fwd local variable addesses:\n"); printf(" char:%p, short:%p, int:%p, long:%p\n", mask((long*)(&f)), mask((long*)(&g)), mask((long*)(&h)), mask((long*)(&i))); printf("\nUnion field locations:\n"); unionCombo u; u.dFld = 1.2825e2; printf(" double 1.2825e2 as raw hex %p\n", (long*)(u.lFld)); u.fFld = 1.2825e2; printf(" float 1.2825e2 as raw hex %p\n", (long*)(u.lFld)); u.lFld = 6; printf(" long 6 as raw hex %p\n", (long*)(u.lFld)); u.iFld = 6; printf(" int 6 as raw hex %p\n", (long*)(u.lFld)); u.sFld = 6; printf(" short 6 as raw hex %p\n", (long*)(u.lFld)); u.cFld = '0'; printf(" char '0' as raw hex %p\n", (long*)(u.lFld)); } void revAlign(long d, int c, short b, char a) { long pre; long i; int h; short g; char f; char post; printf("\nRev parameter addesses:\n"); printf(" long:%p, int:%p, short:%p, char:%p\n", mask((long*)(&d)), mask((long*)(&c)), mask((long*)(&b)), mask((long*)(&a))); printf("Rev local variable addesses:\n"); printf(" long:%p, long:%p, int:%p, short:%p, char:%p, char:%p\n", mask((long*)(&pre)),mask((long*)(&i)), mask((long*)(&h)), mask((long*)(&g)), mask((long*)(&f)), mask((long*)(&post))); } long* examineStack(long a, long b) { static long examineStackLocal = 7; long c = 3; long* ptr = &c; ptr++; printf("\nContents of addresses above first local (i.e. deeper in stack)\n"); printf(" 8 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 16 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 24 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 32 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 40 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 48 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); ptr++; printf(" 64 bytes above: addr(%p), content(%p)\n", mask(ptr), mask((long*)(*ptr))); long d = 4; long e; for (e = 100; e < 102; e++) { long f = 5; long g = 6; if (e == 100) { printf("\nAddresses of first for loop locals:\n"); printf(" e:%p, f:%p, g:%p\n", mask(&e), mask(&f), mask(&g)); } } long h = 7; long i = 8; long j; for (j = 200; j < 202; j++) { long k = 5; long l = 6; if (j == 200) { printf("Addresses of second for loop locals:\n"); printf(" j:%p, k:%p, l:%p\n", mask(&j), mask(&k), mask(&l)); } } printf("\nAddresses of examineStack parameters:\n a:%p, b:%p\n", mask(&a), mask(&b)); printf("\nAddresses of examineStack scope variables:\n c:%p, d:%p, h:%p, i:%p\n", mask(&c), mask(&d), mask(&h), mask(&i)); return &examineStackLocal; } int main(int argc, char *argv[]) { /* print raw data sizes */ dataSizes(); /* investigate alignment and padding */ revAlign(12, 5, 3, 'a'); dataAlign('-', 'a', 3, 5, 12, 25); /* investigate memory/stack organization */ long x = 0; long y = 1; long z = 2; long *p; printf("\nAddresses of parameters to main:\n"); printf(" argc:%p, argv:%p\n", mask((long*)(&argc)), mask((long*)(&argv))); printf("Addresses of locals to main:\n"); printf(" x:%p, y:%p, z:%p\n", mask(&x), mask(&y), mask(&z)); BEFORE: p = examineStack(x, y); AFTER: printf("\nFunction addresses\n main:%p, examineStack:%p\n", mask((long*)(main)), mask((long*)(examineStack))); printf("\nAddresses before/after function call:\n"); printf(" before:%p, after:%p\n", mask(&&BEFORE), mask(&&AFTER)); printf("\nAddresses of globals:\n"); printf(" globalx:%p, globaly:%p\n", mask(&globalx), mask(&globaly)); printf("Addresses of static locals:\n"); printf(" examineStackLocal:%p, maskLocal:%p\n", mask(p), mask(0)); /* parameter passing mechanisms */ unionCombo u; u.lFld = 5; FwdStr s = { 0, 1, 2, 3, 4, 5 }; long arr[3] = { 12, 10, 9 }; printf("\nAddresses of variables being passed as parameters:\n"); printf(" struct s:%p\n", mask((long*)(&s))); printf(" union u:%p\n", mask((long*)(&u))); printf(" array arr:%p\n", mask(arr)); passingDefaults(-1, s, u, arr, 7); /* investigate instruction layout */ instructions(); /* investigate heap */ mallocTesting(); freeTest(); return 0; } |
output |
Data type sizes char:1, short:2, int:4, long:8, float:4, double:8 char*:8, int*:8, double*:8, char**:8 FwdStruct:32, RevStruct:24 unionCombo:8 Field alignment in structs Fwd: char:0x3fc723b0, short:0x3fc723b2, int:0x3fc723b4, char:0x3fc723b8, long:0x3fc723c0, long:0x3fc723c8 Rev: long:0x3fc72390, long:0x3fc72398, int:0x3fc723a0, short:0x3fc723a4, char:0x3fc723a6, char:0x3fc723a7 Rev parameter addesses: long:0x3fc723a8, int:0x3fc723a4, short:0x3fc723a0, char:0x3fc7239c Rev local variable addesses: long:0x3fc723c8, long:0x3fc723c0, int:0x3fc723bc, short:0x3fc723ba, char:0x3fc723b9, char:0x3fc723b8 Fwd parameter addesses: char:0x3fc723ac, char:0x3fc723a8, short:0x3fc723a4, int:0x3fc723a0, long:0x3fc72398, long:0x3fc72390 Fwd local variable addesses: char:0x3fc723cf, short:0x3fc723cc, int:0x3fc723c8, long:0x3fc723c0 Union field locations: double 1.2825e2 as raw hex 0x4060080000000000 float 1.2825e2 as raw hex 0x4060080043004000 long 6 as raw hex 0x6 int 6 as raw hex 0x6 short 6 as raw hex 0x6 char '0' as raw hex 0x30 Addresses of parameters to main: argc:0x3fc7243c, argv:0x3fc72430 Addresses of locals to main: x:0x3fc724a0, y:0x3fc72498, z:0x3fc72490 Contents of addresses above first local (i.e. deeper in stack) 8 bytes above: addr(0x3fc723d8), content(0x3fc723d8) 16 bytes above: addr(0x3fc723e0), content(0x602ef0) 24 bytes above: addr(0x3fc723e8), content(0x3fc72498) 32 bytes above: addr(0x3fc723f0), content(0x3fc72490) 40 bytes above: addr(0x3fc723f8), content(0x3fc725a0) 48 bytes above: addr(0x3fc72400), content(0x3fc724c0) 64 bytes above: addr(0x3fc72408), content(0x4019e4) Addresses of first for loop locals: e:0x3fc723c0, f:0x3fc723a0, g:0x3fc72398 Addresses of second for loop locals: j:0x3fc723a8, k:0x3fc72390, l:0x3fc72388 Addresses of examineStack parameters: a:0x3fc72378, b:0x3fc72370 Addresses of examineStack scope variables: c:0x3fc723d0, d:0x3fc723c8, h:0x3fc723b8, i:0x3fc723b0 Function addresses main:0x4018ca, examineStack:0x40154b Addresses before/after function call: before:0x4019d1, after:0x4019e8 Addresses of globals: globalx:0x602ed8, globaly:0x602ee0 Addresses of static locals: examineStackLocal:0x602ee8, maskLocal:0x602ef0 Addresses of variables being passed as parameters: struct s:0x3fc72460 union u:0x3fc72480 array arr:0x3fc72440 Parameter values and locations: long[-1] value:-1, addr:0x3fc723e8 s{0,1,2,3,4,5} addr:0x3fc72410 s.cFld value:0, addr:0x3fc72410 s.sFld value:1, addr:0x3fc72412 s.iFld value:2, addr:0x3fc72414 s.cFld2 value:3, addr:0x3fc72418 s.lFld value:4, addr:0x3fc72420 s.lFld2 value:5, addr:0x3fc72428 union[5] value:5, addr:0x3fc723e0 array[12,10,9] value:0x3fc72440, addr:0x3fc723d8 long[7] value:7, addr:0x3fc723d0 Instruction addresses: function: 0x400fbc nop/ydef/init:0x400fc4 nop/xdef: 0x400fcb loop: 0x400fcb in loop: 0x400fd4 printf1: 0x400fe4 printf2: 0x400fee return: 0x40108f Testing char mallocs num chars: 1 bytes 0-31: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 e1 f 2 0 0 0 0 0 num chars: 2 bytes 0-31: a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 c1 f 2 0 0 0 0 0 num chars: 3 bytes 0-31: ab 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a1 f 2 0 0 0 0 0 num chars: 4 bytes 0-31: abc 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 f 2 0 0 0 0 0 num chars: 5 bytes 0-31: abcd 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 f 2 0 0 0 0 0 num chars:24 bytes 0-31: abcdefghijklmnopqrstuvw 0 41 f 2 0 0 0 0 0 num chars:25 bytes 0-31: abcdefghijklmnopqrstuvwx 0 0 0 0 0 0 0 0 bytes 32-63: 0 0 0 0 0 0 0 0 11 f 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 num chars:26 bytes 0-31: abcdefghijklmnopqrstuvwxy 0 0 0 0 0 0 0 bytes 32-63: 0 0 0 0 0 0 0 0 e1 e 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 num chars:27 bytes 0-31: abcdefghijklmnopqrstuvwxyz 0 0 0 0 0 0 bytes 32-63: 0 0 0 0 0 0 0 0 b1 e 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Allocated blocks: 1:0x1bc7160, 2:0x1bc71a0, 3:0x1bc71e0, 4:0x1bc7220, 5:0x1bc7260, 6:0x1bc72a0, 7:0x1bc72e0, 8:0x1bc7320, contents just prior to block 1: 41 block 1 contents as 8 longs:0:1:2:3:4:5:6:41 block 2 contents as 8 longs:0:1:2:3:4:5:6:41 block 3 contents as 8 longs:0:1:2:3:4:5:6:41 block 4 contents as 8 longs:0:1:2:3:4:5:6:41 block 5 contents as 8 longs:0:1:2:3:4:5:6:41 block 6 contents as 8 longs:0:1:2:3:4:5:6:41 block 7 contents as 8 longs:0:1:2:3:4:5:6:41 block 8 contents as 8 longs:0:1:2:3:4:5:6:20cb1 contents just after block 8: 0 Freeing blocks 1, 4, 5, 8 contents just prior to block 1: 41 block 1 contents as 8 longs:0:1:2:3:4:5:6:41 block 2 contents as 8 longs:0:1:2:3:4:5:6:41 block 3 contents as 8 longs:0:1:2:3:4:5:6:41 block 4 contents as 8 longs:1bc7150:1:2:3:4:5:6:41 block 5 contents as 8 longs:1bc7210:1:2:3:4:5:6:41 block 6 contents as 8 longs:0:1:2:3:4:5:6:41 block 7 contents as 8 longs:0:1:2:3:4:5:6:41 block 8 contents as 8 longs:1bc7250:1:2:3:4:5:6:20cb1 contents just after block 8: 0 Requesting replacements for 1, 4, 5, 8 Newly allocated blocks: 1:0x1bc7320, 4:0x1bc7260, 5:0x1bc7220, 8:0x1bc7160, contents just prior to block 1: 41 block 1 contents as 8 longs:1bc7250:1:2:3:4:5:6:20cb1 block 2 contents as 8 longs:0:1:2:3:4:5:6:41 block 3 contents as 8 longs:0:1:2:3:4:5:6:41 block 4 contents as 8 longs:1bc7210:1:2:3:4:5:6:41 block 5 contents as 8 longs:1bc7150:1:2:3:4:5:6:41 block 6 contents as 8 longs:0:1:2:3:4:5:6:41 block 7 contents as 8 longs:0:1:2:3:4:5:6:41 block 8 contents as 8 longs:0:1:2:3:4:5:6:41 contents just after block 8: 0 |