Search code examples
cmemorypointerssparc

Memory Address of C Variables


this is my quiz question (warning, lengthy):

Given the following program, reorder the printf lines so that the values that are printed are sorted from smallest to largest if compiled and run on a Sun SPARC architecture. These lines print out the hex address of the different parts of the program (not the values assigned) with the printf() format specifier %p (pointer).

#include <stdio.h> 
#include <stdlib.h> 
int a = 420; 
void foo() { 
    int b; 
    /* 1 */ printf( "b --> %p\n", &b ); 
} 

int 
    main( int argc, char *argv[] ) { 
        int c; 
        int d = 42; 
        static int e; 
        /* 2 */ (void) printf( "foo() --> %p\n", foo ); 
        /* 3 */ (void) printf( "e --> %p\n", &e ); 
        /* 4 */ (void) printf( "malloc --> %p\n", malloc(420) ); 
        foo(); 
        /* 5 */ (void) printf( "d --> %p\n", &d ); 
        /* 6 */ (void) printf( "argv --> %p\n", &argv ); 
        /* 7 */ (void) printf( "a --> %p\n", &a ); 
        /* 8 */ (void) printf( "c --> %p\n", &c ); 
        /* 9 */ (void) printf( "argc --> %p\n", &argc ); 
    return 0; 
} 

I ran this program in C and got these printed values:

2  foo() --> 10594
3  e --> 2099c
4  malloc --> 209a8
1  b --> ffbff1b4
5  d --> ffbff228
6  argv --> ffbff288
7  a --> 20974
8  c --> ffbff22c
9  argc --> ffbff284

My question is well....why? I tried to do this by hand, remembering where each variable was saved (stack, BSS, data etc.), and tried to order them saying that this the order of variable, from low memory to high memory:

Is this how it should be organized from smallest to least?

LOW MEMORY - text (labels, function names):
2 - foo
data (initialized global/static vars):
7 - a
BSS ( initialized global/static vars:
3 - e
stack (local vars):
9 - argc
6 - argv[]
8 - c
5 - d
1 - b
4 - ptr returned by malloc
HIGH MEMORY

If it conflicts with the printed memory values, I don't know why, would someone mind explaining why? Thanks :) !


Solution

  • The only conflict is in the stack area.

    It is system dependent if the stack grows from higher to lower addresses (which is the usual case) or other way.

    On the bottom of the stack there is argc and argv, then c and d, and then b.

    As the arguments are pushed to the stack in the "wrong way", first argv is pushed, then argc, giving argc a smaller address. The same holds for c and d, obviously; but I think the compiler is free to choose where to put the local variables.

    b has the smallest address because it is pushed very late.

    Besides, the ptr returned by malloc() is not on the stack, but on the heap, which starts immediately after the BSS area.

    This makes the solution

    LOW MEMORY
    text (labels, function names):
    2 - foo
    data (initialized global/static vars):
    7 - a
    BSS (initialized global/static vars):
    3 - e
    heap:
    4 - ptr returned by malloc
    stack (local vars):
    1 - b
    5 - d
    8 - c
    9 - argc
    6 - argv[]
    HIGH MEMORY
    

    The reason for this unintuitive argument passing order is because there is an option for variable llength parameters. You might know the function printf(), where all these calls are valid:

    printf("Hello\n");
    printf("Hello %s\n", name);
    printf("Hello User #%d (%s)\n", nr, name);
    

    Only the caller knows the number of variables. The called function knows the top of the stack and wants to have a defined offset to the first arguments. So the only option is to put the first arguments to the top of the stack, thus starting pushing from last to first. Often, the data are not actually pushed, but the stack pointer is decreased manually and the memory reserved in this way filled afterwards.