Free Machine code & execution lessons
Registers, addresses, and control flow
An instruction decodes into an operation over registers, immediates, memory, flags, and the program counter. Loads and stores move data across the register–memory boundary. Branches choose the next instruction according to values or flags. The ISA defines the result even when the processor overlaps many instructions internally.
An instruction such as load r0, [base + index×4] first computes an effective address. It then requests bytes from that address and interprets their width and signedness. Confusing the address with the stored value is the classic pointer mistake in another costume.
Calling conventions and stack frames
A calling convention assigns argument and return locations, classifies caller- and callee-saved registers, defines stack alignment, and specifies how control returns. A stack frame may hold saved state, local storage, spilled registers, and metadata. The compiler may omit or reshape it when the observable contract still holds.
A call records where execution should resume, often in a register or on the stack. Corrupting it can redirect control, which is why stack bounds, non-executable memory, address randomization, control-flow protections, and memory-safe languages matter. A software convention becomes a security boundary when data controls execution.
Symbols, relocation, linking, and loading
An object file contains machine code and data plus symbols, sections, and relocation records. A linker resolves cross-file references and lays out an executable or shared object. A loader maps segments, establishes process state, and performs required dynamic resolution before transferring control to an entry point.
Static linking copies selected library code into the executable, increasing independence and size. Dynamic linking resolves shared libraries at load or run time, enabling sharing and updates but adding deployment and compatibility dependencies. Neither is universally superior; the product’s update, footprint, security, and portability needs decide.
Pipelines, hazards, prediction, and precise state
Fetch, decode, execute, memory, and retirement can operate on different instructions simultaneously. Data hazards arise from dependencies; control hazards arise before a branch outcome is known; structural hazards compete for hardware. Forwarding, stalling, prediction, and speculation recover throughput while retirement preserves defined order and exceptions.
The processor predicts a path and executes ahead. If the guess is wrong, younger speculative instructions are discarded and fetching restarts at the correct target. The architectural state must look as if only the correct path executed, though microarchitectural traces can still matter for timing and security.