Introduction
When a new process is created, the Kernel assigns it a structured Virtual Address Space. This Virtual Address Space is divided into segments.
To ensure consistent and clear terminology, this post focuses on ELF binaries on Linux x86-32.
Memory Segments
These segments are well-known and can be visually represented as the layout below.
File-backed vs Runtime-managed Segments
Memory segments fall into two categories:
File-backed: Code and global/static data that are set at build time. In the ELF file, these are organized into sections (like
.text,.data, and.bss) which are then mapped into memory segments by the loader.Runtime-managed: Other areas (stack, heap, and mappings like shared libraries) are managed dynamically while the process runs.
You can find every standard ELF section in the Linux Standard Base Specification.
The Layout
Below is a quick breakdown of each Segment, ordered from low addresses to high addresses.
Text Segment (.text)
The text segment contains your program’s executable machine code.
Example (x86-32 machine code bytes):
31 C0 C3
Disassembly:
xor eax, eax
ret
Data Segment (.data)
The data segment stores initialized global and static variables.
Example:
int g_counter = 1337; // .data
static char banner[] = "hi"; // .data
BSS Segment (.bss)
The BSS segment stores uninitialized (or zero-initialized) global and static variables.
Example:
int g_flag; // .bss
static char buf[4096]; // .bss
Heap Segment
The heap is where dynamic memory is allocated explicitly by the programmer (e.g., via malloc or new).
The Heap grows upward (towards higher addresses).
Example:
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof *p); // allocate space for one int on the heap
*p = 42; // write into the allocated heap memory
free(p); // release the heap memory
}
Memory Mapping Segment (Libraries)
This region (often called the Memory Mapping Segment) is located between the heap and the stack. It contains the Shared libraries (e.g., libc.so, ld-linux.so).
Stack Segment
The stack is a LIFO (Last-In First-Out) structure used for function calls (Stack Frames), local variables, and temporary values.
The Stack grows downward (towards lower addresses).
Example:
#include <stdio.h>
int main(void) {
int a = 0; // local variable (stack)
printf("%p\n", (void *)&a); // print the address of a
}
Arguments and Environment Variables Segment
At the very top of the user space (just before the kernel boundary), the OS places:
- Arguments (argv): Command line arguments.
- Environment (envp): Environment variables (e.g.,
PATH,HOME). - Auxiliary Vector: Info passed from the OS to the program loader.
Kernel Space Segment
User processes run in user space and cannot directly read or write addresses in the kernel space. This area is reserved for the kernel code, kernel data structures, and hardware drivers. Attempting to access this range from user mode triggers a Segmentation Fault.