Chapter 27 Key Takeaways: Memory Management
-
Every pointer is a virtual address. The CPU translates it to a physical address on every memory access through a 4-level page table walk. The TLB caches recent translations to avoid the walk on repeated accesses.
-
CR3 holds the physical address of the PML4 table. Writing a new value to CR3 switches the active page table (and flushes most of the TLB), which is how the OS switches between process address spaces on a context switch.
-
The 4-level virtual address breakdown: bits 47:39 (PML4 index), 38:30 (PDP index), 29:21 (PD index), 20:12 (PT index), 11:0 (byte offset). Each index is 9 bits, selecting one of 512 entries in the corresponding table.
-
Each page table entry is 8 bytes. The key bits: P (present), R/W (writable), U/S (user-accessible), NX (no-execute). Bits 51:12 hold the physical page number. NX prevents shellcode injection by making data pages non-executable.
-
Page faults fire vector 14 with two outputs from the hardware: CR2 is set to the faulting virtual address; the CPU pushes an error code with P/W/U/R/I bits indicating the fault type. The kernel's #PF handler uses both to decide how to respond.
-
INVLPG [addr]must be called after modifying a PTE. The TLB caches translations. Without invalidating the TLB entry, the CPU will keep using the old (potentially invalid) translation even after the page table has been updated. -
Linux splits the 48-bit virtual address space into two canonical halves: user space (0x0 to 0x7FFF...) and kernel space (0xFFFF8000...). Addresses in the "canonical hole" (not sign-extended from bit 47) cause immediate #GP faults.
-
mmapis the general virtual memory interface: anonymous (MAP_ANONYMOUS) allocates zeroed pages from the OS; file-backed maps the file into the address space; MAP_SHARED creates mappings visible to multiple processes; MAP_PRIVATE uses copy-on-write semantics. -
forkshares physical pages via copy-on-write. Both parent and child initially point to the same physical frames, marked read-only in both page tables. The first write triggers a page fault, which allocates a new frame, copies the content, and updates the writing process's PTE. -
glibc malloc uses two different mechanisms:
brk/sbrkfor small allocations (extending the heap), andmmapfor large allocations (≥128KB). The heap has a chunk header (8 bytes) before each allocation storing the size — corrupting this header is the basis of heap exploitation. -
ASLR randomizes load addresses of heap, stack, and shared libraries on each execution. From assembly's perspective, this means code in PIE binaries must use RIP-relative addressing, and the GOT/PLT is required to resolve external symbol addresses at runtime.
-
The bitmap physical memory allocator uses one bit per 4KB frame.
BSF(Bit Scan Forward) finds the first free bit in O(n/64) time. It provides physical frames to the page fault handler and to explicit memory mapping operations. The free frame count and total frame count are tracked separately for O(1) stat queries. -
MAP_SHARED across fork shares physical pages permanently. Writes by either process are immediately visible to the other, with no kernel involvement. This is the fastest possible IPC mechanism — a write to shared memory costs the same as a write to private memory (~1 ns), compared to ~5000 ns for a pipe.