CMPSC 311, Introduction to Systems Programming

Process Address Space


The address space of a process consists of the memory locations that can be referenced by the process or its threads.
The addresses you see in any program will fall into four general ranges of addresses, known as segments, There are other segments that you will learn about later.  

The text segment
The data segment
Shared libraries
The stack segment
The heap segment
Memory-mapped segments
The kernel area

A map of the process address space should show at least
There are two ways to gather information for this map - look at the output of programs like elfdump, which read an executable file, or query the program as it is running.  You can also get this information from an interactive debugger, but that's for later.  Comparing 32-bit and 64-bit address spaces is also a good idea (this is relatively easy on Solaris), and comparing different operating systems would also help.

The map of the stack should include main()'s function arguments and local variables, but since these locations are subject to change we shouldn't try to be too specific.  Obviously, once the program is compiled and loaded, its location would not change, but we'll see later that more parts can be added to the program as it runs.

So far, this is a logical or notional picture of how a program looks.  The goal here is really to see how the particular implementation of Solaris actually arranges memory, and whether the 32-bit and 64-bit versions differ in any organizational way.  Linux arranges memory in the same general way, but the addresses are different.

Here is some of what we need to test, to see if the "facts on the ground" agree with our hypotheses and the textbook examples.

The first round of tests uses Solaris on a Sparc processor in 32-bit mode.

Here is an example of elfdump's output, from a simple program.  The program itself produces no output.

Look for mention of the program's variables in the elfdump output using the grep command, and sort the results by address:

% grep var demo.0.elfdump | grep 0x | sort -k 2r
      [20]  0x00020e48 0x00000004  OBJT GLOB  D    0 .bss           global_var_2
      [63]  0x00020e48 0x00000004  OBJT GLOB  D    0 .bss           global_var_2
      [15]  0x00020e44 0x00000004  OBJT GLOB  D    0 .bss           global_var_0
      [58]  0x00020e44 0x00000004  OBJT GLOB  D    0 .bss           global_var_0
      [18]  0x00020e38 0x00000004  OBJT GLOB  D    0 .data          global_var_1
      [61]  0x00020e38 0x00000004  OBJT GLOB  D    0 .data          global_var_1
      [22]  0x00010cc0 0x00000004  OBJT GLOB  D    0 .rodata        global_var_3
      [65]  0x00010cc0 0x00000004  OBJT GLOB  D    0 .rodata        global_var_3

The second grep is used to filter out some symbol table information that has no address information.
Note that the local variables declared in main() do not appear in the elfdump output.

Now we will use some macros to help print addresses of variables at runtime.
We used the utility env with addresses.[34].c to control the environment strings in a new process, otherwise there is too much output.

The programs can be compiled (on Solaris) using 32-bit addresses or 64-bit addresses, in C89 or C99, and with Sun's compiler or the GNU compiler.  The compiler commands would be like

        cc  -m32 -o prog_c89_32 -v prog.c
        c99 -m32 -o prog_c99_32 -v prog.c
        cc  -m64 -o prog_c89_64 -v prog.c
        c99 -m64 -o prog_c99_64 -v prog.c

        gcc          -m32 -o prog_c89_32 -Wall -Wextra prog.c
        gcc -std=c99 -m32 -o prog_c99_32 -Wall -Wextra prog.c
        gcc          -m64 -o prog_c89_64 -Wall -Wextra prog.c
        gcc -std=c99 -m64 -o prog_c99_64 -Wall -Wextra prog.c

On Linux and Mac OS X, use the GCC compiler that is normally installed.

Here are the previous examples, but now with 64-bit addresses.

Last revised, 4 Feb. 2013