<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ember_seed</title>
    <description>The latest articles on DEV Community by ember_seed (@ember_seed).</description>
    <link>https://dev.to/ember_seed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3959374%2F90cc46fa-2aa9-4f4e-bf76-7fa7826c5a5d.png</url>
      <title>DEV Community: ember_seed</title>
      <link>https://dev.to/ember_seed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ember_seed"/>
    <language>en</language>
    <item>
      <title>A Deep Dive into the Memory Model</title>
      <dc:creator>ember_seed</dc:creator>
      <pubDate>Wed, 05 Aug 2026 15:31:46 +0000</pubDate>
      <link>https://dev.to/ember_seed/a-deep-dive-into-the-memory-model-2kk5</link>
      <guid>https://dev.to/ember_seed/a-deep-dive-into-the-memory-model-2kk5</guid>
      <description>&lt;p&gt;&lt;strong&gt;A Deep Dive into the Memory Model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;From Source Code to Machine Instructions&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A five-part journey through compilers, executables, virtual memory, and the CPU&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction: What Really Happens When Code Runs&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Consider a simple C program:&lt;/p&gt;

&lt;h1&gt;
  
  
  include &amp;lt;stdio.h&amp;gt;
&lt;/h1&gt;

&lt;p&gt;int value = 10;&lt;/p&gt;

&lt;p&gt;int add(int a, int b) {&lt;/p&gt;

&lt;p&gt;return a + b;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;int main() {&lt;/p&gt;

&lt;p&gt;int x = 5;&lt;/p&gt;

&lt;p&gt;int result = add(x, value);&lt;/p&gt;

&lt;p&gt;printf("%d", result);&lt;/p&gt;

&lt;p&gt;return 0;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Most programmers look at this and see only the visible outcome:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 + 10 = 15&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But behind that single printed number lies a much deeper story. Where does the data actually live? Who moves it from one place to another? How does the CPU find the instructions it needs to run? And how does the result finally make its way to the screen?&lt;/p&gt;

&lt;p&gt;Answering these questions means understanding a concept that many programmers use daily but rarely examine closely: the memory model.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Is a Memory Model, Really?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ask most developers what a "memory model" means, and the answer usually comes back in two words: stack and heap. That answer isn't wrong - it's just incomplete. A memory model is really a description of five things at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How data is stored&lt;/li&gt;
&lt;li&gt;How data is accessed&lt;/li&gt;
&lt;li&gt;How long data exists&lt;/li&gt;
&lt;li&gt;Who is responsible for managing that lifetime&lt;/li&gt;
&lt;li&gt;How different parts of a system communicate through memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A program never leaps directly from C source code into RAM. Several distinct layers sit between the two, each one translating the layer below it into something the layer above can reason about. This article walks through all of them, one at a time, and then reassembles the full picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Four Layers, at a Glance&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Layer&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What It Deals With&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Typical Concepts&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Programming Language&lt;/td&gt;
&lt;td&gt;Human-readable code&lt;/td&gt;
&lt;td&gt;scope, lifetime, ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Compiler&lt;/td&gt;
&lt;td&gt;Translating code to instructions&lt;/td&gt;
&lt;td&gt;registers, optimization, assembly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Operating System&lt;/td&gt;
&lt;td&gt;Running the program as a process&lt;/td&gt;
&lt;td&gt;virtual address space, .text/.data/.bss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. CPU Architecture&lt;/td&gt;
&lt;td&gt;Executing raw instructions&lt;/td&gt;
&lt;td&gt;registers, cache, pipeline, ALU&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rest of this article follows a single program down through each of these layers - from the moment a developer types int x = 10; to the moment a number appears on screen.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Part 1 - The Layers Between Code and Memory&lt;/strong&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Layer 1: The Programming Language&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At the C language level, a programmer thinks in terms of declarations like:&lt;/p&gt;

&lt;p&gt;int x = 10;&lt;/p&gt;

&lt;p&gt;malloc(...);&lt;/p&gt;

&lt;p&gt;static int counter;&lt;/p&gt;

&lt;p&gt;Underneath these simple lines, the language is quietly defining scope, lifetime, visibility, and ownership. Take this function:&lt;/p&gt;

&lt;p&gt;void function() {&lt;/p&gt;

&lt;p&gt;int x = 10;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;The variable x is local: its lifetime begins when the function starts and ends the moment it returns. Compare that to a global declaration:&lt;/p&gt;

&lt;p&gt;int global = 20;&lt;/p&gt;

&lt;p&gt;This variable lives for as long as the program runs. At this stage nobody is thinking about CPU registers or physical RAM - the only question that matters is: what is this data, and how long should it exist?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Layer 2: The Compiler&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The compiler is the bridge between what a human writes and what a machine can run. A line like:&lt;/p&gt;

&lt;p&gt;int x = 10;&lt;/p&gt;

&lt;p&gt;means nothing to the CPU on its own. The compiler has to decide whether that value belongs on the stack, whether it can live entirely inside a register, or whether it can be optimized away completely. An expression such as:&lt;/p&gt;

&lt;p&gt;int result = a + b;&lt;/p&gt;

&lt;p&gt;might be turned into assembly like:&lt;/p&gt;

&lt;p&gt;mov eax, a&lt;/p&gt;

&lt;p&gt;add eax, b&lt;/p&gt;

&lt;p&gt;At this point the very idea of a "variable" starts to dissolve. The CPU never sees anything called result - it only ever sees a sequence of MOVE, ADD, and STORE operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Layer 3: The Operating System&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Compilation produces an executable file, but a file sitting on disk isn't a running program yet. When the user launches it, the operating system kernel steps in and builds an entirely new environment for it, called a virtual address space. Inside that space the program sees familiar regions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Region&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.text&lt;/td&gt;
&lt;td&gt;Executable machine instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.data&lt;/td&gt;
&lt;td&gt;Initialized global variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.bss&lt;/td&gt;
&lt;td&gt;Uninitialized global variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heap&lt;/td&gt;
&lt;td&gt;Memory requested dynamically at runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;Local variables and function call frames&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The operating system gives every program the comfortable illusion that it owns all of memory by itself - it never has to think about other processes or the physical layout of RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Layer 4: The CPU Architecture&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At the very bottom, the CPU has no concept of variables, functions, objects, or C syntax. All it understands are raw machine instructions:&lt;/p&gt;

&lt;p&gt;mov eax, 5&lt;/p&gt;

&lt;p&gt;add eax, 10&lt;/p&gt;

&lt;p&gt;Internally, it relies on a handful of hardware components working together: registers, cache, the MMU, the instruction pipeline, the ALU, and various execution units. The CPU's entire job is to follow instructions and move data around - nothing more, nothing less.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Putting the Four Layers Together&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;C Source Code&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compiler&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Executable File&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operating System Loader&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Process + Virtual Memory&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Translation (MMU)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU Execution&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Machine Instructions&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Final Result&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The core idea to take away from this first layer of understanding is that memory is not simply a physical place where bytes sit. It's a stack of abstractions, each one built on top of the last:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Programming Language&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compiler&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operating System&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU Hardware&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each layer exists to hide complexity from the layer above it. That's precisely what lets a programmer write result = a + b; without ever thinking about registers, page tables, or electrical signals.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Part 2 - Executable Files, Loaders, and Process Memory Layout&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Part 1 established the high-level path a program takes: source code becomes an executable, and the operating system turns that executable into a running process. Now it's time to zoom in on the step that happens in between - what actually lives inside an executable file before the CPU ever touches it?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Is an Executable File?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Compiling a C program doesn't produce a running program - it produces a file containing everything the operating system needs to build one. On Windows, that file uses the PE (Portable Executable) format; on Linux, it typically uses ELF (Executable and Linkable Format). Either way, the format is far more than a wrapper around machine code. It also encodes where the code lives, where the data lives, which libraries are required, the program's entry point, the memory permissions each section needs, and instructions for how the OS should load everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Inside an Executable File&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Take this small program:&lt;/p&gt;

&lt;h1&gt;
  
  
  include &amp;lt;stdio.h&amp;gt;
&lt;/h1&gt;

&lt;p&gt;int global_initialized = 10;&lt;/p&gt;

&lt;p&gt;int global_uninitialized;&lt;/p&gt;

&lt;p&gt;int main() {&lt;/p&gt;

&lt;p&gt;int local = 5;&lt;/p&gt;

&lt;p&gt;printf("%d\n", local);&lt;/p&gt;

&lt;p&gt;return 0;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;Once compiled, its contents are split across distinct sections inside the file:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Header&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.text&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.data&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.bss&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Imports&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Other Data&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;.text - Program Instructions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The .text section holds machine instructions. A function like:&lt;/p&gt;

&lt;p&gt;int add(int a, int b) {&lt;/p&gt;

&lt;p&gt;return a + b;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;compiles down to something like:&lt;/p&gt;

&lt;p&gt;mov eax, ecx&lt;/p&gt;

&lt;p&gt;add eax, edx&lt;/p&gt;

&lt;p&gt;ret&lt;/p&gt;

&lt;p&gt;This section is marked readable and executable, but normally not writable - code isn't supposed to modify itself, and that restriction improves security, stability, and the ability to share memory safely between processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;.data - Initialized Global Data&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A variable declared with an initial value, such as:&lt;/p&gt;

&lt;p&gt;int counter = 100;&lt;/p&gt;

&lt;p&gt;is stored directly in .data, complete with its starting value already baked into the executable. When the program loads, that value is copied straight into process memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;.bss - Uninitialized Global Data&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A variable with no initial value:&lt;/p&gt;

&lt;p&gt;int total;&lt;/p&gt;

&lt;p&gt;doesn't need to occupy space in the file at all. Storing thousands of zero bytes on disk would be wasteful, so .bss simply records an instruction: reserve this much memory and fill it with zero. The loader creates the actual zeroed bytes only when the program starts.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Stack - Temporary Function Memory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The stack comes into existence when the process starts. For a function like:&lt;/p&gt;

&lt;p&gt;void function() {&lt;/p&gt;

&lt;p&gt;int x = 20;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;running it creates a small frame holding x = 20, and returning from it removes that frame automatically. The stack holds local variables, function parameters, return addresses, and other short-lived values - each function call gets its own stack frame, created and destroyed automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Heap - Dynamic Memory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The heap, by contrast, is used only when a program explicitly asks for memory while it's running:&lt;/p&gt;

&lt;p&gt;int *ptr = malloc(sizeof(int));&lt;/p&gt;

&lt;p&gt;Here the operating system hands over space from the heap on request. The key difference from the stack is lifetime management: stack memory comes and goes automatically, while heap memory stays allocated until the programmer explicitly releases it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;From Executable to Process&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A file sitting on disk is not the same thing as a process running in memory. When the user runs program.exe, the operating system kicks off a sequence of steps:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;User Starts Program&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kernel Creates Process&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loader Reads Executable&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maps Sections Into Virtual Memory&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Creates Page Tables&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sets Initial CPU State&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU Starts Execution&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Does the Loader Actually Do?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The loader doesn't simply copy the whole file into RAM. Instead, it builds a memory view of the executable, mapping each section of the file into the freshly created virtual address space:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stack&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Heap&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.bss&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.data&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.text&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Entry Point - Where Execution Begins&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every executable declares a starting address called its entry point - for instance, 0x140001000. The loader writes this address into the CPU's instruction pointer register:&lt;/p&gt;

&lt;p&gt;RIP = Entry Point&lt;/p&gt;

&lt;p&gt;The CPU now knows where its first instruction lives. But there's a catch: that address is still a virtual address, not a physical location in RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The First Connection Between OS and CPU&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this exact moment, two pieces are in place. The operating system has loaded the current process's page table address into the CR3 register, and the entry point address sits in RIP. With both ready, the CPU can begin execution - but it immediately faces a new problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Next Question&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How does the CPU convert the virtual address sitting in RIP into a real location in physical memory? Answering that requires virtual memory, page tables, and the MMU - the subject of Part 3.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Part 3 - Virtual Memory, Pages, Page Tables, CR3, and the MMU&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Part 2 left us at a critical juncture: the operating system had loaded the executable, created a process, and placed both an entry point in RIP and a page table address in CR3. The question left hanging was simple to ask but important to answer: RIP holds a virtual address - how does the CPU turn that into a real location in RAM? The answer lies in the virtual memory system.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Is Virtual Memory?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A common misconception is that virtual memory is simply another kind of RAM. It isn't. Virtual memory is an addressing system created by the operating system - it gives every process its own private view of memory, entirely independent of what any other process is doing.&lt;/p&gt;

&lt;p&gt;Two different programs can both reference the exact same virtual address, 0x140001000, while actually pointing at completely different physical memory underneath:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Virtual Address&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Physical Address&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Process A&lt;/td&gt;
&lt;td&gt;0x140001000&lt;/td&gt;
&lt;td&gt;0x80001000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process B&lt;/td&gt;
&lt;td&gt;0x140001000&lt;/td&gt;
&lt;td&gt;0x90001000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each process has its own private mapping, so identical virtual addresses can resolve to entirely different physical locations. This isolation is one of the most important security guarantees a modern operating system provides.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Virtual Address Space&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every process is handed its own virtual address space, typically laid out like this, from high addresses down to low:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stack&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Heap&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.bss&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.data&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.text&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Region&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Contents&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Typical Permissions&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.text&lt;/td&gt;
&lt;td&gt;mov eax, 5 / add eax, 10 - executable instructions&lt;/td&gt;
&lt;td&gt;Read, Execute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.data&lt;/td&gt;
&lt;td&gt;int counter = 100; - initialized globals&lt;/td&gt;
&lt;td&gt;Read, Write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.bss&lt;/td&gt;
&lt;td&gt;int value; - uninitialized globals, zero-filled&lt;/td&gt;
&lt;td&gt;Read, Write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heap&lt;/td&gt;
&lt;td&gt;malloc() memory, lifetime controlled by the programmer&lt;/td&gt;
&lt;td&gt;Read, Write&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stack&lt;/td&gt;
&lt;td&gt;Local variables and function call frames&lt;/td&gt;
&lt;td&gt;Read, Write&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Memory Is Divided Into Pages&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A virtual address space isn't one continuous block - it's carved up into small, fixed-size chunks called pages. A common page size is 4 KB, though other sizes exist depending on the architecture.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Page 0&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page 1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page 2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page 3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Physical Memory Is Divided Into Frames&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;RAM is split up the same way, into blocks called frames:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Frame 0&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frame 1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frame 2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Rule to Remember&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Page size always equals frame size. If a page is 4 KB, its corresponding frame must also be 4 KB - a virtual page has to fit exactly into a physical frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Page Table: The Translation Map&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Something has to connect virtual pages to physical frames - that something is the page table, maintained by the operating system for every process:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Virtual Page&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;→&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Physical Frame&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page 0&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page 1&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page 2&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In essence, a page table is a dictionary: whenever the program asks for a given virtual address, the table says exactly where the real, physical data lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where Does the CPU Find the Page Table?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is where the CR3 register comes in. CR3 holds the base address of the current process's page table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;CR3 Points To&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Process A&lt;/td&gt;
&lt;td&gt;Page Table A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process B&lt;/td&gt;
&lt;td&gt;Page Table B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When the scheduler switches which process is running, it also swaps the value in CR3 - instantly giving the CPU a completely different memory map to work from.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The MMU - Memory Management Unit&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The MMU is a hardware component built into the CPU whose entire job is translating virtual addresses into physical ones, automatically and on every memory access. The programmer never calls it directly; the operating system simply configures it, and it runs silently underneath everything.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;TLB&lt;/strong&gt; - The Missing Link Between &lt;strong&gt;MMU&lt;/strong&gt; and Page Tables&lt;/p&gt;

&lt;p&gt;Virtual memory provides isolation and flexibility, but it introduces a performance problem.&lt;/p&gt;

&lt;p&gt;Every memory access requires translating a virtual address into a physical address. If the &lt;strong&gt;CPU&lt;/strong&gt; had to walk the page table every single time, memory access would become much slower.&lt;/p&gt;

&lt;p&gt;To solve this problem, modern CPUs include a small and extremely fast cache called the Translation Lookaside Buffer (&lt;strong&gt;TLB&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;TLB&lt;/strong&gt; stores recently used virtual-to-physical address translations.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual Address
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Page Table
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Physical Address
&lt;/h3&gt;

&lt;p&gt;the &lt;strong&gt;CPU&lt;/strong&gt; first checks:&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual Address
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Physical Address
&lt;/h3&gt;

&lt;p&gt;If the translation exists in the &lt;strong&gt;TLB&lt;/strong&gt;, the &lt;strong&gt;CPU&lt;/strong&gt; can immediately continue.&lt;/p&gt;

&lt;p&gt;This is called a:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLB&lt;/strong&gt; Hit &lt;strong&gt;TLB&lt;/strong&gt; Miss&lt;/p&gt;

&lt;p&gt;If the translation is not found:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLB&lt;/strong&gt; Miss&lt;/p&gt;

&lt;p&gt;occurs.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;CPU&lt;/strong&gt; must perform a page table walk:&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual Address
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLB&lt;/strong&gt; Check&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Miss&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Page Table Hierarchy
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Physical Frame
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Update &lt;strong&gt;TLB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next access to the same memory location can now use the cached translation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real Memory Translation Path
&lt;/h3&gt;

&lt;p&gt;The complete process is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RIP&lt;/strong&gt; / Register&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Virtual Address
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;(found?)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Yes
|
↓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Physical Address
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No
|
↓
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Page Table
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;h3&gt;
  
  
  Physical Address
&lt;/h3&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;Cache&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RAM&lt;/strong&gt; Why &lt;strong&gt;TLB&lt;/strong&gt; Matters&lt;/p&gt;

&lt;p&gt;Without a &lt;strong&gt;TLB&lt;/strong&gt;, every instruction fetch and every data access would require additional page table lookups.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;TLB&lt;/strong&gt; allows virtual memory to keep its security and flexibility while avoiding the full cost of address translation on every access&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The First Instruction Fetch, Fully Traced&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With all the pieces now in place, we can trace exactly what happens when the loader sets RIP = 0x140001000 and the CPU asks for its first instruction:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;RIP (Virtual Address)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Table&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Physical Address&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache / RAM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instruction Fetch&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Common Misconception&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many people assume the physical address, once found, gets written back into RIP. It doesn't. RIP always continues to hold a virtual address - the translation happens internally, on the fly, inside the CPU, every single time memory is accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Complete Picture So Far&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Executable File&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Loader&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Virtual Address Space&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Table&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Physical Memory&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU Execution&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At this stage, the operating system has fully prepared the memory world, and the CPU has successfully located its first instruction. One large question still remains: once an instruction physically reaches the CPU, what happens to it from that point on?&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Part 4 - CPU Internals: Registers, Cache, and the Instruction Pipeline&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Part 3 followed an instruction all the way to the CPU's doorstep. Now it's time to go inside: what does the CPU actually do with an instruction once it arrives, and how does it turn that instruction into a computed result?&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The CPU Does Not Understand C Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The CPU has no concept of variables, functions, loops, or objects. All it ever sees are machine instructions. A line like:&lt;/p&gt;

&lt;p&gt;int result = 5 + 10;&lt;/p&gt;

&lt;p&gt;becomes assembly such as:&lt;/p&gt;

&lt;p&gt;mov eax, 5&lt;/p&gt;

&lt;p&gt;add eax, 10&lt;/p&gt;

&lt;p&gt;From the CPU's perspective, every program - no matter how complex - ultimately reduces to moving data, performing calculations, comparing values, and jumping to other instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Registers - The Fastest Memory There Is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Inside the CPU sit a small number of extremely fast storage locations called registers. RAM is large but comparatively slow; registers are tiny but blazingly fast, and the CPU relies on them to hold current data, addresses, intermediate results, and execution state. Unlike RAM, a register isn't external memory at all - it's physically part of the CPU itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;RIP - Instruction Pointer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RIP always holds the address of the next instruction to execute:&lt;/p&gt;

&lt;p&gt;RIP = 0x140001000&lt;/p&gt;

&lt;p&gt;Once that instruction finishes, RIP automatically advances to point at the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;General-Purpose Registers&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These hold everyday working data - RAX, RBX, RCX, RDX, RSI, RDI, and R8 through R15. A pair of instructions like:&lt;/p&gt;

&lt;p&gt;mov eax, 5&lt;/p&gt;

&lt;p&gt;add eax, 10&lt;/p&gt;

&lt;p&gt;simply means: set EAX to 5, then add 10 to it, leaving EAX holding 15.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;RSP - Stack Pointer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RSP always tracks the current top of the stack. Whenever a function like:&lt;/p&gt;

&lt;p&gt;int main() {&lt;/p&gt;

&lt;p&gt;int x = 10;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;runs, the CPU creates a stack frame, and RSP keeps track of exactly where that frame currently sits.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;RBP - Base Pointer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;RBP typically marks the beginning of the current stack frame, giving the compiler a stable reference point from which to access parameters and local variables:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stack Frame (High → Low)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pointer&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Return Address&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Variable&lt;/td&gt;
&lt;td&gt;← RBP: Frame Start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameters&lt;/td&gt;
&lt;td&gt;← RSP: Current Position&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;CR3 vs. the Execution Registers&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It's worth being precise about the difference in roles here. CR3 answers the question "which memory map should I use?" - it belongs entirely to address translation. RIP, RSP, RAX, and the rest belong to execution itself, answering questions like "which instruction runs next?", "where is my current stack?", and "what value am I working with right now?"&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Cache - Faster Than RAM&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even RAM is too slow to keep up with a modern CPU, which is why several layers of cache sit between the two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;CPU Registers&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;L1 Cache&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;L2 Cache&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;L3 Cache&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RAM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A cache stores both the raw data and the information needed to find it again quickly - for instance, an instruction cache entry might pair address 0x140001000 with the raw bytes 55 48 89 E5, while a data cache entry pairs address 0x5000 with the value 123.&lt;/p&gt;

&lt;p&gt;Without a cache, every request for data has to travel all the way out to RAM and back - a comparatively slow round trip. With a cache in place, most requests are satisfied much closer to the CPU, which is dramatically faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Instruction Pipeline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A CPU doesn't finish one instruction completely before starting the next - it overlaps several instructions at once, a technique known as pipelining. The classic five-stage pipeline looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Fetch&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decode&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execute&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write Back&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Fetch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The CPU retrieves the next instruction - say, add eax, ebx - from the instruction cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Decode&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The decoder figures out what the instruction actually means: the operation is ADD, the inputs are EAX and EBX, and the output goes back into EAX.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Execute&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The ALU performs the actual arithmetic - for example, 5 + 10 = 15.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Memory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If the instruction needs to read or write memory - as in mov eax, [address] - the CPU accesses cache first, falling back to RAM only if necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Write Back&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Finally, the result is written back into its destination register, ready for the next instruction to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Complete CPU Execution Path&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;RIP&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fetch Instruction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decode&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read Registers&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Execute in ALU / FPU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Access (if needed)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write Result Back&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where Does the Final Result Actually Go?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The CPU never shows anything to the user by itself. A call like printf("%d", result); has to travel through several more layers before anything appears on screen:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Program&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C Library&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Call&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Driver&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Output&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CPU calculates the answer. The operating system manages the resources needed to display it. The hardware produces the final visible effect. Each of the three plays a distinct, necessary role.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Part 5 - The Complete Journey: From C Code to CPU Result&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Parts 1 through 4 examined each layer in isolation: how C becomes machine instructions, how an executable file is structured, how the operating system builds a process, how virtual memory and page tables work, and how the CPU itself processes instructions through registers, cache, and its pipeline. It's time now to connect every piece into one continuous story, following a single program from the first line of code to the final number on screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Starting Point&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Consider this small program:&lt;/p&gt;

&lt;h1&gt;
  
  
  include &amp;lt;stdio.h&amp;gt;
&lt;/h1&gt;

&lt;p&gt;int global = 10;&lt;/p&gt;

&lt;p&gt;int add(int a, int b) {&lt;/p&gt;

&lt;p&gt;return a + b;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;int main() {&lt;/p&gt;

&lt;p&gt;int x = 5;&lt;/p&gt;

&lt;p&gt;int result = add(x, global);&lt;/p&gt;

&lt;p&gt;printf("%d\n", result);&lt;/p&gt;

&lt;p&gt;return 0;&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;At the source level this looks almost trivially simple: x is 5, global is 10, their sum is 15, and that number gets printed. But underneath that simplicity, thousands of individual operations take place across every layer discussed so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1 - Compilation&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Everything begins with compilation, which transforms human-readable C into machine instructions through a multi-stage pipeline:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Source Code&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Preprocessor&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compiler&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Assembly Code&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Assembler&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Object File&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Linker&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Executable File&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The result is a file - program.exe on Windows, or simply program on Linux - containing .text, .data, .bss, metadata, library references, and an entry point. At this point the program is still nothing more than a file sitting on disk; it isn't running yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2 - Starting the Program&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The moment the user launches the executable, control passes to the operating system kernel, which creates a process. A process is far more than the executable file itself - it bundles together a virtual address space, page tables, register state, system resources, and a full execution context.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3 - The Loader Builds the Memory Environment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The loader reads the executable and maps its sections into the new virtual address space:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stack&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Heap&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.bss&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.data&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;.text&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The instruction add eax, ebx lands in .text. The variable int global = 10; lands in .data. The stack and heap are prepared and left ready for use once execution begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4 - Creating Page Tables&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The process now has a virtual address space, but physical RAM lives somewhere else entirely, so the OS builds a page table connecting the two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Virtual Page&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;→&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Physical Frame&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page 0&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page 1&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page 2&lt;/td&gt;
&lt;td&gt;→&lt;/td&gt;
&lt;td&gt;Frame 13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The OS then writes this page table's address into CR3, so the CPU always knows exactly which memory map belongs to the process currently running.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5 - Starting CPU Execution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The loader sets RIP to the entry point - 0x140001000, for example - and the CPU immediately needs to fetch that first instruction. Translation kicks in right away:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;RIP (Virtual Address)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Table&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Physical Address&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache / RAM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The instruction successfully reaches the CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6 - The Instruction Pipeline Begins&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Take a simple instruction like mov eax, 5 and follow it through the pipeline:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stage&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What Happens&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fetch&lt;/td&gt;
&lt;td&gt;The instruction moves from the instruction cache into the CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decode&lt;/td&gt;
&lt;td&gt;The CPU identifies the operation (Move), destination (EAX), and value (5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute&lt;/td&gt;
&lt;td&gt;The execution unit performs EAX = 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write Back&lt;/td&gt;
&lt;td&gt;The result, 5, is stored in the EAX register&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7 - The Function Call and the Stack&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When result = add(x, global); executes, the CPU builds a new stack frame to hold everything the function call needs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Stack Frame (High → Low)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Return Address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameter b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parameter a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local Data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RSP tracks the current stack position throughout, while RBP marks the base of this particular frame - together they let the compiler generate code that reliably finds parameters and locals.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 8 - The Calculation Itself&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With everything in place, the CPU finally performs the arithmetic: two register values flow into the ALU, which computes 5 + 10 and stores the result, 15, back into a register.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 9 - Printing the Result&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The CPU has no idea what a screen is. Producing visible output means calling out through several more layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Application&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C Standard Library&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operating System API&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Call&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Driver&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Display Hardware&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The kernel communicates with the hardware, and only then does 15 finally appear on the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Complete Memory Model, End to End&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Developer&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C Source Code&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compiler&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Executable File&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Operating System Loader&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Virtual Address Space&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Page Table&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CR3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MMU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache / RAM&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CPU Registers&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instruction Pipeline&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ALU&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;↓&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Final Understanding&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The single most important idea in this entire journey is that a program is never executed directly from the file sitting on disk. It passes through layer after layer of abstraction, and each layer sees something completely different:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Layer&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;What It Sees&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Programmer&lt;/td&gt;
&lt;td&gt;result = a + b;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compiler&lt;/td&gt;
&lt;td&gt;Variables and instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operating System&lt;/td&gt;
&lt;td&gt;A process and its memory mappings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;An ADD instruction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware&lt;/td&gt;
&lt;td&gt;Electrical signals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every layer hides complexity from the one above it - and that hiding is exactly what allows modern computers to execute billions of instructions per second while programmers get to write simple, readable code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Understanding the memory model ultimately means understanding how programming languages, compilers, operating systems, memory management, CPU architecture, and hardware execution all connect into a single continuous chain. Once that connection clicks into place, entire fields open up more easily - debugging, reverse engineering, operating system development, performance optimization, and systems programming all become far less mysterious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;A program is not just code.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;It is a journey through multiple layers of abstraction until it becomes physical computation.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>c</category>
    </item>
    <item>
      <title>Why I Built a Scientific Calculator in Pure C for Terminal Environments</title>
      <dc:creator>ember_seed</dc:creator>
      <pubDate>Sat, 30 May 2026 04:53:44 +0000</pubDate>
      <link>https://dev.to/ember_seed/why-i-built-a-scientific-calculator-in-pure-c-for-terminal-environments-2a85</link>
      <guid>https://dev.to/ember_seed/why-i-built-a-scientific-calculator-in-pure-c-for-terminal-environments-2a85</guid>
      <description>&lt;p&gt;For most people, opening a calculator means launching a GUI application or typing a quick expression into Python.&lt;/p&gt;

&lt;p&gt;For me, neither felt ideal.&lt;/p&gt;

&lt;p&gt;A large part of my work happens inside terminals: remote servers, SSH sessions, minimal Linux installations, recovery environments, virtual machines, and development systems where a terminal is always available but a graphical environment is not guaranteed.&lt;/p&gt;

&lt;p&gt;I wanted a scientific calculator that felt native to that environment.&lt;/p&gt;

&lt;p&gt;Not a Python script.&lt;/p&gt;

&lt;p&gt;Not a desktop application.&lt;/p&gt;

&lt;p&gt;Not something that required package installation, runtime environments, or external dependencies.&lt;/p&gt;

&lt;p&gt;Just a single executable that could be compiled anywhere and run immediately.&lt;/p&gt;

&lt;p&gt;So I built one.&lt;/p&gt;

&lt;p&gt;Why Not Python?&lt;/p&gt;

&lt;p&gt;Before someone asks: Python is excellent.&lt;/p&gt;

&lt;p&gt;I use Python regularly and have no problem with it.&lt;/p&gt;

&lt;p&gt;The goal of this project was never to replace Python.&lt;/p&gt;

&lt;p&gt;The goal was to build a tool with different trade-offs.&lt;/p&gt;

&lt;p&gt;With Python, even a simple calculation requires starting an interpreter:&lt;/p&gt;

&lt;p&gt;python -c "print(2+2)"&lt;/p&gt;

&lt;p&gt;That is perfectly reasonable.&lt;/p&gt;

&lt;p&gt;But in terminal-centric workflows, I wanted something that behaves more like a traditional Unix utility:&lt;/p&gt;

&lt;p&gt;calculator&lt;/p&gt;

&lt;p&gt;Instant startup.&lt;/p&gt;

&lt;p&gt;No runtime.&lt;/p&gt;

&lt;p&gt;No dependency management.&lt;/p&gt;

&lt;p&gt;No interpreter.&lt;/p&gt;

&lt;p&gt;No virtual environments.&lt;/p&gt;

&lt;p&gt;Just a native executable.&lt;/p&gt;

&lt;p&gt;Why Terminal First?&lt;/p&gt;

&lt;p&gt;Modern software increasingly assumes graphical environments.&lt;/p&gt;

&lt;p&gt;Yet terminals remain one of the most important interfaces in computing.&lt;/p&gt;

&lt;p&gt;System administrators live in terminals.&lt;/p&gt;

&lt;p&gt;Embedded developers use terminals.&lt;/p&gt;

&lt;p&gt;Linux users spend hours inside terminals.&lt;/p&gt;

&lt;p&gt;SSH sessions are terminals.&lt;/p&gt;

&lt;p&gt;Containers are terminals.&lt;/p&gt;

&lt;p&gt;Rescue environments are terminals.&lt;/p&gt;

&lt;p&gt;Many scientific calculators either require a GUI or offer only basic arithmetic.&lt;/p&gt;

&lt;p&gt;I wanted something that remained entirely inside the command line while still providing advanced mathematical functionality.&lt;/p&gt;

&lt;p&gt;Features Beyond Basic Arithmetic&lt;/p&gt;

&lt;p&gt;The project started as a simple calculator.&lt;/p&gt;

&lt;p&gt;It gradually evolved into something closer to a lightweight mathematical toolkit.&lt;/p&gt;

&lt;p&gt;Expression Parsing&lt;/p&gt;

&lt;p&gt;The calculator supports full mathematical expressions:&lt;/p&gt;

&lt;p&gt;2+3*4&lt;br&gt;
sqrt(16)&lt;br&gt;
sin(pi/2)&lt;/p&gt;

&lt;p&gt;It also supports implicit multiplication:&lt;/p&gt;

&lt;p&gt;2pi&lt;br&gt;
3(2+4)&lt;br&gt;
(x+1)(x-1)&lt;/p&gt;

&lt;p&gt;which feels natural when entering mathematical expressions.&lt;/p&gt;

&lt;p&gt;Scientific Functions&lt;/p&gt;

&lt;p&gt;Built-in support includes:&lt;/p&gt;

&lt;p&gt;Trigonometric functions&lt;br&gt;
Inverse trigonometric functions&lt;br&gt;
Degree-based variants&lt;br&gt;
Logarithms&lt;br&gt;
Exponentials&lt;br&gt;
Roots&lt;br&gt;
Factorials&lt;br&gt;
Rounding functions&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;sin(pi/2)&lt;br&gt;
sind(90)&lt;br&gt;
sqrt(25)&lt;br&gt;
log2(1024)&lt;br&gt;
fact(5)&lt;br&gt;
Number Base Support&lt;/p&gt;

&lt;p&gt;Working close to hardware often means switching between number systems.&lt;/p&gt;

&lt;p&gt;The calculator supports:&lt;/p&gt;

&lt;p&gt;0b1010&lt;br&gt;
0o77&lt;br&gt;
0xFF&lt;/p&gt;

&lt;p&gt;as inputs and can convert values between bases.&lt;/p&gt;

&lt;p&gt;Equation Solving&lt;/p&gt;

&lt;p&gt;Instead of only evaluating expressions, the calculator can solve equations.&lt;/p&gt;

&lt;p&gt;Supported modes include:&lt;/p&gt;

&lt;p&gt;Quadratic equations&lt;br&gt;
Cubic equations&lt;br&gt;
General numerical root finding&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;x^2 - 2 = 0&lt;/p&gt;

&lt;p&gt;which converges to:&lt;/p&gt;

&lt;p&gt;1.414213562...&lt;/p&gt;

&lt;p&gt;using Newton-Raphson iteration.&lt;/p&gt;

&lt;p&gt;Numerical Differentiation&lt;/p&gt;

&lt;p&gt;Given any expression containing x, the calculator can estimate its derivative numerically.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;f(x) = x^2&lt;/p&gt;

&lt;p&gt;at:&lt;/p&gt;

&lt;p&gt;x = 2&lt;/p&gt;

&lt;p&gt;returns:&lt;/p&gt;

&lt;p&gt;f'(2) = 4&lt;br&gt;
ASCII Graph Plotting&lt;/p&gt;

&lt;p&gt;This is one of my favorite features.&lt;/p&gt;

&lt;p&gt;Graphing normally requires graphical libraries.&lt;/p&gt;

&lt;p&gt;Instead, this calculator renders graphs directly in the terminal using ASCII characters.&lt;/p&gt;

&lt;p&gt;No GUI.&lt;/p&gt;

&lt;p&gt;No plotting framework.&lt;/p&gt;

&lt;p&gt;Just text.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;y = x^2&lt;/p&gt;

&lt;p&gt;can be visualized directly inside a terminal window.&lt;/p&gt;

&lt;p&gt;Matrix Operations&lt;/p&gt;

&lt;p&gt;The calculator also includes support for 2×2 matrix operations:&lt;/p&gt;

&lt;p&gt;Addition&lt;br&gt;
Multiplication&lt;br&gt;
Determinant&lt;br&gt;
Inverse&lt;/p&gt;

&lt;p&gt;which makes it useful for basic linear algebra tasks.&lt;/p&gt;

&lt;p&gt;Why a Single File?&lt;/p&gt;

&lt;p&gt;One criticism I expect is:&lt;/p&gt;

&lt;p&gt;"Why is everything in one file?"&lt;/p&gt;

&lt;p&gt;Because simplicity was a design goal.&lt;/p&gt;

&lt;p&gt;This project is intentionally small enough that opening a single source file provides a complete view of the entire program.&lt;/p&gt;

&lt;p&gt;There is no build system.&lt;/p&gt;

&lt;p&gt;No project hierarchy.&lt;/p&gt;

&lt;p&gt;No dependency graph.&lt;/p&gt;

&lt;p&gt;No package manager.&lt;/p&gt;

&lt;p&gt;No generated code.&lt;/p&gt;

&lt;p&gt;A developer can open the source, scroll through it, understand it, modify it, and compile it.&lt;/p&gt;

&lt;p&gt;That simplicity has value.&lt;/p&gt;

&lt;p&gt;Especially for educational projects.&lt;/p&gt;

&lt;p&gt;Especially for C.&lt;/p&gt;

&lt;p&gt;What I Learned&lt;/p&gt;

&lt;p&gt;The most interesting part of this project wasn't writing mathematical functions.&lt;/p&gt;

&lt;p&gt;It was building the expression parser.&lt;/p&gt;

&lt;p&gt;Supporting features like:&lt;/p&gt;

&lt;p&gt;2pi&lt;br&gt;
3(2+4)&lt;br&gt;
root(8,3)&lt;br&gt;
logbase(100,10)&lt;/p&gt;

&lt;p&gt;required much more thought than I initially expected.&lt;/p&gt;

&lt;p&gt;The project also reinforced something I appreciate about C:&lt;/p&gt;

&lt;p&gt;For small system-oriented utilities, C remains remarkably effective.&lt;/p&gt;

&lt;p&gt;The language gives direct control, fast execution, minimal overhead, and broad portability.&lt;/p&gt;

&lt;p&gt;Future Plans&lt;/p&gt;

&lt;p&gt;There are still many things I'd like to improve:&lt;/p&gt;

&lt;p&gt;Better matrix support&lt;br&gt;
More graphing capabilities&lt;br&gt;
Additional numerical methods&lt;br&gt;
Persistent history&lt;br&gt;
Improved expression parsing&lt;/p&gt;

&lt;p&gt;But even in its current form, the calculator already serves the purpose that motivated the project:&lt;/p&gt;

&lt;p&gt;Providing a capable scientific calculator that feels at home in terminal environments.&lt;/p&gt;

&lt;p&gt;Repository&lt;/p&gt;

&lt;p&gt;If you're interested in terminal tools, C programming, parsers, or numerical methods, I'd love to hear your feedback and ideas for future improvements.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/EmberSeed" rel="noopener noreferrer"&gt;
        EmberSeed
      &lt;/a&gt; / &lt;a href="https://github.com/EmberSeed/ADVANCED-TERMINAL-CALCULATOR" rel="noopener noreferrer"&gt;
        ADVANCED-TERMINAL-CALCULATOR
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      **Advanced Terminal Calculator** – A powerful CLI scientific calculator with trig, logs, roots, base conversion, equation solver, differentiation, matrix ops, ASCII plotting, and history. No GUI, just pure math in your terminal.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🧮 Advanced Terminal Calculator&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A zero-dependency scientific calculator written in C.&lt;/p&gt;
&lt;p&gt;This project combines an expression parser, scientific functions, numerical methods, equation solving, graph plotting, and basic matrix operations into a single self-contained terminal application.&lt;/p&gt;
&lt;p&gt;The entire implementation is contained in a single source file and depends only on the C standard library and &lt;code&gt;libm&lt;/code&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Arithmetic &amp;amp; Expressions&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Supported operators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full operator precedence&lt;/li&gt;
&lt;li&gt;Parentheses&lt;/li&gt;
&lt;li&gt;Implicit multiplication&lt;/li&gt;
&lt;li&gt;Right-associative exponentiation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;2+3*4          -&amp;gt; 14
(2+3)*4        -&amp;gt; 20
2pi            -&amp;gt; 6.28318...
3(2+4)         -&amp;gt; 18
2^3^2          -&amp;gt; 512
10%3           -&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;2. Trigonometric Functions&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Radians:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;atan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Degrees:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sind&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cosd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asind&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acosd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;atand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;sin(pi/2)      -&amp;gt; 1
cos(0)         -&amp;gt; 1
tan(pi/4)      -&amp;gt; 1

sind(90)       -&amp;gt; 1
cosd(180)      -&amp;gt; -1
tand(45)       -&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;3. Logarithmic &amp;amp; Exponential Functions&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ln&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;logbase(x,base)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;ln(e)              -&amp;gt; 1&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/EmberSeed/ADVANCED-TERMINAL-CALCULATOR" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>c</category>
      <category>cli</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
