From Source Code to Silicon: The Layers of a Computer

Concept

A computer is a stack of layers. Each layer hides the complexity of the one below and offers a simpler interface to the one above:

What it provides The program you write printf("speed = %d km/h\n", speed); Programming language + compiler

Portable source → machine code for one ISA GCC, Clang, rustc Libraries and runtime C library (printf, malloc) Operating system

Processes, memory, files, devices, security Linux, Windows, macOS, an RTOS Instruction Set Architecture (ISA)

The contract between software and hardware: instructions, registers, memory model x86-64, ARM64, RISC-V

One implementation of an ISA: pipeline, caches, predictors Intel Coffee Lake, ARM Cortex-A78 Gates, adders, registers, memories A 64-bit adder Circuits and devices Two ideas make this stack work:

Abstraction: each layer can be understood (and replaced) without knowing the details of the others — the same C program runs on Intel and AMD CPUs, which implement the same ISA very differently.

Interfaces: the ISA is the most important interface in computing: everything above it is software, everything below it is hardware.

Computer Architecture vs Organization Computer architecture is what a programmer can see: the instruction set, registers, data types, addressing modes, memory model.

Computer organization (microarchitecture) is how it is built: pipeline depth, cache sizes, number of execution units, branch predictor design.

The Von Neumann Model Almost every computer follows the stored-program (von Neumann) model: a CPU that executes instructions, a memory that holds both instructions and data, and I/O devices, connected by buses. The CPU repeatedly fetches an instruction from memory, decodes it and executes it (Module 6). Keeping programs in ordinary memory is what makes software possible: a compiler can write a program as data and the CPU can then run it.

What the Operating System Adds Without an OS, every program would have to drive the hardware itself. The OS provides:

Abstraction: files instead of disk sectors, processes instead of a bare CPU, virtual memory instead of physical RAM, sockets instead of network cards.

Resource management: sharing CPU time, memory and devices among many programs.

Protection: programs can't read each other's memory or touch devices directly; they must ask the kernel via system calls (Module 11).

Why It Matters

Performance problems, crashes and security bugs often live in the layers you don't normally see: a cache miss, a page fault, a system call, an integer that overflowed in hardware. Engineers who can move between layers debug faster and write faster code — and interviewers probe exactly this "full-stack" understanding.

Syntax

The standard tools for looking at each layer on Linux:

gcc -E file.c gcc -S file.c Assembly for your ISA gcc -c file.c

Object file (machine code, not yet linked) objdump -d prog Disassembled machine code File format, ISA, linking type strace./prog

System calls a program makes (Module 11)

Example

1.1 The C program 1.2 Every layer made visible The transcript compiles the program step by step, showing the preprocessed size, the assembly, the object file, the linked executable, the machine code and the running program.

#include <stdio.h>

int main(void)
{
    int speed = 120;
    printf("speed = %d km/h\n", speed);
    return 0;
}
$ gcc -E hello.c -o hello.i && wc -l hello.c hello.i
    8 hello.c
  746 hello.i
  754 total
$ gcc -S -O1 -fcf-protection=none hello.c -o hello.s && grep -v '^\s*\.' hello.s
main:
	subq	$8, %rsp
	movl	$120, %edx
	leaq	.LC0(%rip), %rsi
	movl	$1, %edi
	movl	$0, %eax
	call	__printf_chk@PLT
	movl	$0, %eax
	addq	$8, %rsp
	ret
$ gcc -c -O1 -fcf-protection=none hello.c -o hello.o && file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ gcc -O1 hello.o -o hello && file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=02b57fa28d565ebf8acf31cc26f83f3bfb31910c, for GNU/Linux 3.2.0, not stripped
$ ./hello
speed = 120 km/h
$ stat -c '%s bytes' hello
15888 bytes
$ objdump -d --no-show-raw-insn hello | grep -A8 '<main>:'
0000000000001139 <main>:
    1139:	sub    $0x8,%rsp
    113d:	mov    $0x78,%edx
    1142:	lea    0xebb(%rip),%rsi        # 2004 <_IO_stdin_used+0x4>
    1149:	mov    $0x1,%edi
    114e:	mov    $0x0,%eax
    1153:	call   1030 <__printf_chk@plt>
    1158:	mov    $0x0,%eax
    115d:	add    $0x8,%rsp
$ uname -srm
Linux 6.18.33.2-microsoft-standard-WSL2 
…

Expected Result

Reading the transcript from top to bottom walks down the layers:

The preprocessor expanded 8 lines into 746 — mostly declarations from <stdio.h>.

The compiler turned printf into a call of __printf_chk (a hardened printf variant) and passed 120 in register edx: x86-64 passes arguments in registers (Module 7).

file shows the formats: an ELF relocatable object, then a dynamically linked PIE executable that needs the loader /lib64/ld-linux-x86-64.so.2 (Module 9).

objdump shows the final machine code of main at address 0x1149; $0x78 is 120 in hexadecimal.

(The build ID hash is unique to each build.)

speed = 120 km/h

Common Mistakes

Thinking the CPU runs C code. It only runs machine instructions of its ISA; everything else is translated first.

Confusing architecture (the ISA contract) with organization (the implementation).

Assuming a program talks to hardware directly. On a general-purpose OS, user programs reach devices only through system calls.

Treating "64-bit" as a single property: it can describe register width, address width or the ISA.

Best Practices

Learn to read gcc -S and objdump -d output — it answers "what does my code really do?" definitively.

When something is slow or broken, ask which layer is responsible before changing code.

Keep portable code above the ISA layer; isolate architecture-specific code (intrinsics, assembly) in small modules.

Interview Relevance

High: "what happens when you run a program?", "what is an ISA?", "architecture vs organization?", "what does an operating system do?", "what is the von Neumann architecture?".

Practice Questions

Run gcc -S -O0 and -O2 on the same small program and compare the length of the assembly.

Use file on /bin/ls, a .o file and a shell script. What does each report?

List three things your program would have to do itself if there were no operating system.

Find the ISA of your own computer with uname -m and look up two microarchitectures that implement it.

Quick Quiz

Q1. (Multiple choice) Which layer is the contract between software and hardware? A) Operating system B) Instruction set architecture C) Microarchitecture D) Compiler Answer: B.

Q2. (True/False) Intel and AMD CPUs that both run x86-64 programs must have the same pipeline and cache design.

Answer: False. They share an ISA (architecture) but differ in microarchitecture (organization).

Q3. (Predict the output) In mov $0x78,%edx, what decimal value is loaded?

Answer: 120 (verified: it is the speed variable's value).

Q4. (Find the bug) "My program is faster on a new CPU with the same ISA, so the compiler must have changed the machine code."

Answer: Not necessarily: the same machine code runs faster on a better microarchitecture (deeper pipeline, bigger caches, better branch prediction).

Coding Challenge

Write a C program that prints the size in bits of a pointer, a long and an int on your machine, and whether the machine is little- or big-endian.

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint16_t probe = 0x0102;
    unsigned char first = *(unsigned char *)&probe;
    printf("pointer: %zu bits, long: %zu bits, int: %zu bits\n",
           sizeof(void *) * 8, sizeof(long) * 8, sizeof(int) * 8);
    printf("byte order: %s-endian\n", first == 0x02 ? "little" : "big");
    return 0;
}