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

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:Cint 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:Cint 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

SegmentLocation
.textFlash
.rodataFlash
.dataRAM
.bssRAM
HeapRAM
StackRAM

Example Program to Visualize Memory Segments

C

#include <stdio.h>
#include <stdlib.h>
// Global variables
int global_init = 100; // .data
int global_uninit; // .bss
const int global_const = 200; // .rodata
void 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 Demo
Address of main (code/text): 0x4005d0
Address of demo_function (text): 0x400590
Global / Static Segments:
global_init (.data): 0x601040
global_uninit (.bss): 0x601050
global_const (.rodata): 0x4006a0
static_var (.data): 0x601060
Inside 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 or 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)