Why? Memory Structure 101

Kernel organizes memory in pages.

  • Typically 4096 bytes.

Processes operate in a Virtual Memory Space.

  • Mapped to real pages, which can be in RAM or Swapped.

Kernel splits program in several segments.

  • Increases security.

    • segment based permissions.

  • Increases performance.

    • some are dynamic: invalidated when program terminates.

    • some are static: can be retained, speed repeated startup.

Memory Structure

  • SS: Local variables and execution flow

  • Shared Libraries: .so/dlls loaded.

    • Addresses are shared between programs.

  • Heap: memory allocated with malloc/new.

  • BSS: Global Variables.

  • Data: Constants.

  • Code: Actual instructions.

mem.c

Simple program showing the memory map of itself.

Features:

  • Prints the address of objects of different types.

    • Argument.

    • Dynamic memory with malloc.

    • Global Variable.

    • Constant.

    • Function

  • Prints the memory maps as exposed in /proc/self/maps.

  • Creates a recursive function and prints the address of local variables.

  • Crashes with a Stack Overflow.

Stack organization

Stack is organized by frames, one for each function call.

  • Memory reserved for the function to use as it requires.

Each stack frame stores:

  • Return Information.

  • Local Variables.

  • Arguments to following functions (x32: all, x64: +5th).

Return information has 2 major objectives.

  • Chaining frames as new functions are called.

  • Return to the next instruction after the function ends.

Frame chaining.

  • When a function is called, the address of the current stack frame (Register RBP in x64) is push to the frame.

  • When the function ends, RBP is popped.

    • Caller function has it’s frame restored.

Function chaining

  • When a function is called, the address of the next instruction is push to the stack (RIP register).

  • When a function ends, that address is popped.

    • Execution resumes at the caller function.

mem_local.c

Prints the address to several variables.

  • Local variables declared in the main function.

  • Arguments passed to the foo function.

  • Local variables in the foo function.

main
argc : 0x7fffd6baeddc
argv : 0x7fffd6baeed8

foo
a       : 0x7fffd6baed8c
local_a : 0x7fffd6baed9b
buffer  : 0x7fffd6baeda0
local_b : 0x7fffd6baed9c
char foo(int a,){
    char local_a = 3;
    char buffer[16];
    int local_b = 5;

    printf(“%p\n”,&a);
    printf(“%p\n”,&local_a);
    printf(“%p\n”,&buffer);
    printf(“%p\n”,&local_b);
    
    buffer[0] = local_a;
    return buffer[0];
}

int main(int argc, char* argv[]){
    printf(“%p\n”, &argc);
    printf(“%p\n”, argv);
 
    return foo(argc);
}

Stack frame grows from higher addresses to lower addresses.

  • Main has variables at 0xbaedb.

  • Foo has variables at 0xbaed6-8.

Declaration order doesn’t matter!

Compiler will place variables are he seems adequate.

  • Will keep information aligned.

  • May create empty spaces.

  • May deploy additional protection mechanisms (canaries).

mem.c

  1. Until evolution: a limit imposed by the SO is reached.

  2. Until vital memory is overwritten.

Last updated