C Programming

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 (.text)

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 (.rodata)

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 (.data)
  • Stores global and static variables with initial values
Example
int g = 10;
static int s = 5;
Key Points
  • Stored in RAM
  • Initial values copied from Flash at startup
4. Uninitialized Data Segment (.bss)

Stores global and static variables without initialization

Example
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

Functions: malloc() calloc() and free()

Characteristics

Grows upward; Managed manually

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

SegmentLocation
.textFlash
.rodataFlash
.dataRAM
.bssRAM
HeapRAM
StackRAM

Example Program to Visualize Memory Segments

#include <stdio.h>
#include <stdlib.h>// Global variables
int global_init = 100; // .data
int 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):        0x4005d0
Address of demo_function (text): 0x400590Global / Static Segments:
global_init (.data): 0x601040
global_uninit (.bss): 0x601050
global_const (.rodata): 0x4006a0
static_var (.data): 0x601060Inside demo_function:
Address of local_var (stack): 0x7ffc1234
Address 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

1. Stack Overflow
  • Too many local variables
  • Deep recursion
2. Memory Leak (Heap)
  • Forgetting free()
3. Fragmentation
  • Frequent malloc/free cycles

A comparison of execution across multiple environments

ConceptBare MetalRTOSLinux (GPOS)
Execution ModelSingle main() loop (superloop) or interrupt-drivenMultiple tasks/threads managed by schedulerMultiple processes + threads managed by kernel
StackOne global stackOne stack per taskOne stack per thread (user + kernel stacks)
SchedulingManual (you control flow)Priority-based, often preemptive real-timeComplex scheduler (CFS), fairness + throughput
Context SwitchNot applicable (unless interrupts)Save/restore registers + switch stack pointerFull context switch: registers, MMU state, address space
HeapOptional, often avoided or simple allocatorRTOS-managed, thread-safe heap APIsFully managed (glibc), virtual memory backed
IsolationNoneNone (tasks share memory)Strong isolation via virtual memory (MMU)