Instruction sets — study guide
The concept's fragments, read in order.
The words a CPU knows
A processor does not understand code in general — it understands one specific set of operations, encoded in one specific way, and nothing else. That set is the instruction set, and it is fixed in silicon. A chip that knows the x86 vocabulary and a chip that knows the ARM vocabulary are both computers, but they are not speaking the same language.
This matters the moment you try to move software between them. A program, compiled, is machine code written in one instruction set's encoding — and the other chip cannot read it. It works like two people who speak different native languages — instructions written for one are meaningless noise to the other, even though both can read: a set of instructions written for one processor is meaningless noise to the other, even though both run programs for a living.
That single fact is why a phone app and a desktop app are built differently, why a Raspberry Pi won't run a Windows .exe, and why "just copy the program over" so often fails. The rest of this concept is what an instruction set is, the two families you'll actually meet, and what to do when you need to cross between them.
The contract between software and hardware
An instruction set architecture — ISA — is the abstract contract a CPU offers to software: the exact set of instructions it will execute, the registers it makes available, and how each instruction is encoded as bits. It is the interface between everything above (compilers, operating systems, programs) and the physical circuitry below.
The contract is what lets the two sides be built by different people at different times. A compiler turns source code into machine code targeting an ISA, without knowing which particular chip will run it; a chip vendor builds silicon that honors the ISA, without knowing which programs will arrive. Any processor that implements the same ISA runs the same binaries — that shared promise is called binary compatibility, and it holds only within one ISA.
So the ISA is the seam the whole stack pivots on. Above it, software is written once for the instruction set; below it, hardware is free to change completely as long as it keeps decoding the same instructions. Cross to a different ISA and the contract — and the compatibility — is gone.
x86 and ARM
Two instruction-set families dominate today. x86 — and its 64-bit form x86-64 — comes from Intel and AMD and runs most desktops, laptops, and servers; it is the vocabulary the traditional PC world is written in. ARM — in its 64-bit form AArch64 — is the most widely used ISA family of all, sitting in nearly every phone, in Apple Silicon Macs, and in boards like the Raspberry Pi.
For years the split was clean: x86 owned the desk and the data center, ARM owned anything running on a battery. That line has blurred — Apple moved its Macs to ARM, ARM chips now run in servers, and Windows ships an ARM edition — but the two families remain distinct instruction sets with distinct encodings. A chip is built for one of them.
Which family a machine belongs to is the single most important compatibility fact about it, because it decides which binaries can run at all. It is also something you can read off your own computer in one command, which the lab at the end does.
Why a binary won't cross over
A compiled binary is not instructions in the abstract — it is a specific stream of bytes, and each ISA encodes its instructions into bytes differently. The same operation, "add these two registers," is one pattern of bits on x86 and a different pattern on ARM. A CPU's decoder is wired to read only its own ISA's patterns; hand it the other family's bytes and they decode to nonsense or to nothing at all.
That is the whole reason a program built for one architecture will not run on the other. It is not a policy or a missing setting — the processor physically cannot interpret instructions from a foreign instruction set. Binary compatibility exists only between chips that implement the same ISA, which is exactly why an x86-64 .exe is inert on an ARM Raspberry Pi.
The fix is never to copy the binary. It is to get bytes the target CPU can actually decode — which means building for that ISA, or translating to it, the subject of the next step.
Emulation, translation, and recompiling
There are three ways to run software on an ISA it wasn't built for. The cleanest is to recompile from source for the target: the same program, rebuilt into the new instruction set, running at full native speed — available only when you have the source. The second is a universal binary (Apple's term; also called a fat binary), a single file that packs machine code for more than one ISA so the right version runs on each.
The third is translation at run time: a layer reads the foreign binary's instructions and rewrites them into the host's as the program runs. Apple's Rosetta 2 does this to run x86-64 Mac apps on Apple Silicon, and tools like QEMU do it across many architectures. It works like a live interpreter translating a speech sentence by sentence — it works, but it is slower than someone who simply speaks the language — correct, but paying a tax in speed for every instruction it has to convert.
The trade-off ranks them naturally: recompiling is fastest but needs source, a universal binary is native but bigger, and translation runs almost anything at a performance cost. Knowing which one you're relying on explains a lot of "why is this app slower on the new machine?"
RISC and CISC, lightly
The two families grew from opposite design philosophies. x86 is the CISC tradition — a complex instruction set with many specialized instructions and a variable-length encoding, where a single instruction can do a lot. ARM is the RISC tradition — a reduced instruction set that implements mostly simple, frequently used operations, with a uniform fixed-width encoding that is easy to decode and pipeline.
The old story was that RISC is lean and efficient while CISC is powerful but power-hungry, and that framing still explains part of why ARM took over battery-powered devices. But the line has blurred in practice: modern x86 chips decode their complex instructions into small internal micro-operations and execute those in a RISC-like core, so under the hood the two approaches have largely converged.
The honest takeaway is that RISC-versus-CISC is more history than daily concern. What still bites you is not the philosophy but the encoding: the instruction sets are different, so the binaries are different, and that is the part you actually have to plan around.
Picking and building for the right chip
The instant you build on a small computer, the ISA stops being trivia. A self-driving RC car usually runs on an ARM board — a Raspberry Pi or similar — and every piece of software on it must be built for ARM. A binary you compiled on your x86 laptop will not run there, and neither will a desktop installer; you either rebuild for the board's architecture or pull a version already built for it.
It explains the everyday failures too. "This works on my machine but not on the server," "the Docker image won't start on the new Mac," "why is there no download for my chip?" — underneath each is an ISA mismatch, a binary meeting a processor that can't decode it. Container images and downloads are published per-architecture for exactly this reason.
So the habit worth keeping is small: before you install or ship, know the target chip's instruction set. Read your own machine's architecture, match the binary to it, and reach for translation only when you must — because the CPU only ever runs its own language.