# Memory Layout Essentials: Understanding Program Memory
Have you ever wondered how your computer keeps track of everything running in memory? It's actually a bit like organising a massive library - every book (or in our case, every piece of data) needs its own spot on the shelf, and we need a system to find it quickly. Let's dive into how modern computers organise their memory "library"!
## The Big Picture
This isn't just some random arrangement - it's carefully designed to keep things running smoothly and securely. The way the stack and heap grow towards each other is pretty clever - it helps use memory efficiently while making it super obvious if they ever bump into each other (which would be bad news!).
Think of program memory like a tall building where different departments each get their own floor. Everyone knows where they need to go, and there's a method to the madness of how everything's arranged.
![[Pasted image 20250110100046.png]]
## Breaking Down Each Section
Let's take a closer look at each "floor" of our memory building, starting from the bottom.
### Text Segment (Code Segment)
This is where all your program's actual instructions live. Think of it as the master recipe book that tells your program precisely what to do:
- It's where the executable code hangs out.
- Usually read-only (because who wants their instructions getting scrambled?)
- Often shared between multiple copies of the same program (why waste space?)
- Typically, it starts at a fixed address (though ASLR might shake things up a bit - want to know more about ASLR, have a read about it in [[The Stack]].)
```c
// This code would end up in the text segment
int add(int a, int b) {
return a + b;
}
```
### Data Segment
Think of this as your program's storage room split into two sections:
#### Initialised Data (.data)
- Home to global and static variables that start with specific values
- Takes up space in your program file
- Gets loaded into memory when your program kicks off
```c
// These end up in the initialised data segment
static int counter = 42; // Static variable with initial value
char *message = "Hello World"; // Global string with initial value
```
#### Uninitialised Data (BSS)
- Where variables that start as zero live
- Cleverly doesn't waste space in your program file
- Gets set up fresh when your program starts running
```c
// These go in the BSS segment
static int uninitialised; // Static variable without initial value
char buffer[1024]; // Large buffer (automatically zeroed)
```
### Heap
> [!tip] Intrigued by how the heap actually manages all this dynamic memory? Hop over to [[The Heap]], where we dive deep into heap internals, common vulnerabilities, and why malware authors love targeting heap operations!
This is your program's flexible workspace - like a craft room where you can grab more table space when you need it:
- Grows upward in memory (reaching for the sky!)
- Managed by malloc/free in C or new/delete in C++
- Can grow or shrink as your program runs
- It can get a bit messy over time (like any workspace)
```c
// Example of heap allocation
char *dynamic_buffer = malloc(1024); // Allocates on the heap
// ... use the buffer ...
free(dynamic_buffer); // Returns memory to the heap
```
### Stack
We dove deep into this in [[The Stack]], but here's the quick version:
- Grows downward in memory (like building a tower of blocks from the top down)
- Handles function calls and local variables
- Cleans up after itself automatically (nice!)
- Super fast but has size limits
```c
void function() {
int local = 42; // Lives on the stack
char buffer[512]; // Also calls the stack home
} // Poof! Cleaned up automatically
```
## Memory Management Units (MMU)
>[!tip] If you're into malware analysis, understanding virtual memory is super important - lots of sneaky anti-debugging tricks mess around with memory permissions or try to spot when they're running in a virtual environment!
Think of the MMU as your memory's security guard and personal assistant rolled into one. It's constantly:
- Converting virtual addresses to physical ones (like a postal service for memory)
- Enforcing memory protection (making sure everything stays where it should)
- Handling memory hiccups and access violations
Here's a simplified look at how virtual addressing works:
<div style="font-family: monospace;">
<strong style="color: #6C83DB;">Virtual Address</strong><br>
+----------------+----------------+<br>
| <strong style="color: #A8B4F3;">Page Number</strong> | <strong style="color: #F2CF85;">Page Offset</strong> |<br>
+----------------+----------------+<br>
<span style="color: #DBB9F8;">↓</span> <span style="color: #DBB9F8;">↓</span><br>
<strong style="color: #EA7268;">Page Table</strong> <strong style="color: #EA7268;">Physical Memory</strong><br>
<span style="color: #DBB9F8;">↓</span> <span style="color: #DBB9F8;">↓</span><br>
+----------------+----------------+<br>
| <strong style="color: #A8B4F3;">Frame Number</strong> | <strong style="color: #F2CF85;">Frame Offset</strong> |<br>
+----------------+----------------+<br>
<strong style="color: #EA7268;">Physical Address</strong>
</div>
## Common Memory Issues
Let's look at some common memory problems you might encounter:
### Stack Overflow
When your stack grows too big:
```c
void recursive_disaster() {
char huge_buffer[1024*1024]; // Big local array
recursive_disaster(); // Recursion without exit
} // 💥 Stack overflow!
```
### Memory Leaks
When you forget to free heap memory:
```c
void leaky_function() {
char *buffer = malloc(1024);
// Oops, forgot to free(buffer)!
} // Memory leak - that space is now lost
```
### Use After Free
Using memory after returning it to the heap:
```c
char *ptr = malloc(10);
free(ptr);
ptr[0] = 'A'; // 💥 Accessing freed memory!
```
## Memory Protection Techniques
Modern systems use several techniques to protect memory:
1. **DEP (Data Execution Prevention)**
- Prevents code execution from data pages
- Marks memory regions as non-executable
2. **ASLR (Address Space Layout Randomisation)**
- Randomises memory layout each time the program runs
- Makes exploitation harder
3. **Stack Cookies/Canaries**
- Places magic values to detect stack corruption
- Checks values before function returns
## Practical Memory Analysis
When analysing programs or debugging memory issues, these tools are invaluable:
```bash
# Linux tools
$ pmap <pid> # View process memory map
$ /proc/<pid>/maps # Raw memory layout info
$ valgrind # Memory leak detection
# Windows tools
> VMMap # SysInternals memory mapper
> !address # WinDbg memory command
> !heap # WinDbg heap analysis
```
## Going Further
Want to dive deeper? Check out these related topics:
- [[CPU Registers Building Blocks]] - How CPU registers interact with memory
- [[The Stack]] - Deep dive into stack operations
- [[PE File Format Foundations]] - How programs are structured in memory
- [[Windows API Basics]] - How programs interact with system memory
Remember: understanding memory layout is crucial for both development and security analysis. Whether you're debugging a crash, analysing malware, or just trying to write more efficient code, knowing how memory works under the hood is invaluable!