Process Memory Mapping in C
When a C program runs, its memory is divided into distinct segments, each serving a specific purpose. This layout is called the process memory map. Understanding this is critical in embedded systems, where:
- RAM is limited
- Memory placement is often controlled manually
- Bugs like stack overflow or memory corruption are common
Typical Memory Layout
+------------------------+ High Address
| Stack |
|------------------------|
| Heap |
|------------------------|
| Uninitialized Data | (.bss)
|------------------------|
| Initialized Data | (.data)
|------------------------|
| Read-Only Data | (.rodata)
|------------------------|
| Code (Text) | (.text)
+------------------------+ Low Address
Memory Segments
1. Code Segment
Contains compiled machine instructions. Includes functions and executable code. Typically read-only.
- Embedded Insight: Stored in Flash/ROM; cannot be modified at runtime.
2. Read-Only Data
Contains string literals ("Hello") and const global variables.
- Example:
const int max_val = 100; - Embedded Insight: Stored in Flash; saves RAM.
3. Initialized Data Segment
Stores global and static variables with initial values.
- Example:C
int g = 10; static int s = 5; - Key Points: Stored in RAM; initial values copied from Flash at startup.
4. Uninitialized Data Segment
Stores global and static variables without initialization.
- Example:C
int g_uninit; static int s_uninit; - Key Points: Automatically initialized to 0; does NOT take space in program file (efficient).
5. Heap
Used for dynamic memory allocation (malloc(), calloc(), and free()).
- Characteristics: Grows upward; manually managed.
- Embedded Insight: Often avoided due to fragmentation and unpredictability.
6. Stack
Stores local variables, function parameters, and return addresses.
- Characteristics: Grows downward; automatically managed.
- Embedded Insight: Limited size → risk of overflow; avoid deep recursion.
Memory Mapping in Embedded Systems
| Segment | Location |
| .text | Flash |
| .rodata | Flash |
| .data | RAM |
| .bss | RAM |
| Heap | RAM |
| Stack | RAM |
Example Program to Visualize Memory Segments
C
<stdio.h> <stdlib.h>// Global variablesint global_init = 100; // .dataint global_uninit; // .bssconst int global_const = 200; // .rodatavoid demo_function(){ int local_var = 10; // stack int *heap_var = (int*)malloc(sizeof(int)); // heap *heap_var = 50; printf("\nInside demo_function:\n"); printf("Address of local_var (stack): %p\n", &local_var); printf("Address of heap_var (heap): %p\n", heap_var); free(heap_var);}int main(){ static int static_var = 300; // .data printf("Process Memory Mapping Demo\n\n"); printf("Address of main (code/text): %p\n", main); printf("Address of demo_function (text): %p\n", demo_function); printf("\nGlobal / Static Segments:\n"); printf("global_init (.data): %p\n", &global_init); printf("global_uninit (.bss): %p\n", &global_uninit); printf("global_const (.rodata):%p\n", &global_const); printf("static_var (.data): %p\n", &static_var); demo_function(); return 0;}
Sample Output (Addresses Vary)
Process Memory Mapping DemoAddress of main (code/text): 0x4005d0Address of demo_function (text): 0x400590Global / Static Segments:global_init (.data): 0x601040global_uninit (.bss): 0x601050global_const (.rodata): 0x4006a0static_var (.data): 0x601060Inside demo_function:Address of local_var (stack): 0x7ffc1234Address of heap_var (heap): 0x602010
Key Observations
- Code & constants → lower memory (Flash)
- Globals → middle region
- Heap grows upward
- Stack grows downward
- Heap & Stack may collide → crash
Common Issues
- Stack Overflow: Too many local variables or deep recursion.
- Memory Leak (Heap): Forgetting
free(). - Fragmentation: Frequent
malloc/freecycles.
A Comparison of Execution Across Multiple Environments
| Concept | Bare Metal | RTOS | Linux (GPOS) |
| Execution Model | Single main() loop (superloop) or interrupt-driven | Multiple tasks/threads managed by scheduler | Multiple processes + threads managed by kernel |
| Stack | One global stack | One stack per task | One stack per thread (user + kernel stacks) |
| Scheduling | Manual (you control flow) | Priority-based, often preemptive real-time | Complex scheduler (CFS), fairness + throughput |
| Context Switch | Not applicable (unless interrupts) | Save/restore registers + switch stack pointer | Full context switch: registers, MMU state, address space |
| Heap | Optional, often avoided or simple allocator | RTOS-managed, thread-safe heap APIs | Fully managed (glibc), virtual memory backed |
| Isolation | None | None (tasks share memory) | Strong isolation via virtual memory (MMU) |