Programs see memory as an array of bytes from 0 to 264−1
(0x0000000000000000-0xFFFFFFFFFFFFFFFF), this is assuming a 64 bit architecture
The memory is organized into different sections, called “memory mappings”
Each section has different permissions, read/write/execute or a combination of them
Text - This is where the actual code is stored, the instructions that the program runs
Data - These are the initialized global variables
BSS - These are the uninitialized global variables. They are all set to 0 to start with
Heap - This is where memory is returned from when calling malloc or new. It grows upwards
Stack - This is where the local variables and return addresses are stored. It grows downwards
Dynamic Libraries - These are the libraries shared with other processes
Each dynamic library has its own text, data, and BSS
Each program has its own view of memory, they don’t all see the same section of memory
This is called the “address space” of the program
If a program modifies its address space, it won’t affect another one
// Program hello.cint a = 5; // Stored in data section int b[20]; // Stored in bss int main() { // Stored in text int x; // Stored in stack int *p =(int*) malloc(sizeof(int)); //In heap }
Between each memory section there may be gaps without a memory mapping
If a program attempts to access one of these gaps, the OS will send a SEGV signal that (by default) kills the program and dumps a core file
The core file contains the values of the variables, both global and local, at the time of the SEGV signal
The core file can be used for debugging “post mortem”, after the program has died