Understanding Linux Executable Files and Their Virtual Address Space
This article explains how Linux creates a new process with its own virtual address space, maps ELF executable segments to memory regions, describes the roles of code, data, and BSS sections, shows how to inspect mappings via /proc/pid/maps, and clarifies segment‑section relationships and loading details.
Process Creation and Virtual Address Space
When an executable is run, Linux creates a new process and allocates a fresh virtual address space. The kernel reads the ELF file header, establishes a mapping between the file’s segments and the process’s address space, and sets the CPU instruction pointer to the entry point.
ELF File Layout
An ELF executable contains binary instructions and data that have already been translated into machine code. Inside the file, distinct segments (code, data, BSS, etc.) are defined. The code segment holds executable instructions, the data segment stores initialized variables, and the BSS segment reserves space for uninitialized variables.
32‑bit and 64‑bit Virtual Address Spaces
Inspecting the Process Layout via /proc
The virtual memory areas (VMAs) of a process can be examined with: cat /proc/pid/maps Each line of the output corresponds to a VMA described by the vm_area_struct structure, which includes vm_start and vm_end addresses and permission flags.
Segment Permissions
The first three VMAs usually correspond to the ELF file’s loadable segments. Their permissions differ:
Read‑execute (code segment)
Read‑write (data and BSS segments)
Read‑only (read‑only data)
Segments vs. Sections
ELF distinguishes between segments (used by the loader) and sections (used by the linker). The readelf -S name.elf command shows the section header table, while readelf -l name.elf displays the program header table containing segment information.
Loading Details and BSS Handling
Only two LOAD‑type segments need to be mapped; other segments like NOTE or GNU_STACK serve auxiliary purposes. The FileSiz field gives the size of the segment in the ELF file, while MemSiz shows the size in memory. The difference often accounts for the BSS area, which is zero‑filled at runtime and does not have a separate LOAD segment.
The BSS size can be observed as a 0x20 (32‑byte) increase in MemSiz compared to FileSiz. This extra space is automatically zero‑initialized, which explains why uninitialized global or static variables in C appear as zero.
Verification Example
A small program that prints the addresses of global and static variables confirms that the BSS region follows the data segment in memory.
Overall, ELF segments provide the execution view of a binary, while sections represent the linking view. The loader maps segments (and thus VMAs) based on their permissions, consolidating sections with similar attributes to reduce fragmentation and simplify memory management.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
