Process Address Space

Question: When we compile and execute a C program, how different parts of the program are mapped into memory?

Answer: There are three areas where the program gets mapped nto the memory. The parts are as follows.

Name
Interpretation
Code Segment
(also known as Text segment
Executatble statements of the program
Data Segment. Three categpries
  • Initialized Data
  • Zero-Initialized or BSS data
  • Heap
The respective interpretation of categories:
  • Statically allocated or global data that are initialized with non-zero values
  • Uninitialized data
  • Source of Dynamic memory allocation
The three categories are usually placed into a single contiguous area.
Stack Segment
Local variables of the scope.
Function parameters
Variables stores on the stack "disappear" when the function containing them returns,
the space on the stack is reused for subsequent function calls.

Here is a C program which will show the memory addresses of these segments.

   /*
   * ch03-memaddr.c --- Show address of code, data and stack sections, as well as BSS and dynamic memory.
  
This program prints the locations of the two functions main() and afunc() (lines 22–23). It then shows how the stack grows downward, letting afunc() (lines 51–63) print the address of successive instantiations of its local variable stack_var. (stack_var is purposely declared auto, to emphasize that it's on the stack.) It then shows the location of memory allocated by alloca() (lines 28–32). Finally it prints the locations of data and BSS variables (lines 34–38), and then of memory allocated directly through sbrk() (lines 40–48). Refernce: http://www.phptr.com/articles/article.asp?p=173438&seqNum=2

   */

  #include <stdio.h>
  #include <malloc.h>     /* for definition of ptrdiff_t on GLIBC */
  #include <unistd.h>
  #include <alloca.h>     /* for demonstration only */

  extern void afunc(void);    /* a function for showing stack growth */

  int bss_var;            /* auto init to 0, should be in BSS */
  int data_var = 42;      /* init to nonzero, should be data */

  int
  main(int argc, char **argv) /* arguments aren't used */
  {
      char *p, *b, *nb;

      printf("Text Locations:\n");
      printf("\tAddress of main: %p\n", main);
      printf("\tAddress of afunc: %p\n", afunc);

      printf("Stack Locations:\n");
      afunc();

      p = (char *) alloca(32);
      if (p != NULL) {
          printf("\tStart of alloca()'ed array: %p\n", p);
          printf("\tEnd of alloca()'ed array: %p\n", p + 31);
      }

      printf("Data Locations:\n");
      printf("\tAddress of data_var: %p\n", & data_var);

      printf("BSS Locations:\n");
      printf("\tAddress of bss_var: %p\n", & bss_var);

      b = sbrk((ptrdiff_t) 32);   /* grow address space */
      nb = sbrk((ptrdiff_t) 0);
      printf("Heap Locations:\n");
      printf("\tInitial end of heap: %p\n", b);
      printf("\tNew end of heap: %p\n", nb);

      b = sbrk((ptrdiff_t) -16);  /* shrink it */
      nb = sbrk((ptrdiff_t) 0);
      printf("\tFinal end of heap: %p\n", nb);

      /* infinite loop */
      while (1) {}
  }

  void
  afunc(void)
  {
      static int level = 0;       /* recursion level */
      auto int stack_var;        /* automatic variable, on stack */

      if (++level == 3)           /* avoid infinite recursion */
          return;

      printf("\tStack level %d: address of stack_var: %p\n",
              level, & stack_var);
      afunc();                    /* recursive call */
  }





The output of the above program is shown below with few additional details about the environment.

saha@stevens $ pwd
/home/csgrads/saha/unix/c

saha@stevens $ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linux
Thread model: posix
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-49)

saha@stevens $ gcc ch03-memaddr.c

saha@stevens $ ./a.out
Text Locations:
        Address of main: 0x8048378
        Address of afunc: 0x80484e4
Stack Locations:
        Stack level 1: address of stack_var: 0xbfff75b4
        Stack level 2: address of stack_var: 0xbfff75a4
        Start of alloca()'ed array: 0xbfff75a0
        End of alloca()'ed array: 0xbfff75bf
Data Locations:
        Address of data_var: 0x804976c
BSS Locations:
        Address of bss_var: 0x8049870
Heap Locations:
        Initial end of heap: 0x8b6d000
        New end of heap: 0x8b6d020
        Final end of heap: 0x8b6d010
-

While the above program is busy waiting in the infinite while loop, we do the following in a differnt shell of the same machine

saha@stevens $ ps -ef |grep a.out
saha      7646  2217 87 10:45 pts/1    00:00:05 ./a.out
saha      7649  2211  0 10:45 pts/0    00:00:00 grep a.out

saha@stevens $ pmap 7646
7646: a.out
Start         Size Perm Mapping
007d5000       84K r-xp /lib/ld-2.3.2.so
007ea000        4K rw-p /lib/ld-2.3.2.so
00d06000     1224K r-xp /lib/tls/libc-2.3.2.so
00e38000       12K rw-p /lib/tls/libc-2.3.2.so
00e3b000       12K rw-p [ anon ]
08048000        4K r-xp /home/csgrads/saha/unix/c/a.out
08049000        4K rw-p /home/csgrads/saha/unix/c/a.out
08467000        4K rw-p [ anon ]
b75e4000        4K rw-p [ anon ]
b75f6000        4K rw-p [ anon ]
bfff8000       32K rw-p [ stack ]
mapped: 1388K    writeable/private: 76K    shared: 0K

saha@stevens $


[Terminate the ./a.out running in ht previous shell.]

Using the output of a.out and pmap we can visualize the memory space as the following.

Memory address (hex)
Contents
Comments
0804 4000
Heap
Data segment -- Heap

0804 8000
     8378
     84E4

main()
afunc()
Code segment
0804 9000
     976C
     9870

data_var
bss_var
Data segment -- Initialized and BSS



BFFF C000
     CB40
     CB5F

start of alloca()'ed array
end of alloca()'ed array
Stack segment


If you can provide further insight into the process address mapping of a C program, please send me the details. saha _AT_ cs.ucr.edu