Why can a CPU treat a program's own instructions as ordinary data — and what architecture makes that possible?
Because in the von Neumann (stored-program) model, code and data live in the same memory — so instructions are just bytes the CPU can also read and write.
* Von Neumann puts code and data in one shared memory, while Harvard keeps instruction and data memories separate. *
This raises a deceptively deep question: where are the instructions? The answer is that a program's machine code is loaded into main memory right alongside its data — when you run p24, its code and its data sit together in RAM. The CPU distinguishes the two only by how it uses an address — the Program Counter names bytes to fetch and execute, while a load/store names bytes to read or write as data. Nothing in the memory itself marks a byte as "code" or "data".
| Model | Instruction & data memory |
|---|---|
| Von Neumann (typical PCs) | One shared memory — flexible, but code and data can be confused |
| Harvard (many microcontrollers, DSPs) | Separate instruction and data memories — faster, safer, less flexible |
Why this matters for reverse engineering and security:
- You can point a disassembler at any bytes and it will decode them as instructions — which is exactly what
objdump -ddoes to a data-looking.ofile. - It's why a buffer overflow can inject "shellcode": attacker-supplied data becomes executable code if the CPU's PC is redirected into it. Defenses like NX/DEP exist precisely to re-impose a code/data boundary the hardware doesn't enforce by default.
Tip: "Stored-program" = the program is stored in memory, as data. That single idea is what makes computers general-purpose — and what makes them exploitable.
Go deeper:
Stored-program computer (Wikipedia) — the core idea that instructions live in the same memory as data, contrasted with the Harvard split.
Von Neumann architecture (Wikipedia) — the single shared bus/memory that makes code-as-data possible, plus the bottleneck it creates.