memorywinapiprogram-structure

How does a program look in memory?


How is a program (e.g. C or C++) arranged in computer memory? I kind of know a little about segments, variables etc, but basically I have no solid understanding of the entire structure.

Since the in-memory structure may differ, let's assume a C++ console application on Windows.

Some pointers to what I'm after specifically:

Links to tutorial-like material and such is welcome, but please no reference-style material assuming knowledge of assembler etc.


Solution

  • Might this be what you are looking for:

    http://en.wikipedia.org/wiki/Portable_Executable

    The PE file format is the binary file structure of windows binaries (.exe, .dll etc). Basically, they are mapped into memory like that. More details are described here with an explanation how you yourself can take a look at the binary representation of loaded dlls in memory:

    http://msdn.microsoft.com/en-us/magazine/cc301805.aspx

    Edit:

    Now I understand that you want to learn how source code relates to the binary code in the PE file. That's a huge field.

    First, you have to understand the basics about computer architecture which will involve learning the general basics of assembly code. Any "Introduction to Computer Architecture" college course will do. Literature includes e.g. "John L. Hennessy and David A. Patterson. Computer Architecture: A Quantitative Approach" or "Andrew Tanenbaum, Structured Computer Organization".

    After reading this, you should understand what a stack is and its difference to the heap. What the stack-pointer and the base pointer are and what the return address is, how many registers there are etc.

    Once you've understood this, it is relatively easy to put the pieces together:

    A C++ object contains code and data, i.e., member variables. A class

    class SimpleClass {
         int m_nInteger;
         double m_fDouble;
    
         double SomeFunction() { return m_nInteger + m_fDouble; }
    }
    

    will be 4 + 8 consecutives bytes in memory. What happens when you do:

    SimpleClass c1;
    c1.m_nInteger = 1;
    c1.m_fDouble = 5.0;
    c1.SomeFunction();
    

    First, object c1 is created on the stack, i.e., the stack pointer esp is decreased by 12 bytes to make room. Then constant "1" is written to memory address esp-12 and constant "5.0" is written to esp-8.

    Then we call a function that means two things.

    1. The computer has to load the part of the binary PE file into memory that contains function SomeFunction(). SomeFunction will only be in memory once, no matter how many instances of SimpleClass you create.

    2. The computer has to execute function SomeFunction(). That means several things:

      1. Calling the function also implies passing all parameters, often this is done on the stack. SomeFunction has one (!) parameter, the this pointer, i.e., the pointer to the memory address on the stack where we have just written the values "1" and "5.0"
      2. Save the current program state, i.e., the current instruction address which is the code address that will be executed if SomeFunction returns. Calling a function means pushing the return address on the stack and setting the instruction pointer (register eip) to the address of the function SomeFunction.
      3. Inside function SomeFunction, the old stack is saved by storing the old base pointer (ebp) on the stack (push ebp) and making the stack pointer the new base pointer (mov ebp, esp).
      4. The actual binary code of SomeFunction is executed which will call the machine instruction that converts m_nInteger to a double and adds it to m_fDouble. m_nInteger and m_fDouble are found on the stack, at ebp - x bytes.
      5. The result of the addition is stored in a register and the function returns. That means the stack is discarded which means the stack pointer is set back to the base pointer. The base pointer is set back (next value on the stack) and then the instruction pointer is set to the return address (again next value on the stack). Now we're back in the original state but in some register lurks the result of the SomeFunction().

    I suggest, you build yourself such a simple example and step through the disassembly. In debug build the code will be easy to understand and Visual Studio displays variable names in the disassembly view. See what the registers esp, ebp and eip do, where in memory your object is allocated, where the code is etc.