Gap between ELF sections of different permissions

2026-04-29

Stack Overflow: View Question

Tags: elf

Score: 0 | Views: 119

The asker noticed a gap in a simple ELF binary (the wc utility) between the .eh_frame section (read-execute) and .init_array section (read-write). The permissions boundary is reflected in the program headers, but there's a seemingly wasteful hole of unused bytes between them. Since memory protection only operates at page granularity, why does the linker insert this gap?

This is a deceptively deep question that touches on how the kernel's ELF loader, the linker, and virtual memory interact. The core issue is this: memory protection via mmap/mprotect works at page boundaries (typically 4 KiB, but 16 KiB on some ARM64 systems). When two adjacent sections have different permissions (RX vs RW), they must start on separate pages in virtual memory. Otherwise the kernel cannot enforce distinct protections on them.

The gap exists because of how PT_LOAD segments are mapped. The linker produces two separate loadable segments: one for executable code (RX) and one for writable data (RW). Each segment must be page-aligned in virtual memory. But here's the subtlety: to save space in the file, the linker uses a technique where segments can overlap on their file-page boundaries. The key field is p_align in the program header, and the rule is:

p_vaddr mod p_align == p_offset mod p_align

This means the virtual address and the file offset must be congruent modulo the alignment. The gap in the file isn't necessarily wasted disk space—it ensures that when the kernel maps each segment, the pages land correctly in memory with the right permissions. The actual file may be smaller than the virtual layout suggests, because the tail of the RX segment and the head of the RW segment can share a file page (mapped twice with different permissions).

There are several gotchas worth noting:

To investigate, run readelf -l wc and compare each PT_LOAD segment's p_offset, p_vaddr, p_filesz, and p_memsz. The gap in virtual addresses minus the gap in file offsets reveals exactly how much padding the page-alignment constraint introduces.

The challenge: Understanding why ELF binaries contain seemingly wasteful gaps requires grasping the interplay between page-granularity memory protection, segment alignment congruence rules, and modern linker security hardening defaults.

All newsletters