Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Assembly (x86-64, AArch64, RISC-V)  Module 1 – Start here: what assembly is and how to run it

What assembly language is and why it matters

Assembly language is the human-readable spelling of a processor's instructions on x86-64, AArch64 and RISC-V, with recorded runs and cited manuals.

  • Beginner
  • 10 minutes
  • Examples run with Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 10 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Explain how machine code, assembly language, assemblers and disassemblers relate
  • Name the three ISAs this track teaches and where each one runs
  • Describe what the track records for every example, from command to exit status
What you’ll learn

What you will learn

  • Explain how machine code, assembly language, assemblers and disassemblers relate
  • Name the three ISAs this track teaches and where each one runs
  • Describe what the track records for every example, from command to exit status
On this page

Every program a processor runs is a stream of bytes, called machine code. Assembly language is the human-readable spelling of those bytes: one line names one instruction, and an assembler translates each name into the opcode it stands for. Reading those names matters when a compiler’s output has to be checked, when a crash dump arrives without any source, when a loop runs slower than it should, when a security hardening claim must be verified, or when a bootloader or a driver has no higher-level language to hide inside.

This track teaches assembly for the three instruction set architectures that run most of the computing happening today: x86-64 on PCs and servers, AArch64 on phones and Apple silicon, and RISC-V on open and emerging hardware. Every program on every page is assembled, linked and run on a pinned toolchain, and the recording of that run — the exact command, the output and the exit status — is saved beside the lesson.

From text to bytes a processor can run

Open the lesson’s AArch64 program first: three lines of text in aarch64_exit42.s. mov w0, #42 puts the number 42 into register w0, ret returns to whoever called the function, and the label _main names the entry point the linker looks for on macOS. Each line is one instruction, and the three together are the function the processor runs.

The assembly language: A human-readable spelling of a processor's instructions, one line per instruction, written to the rules of a single ISA. An assembler turns the text into the matching bytes; a program for one ISA does not run on another. is this human-readable spelling of a processor’s instructions, and the assembler: A program that reads assembly-language text and writes the matching bytes to an object file, with any labels, constants and directives the source used. clang, nasm and GNU as are three widely used assemblers. is the program that turns that text into the matching bytes. For the AArch64 program here, Apple’s clang acts as both: it assembles the three lines and links them into a Mach-O executable with one command.

The bytes themselves are machine code: The stream of bytes a processor really reads and runs, written to the rules of an ISA. Assembly language is a human-readable spelling of the same bytes; a disassembler reads the bytes and prints the spelling back., the only form the processor really reads. The disassembler: A program that reads the bytes of a compiled binary and prints the assembly instructions they encode, so a build with no source can still be read. otool, objdump and llvm-objdump are three widely used disassemblers. otool reads those bytes back and prints the same two instructions, so the source and the binary carry the same information in two different forms. A few bits inside each AArch64 instruction, together with the pattern of neighbouring bits, tell the processor which operation to run; that selector is the opcode: The group of bits inside an instruction that tells the processor which operation to run, with the remaining bits of the instruction selecting registers, immediates and modes. The ISA fixes where each opcode sits and what it means.. In Mach-O here, the encoding of mov w0, #42 writes 42 directly into w0 and ret is a single four-byte instruction, so the whole .text section comes out to eight bytes.

Step through the chain from source to a running program; then the recording below shows the same eight bytes and the exit status 42:

Interactive · step by step From text to bytes a processor can run Step through the lesson's AArch64 program as text, as bytes in a Mach-O binary, as two instructions a processor runs, and as the exit status the shell reads.
From text to bytes a processor can run, step 5 of 5. Showing aarch64_exit42.s (mov w0, #42 ; ret), clang (Apple clang 21) (assembler + linker), aarch64_exit42 (mov w0, #0x2a ; ret), CPU (w0 = 42 at the end), echo $?. In focus: echo $?.aarch64_exit42.smov w0, #42 ; retclang (Apple clang 21)assembler + linkeraarch64_exit42mov w0, #0x2a ; retCPUw0 = 42 at the endecho $?reads the exit statusexit status 42

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. A text file of three lines. Three lines a person can read. mov w0, #42 puts 42 into register w0, ret returns to the C runtime, and _main names the entry point the linker looks for. Each line is one instruction.
  2. clang assembles and links. Apple clang 21 reads the three lines, turns each mnemonic into the four bytes of its opcode and writes a Mach-O binary. The whole .text section is 8 bytes.
  3. A disassembler reads the bytes. otool reads the same 8 bytes and prints the two instructions. The hex 0x2a is 42, and ret is one four-byte instruction too. The source and the bytes carry the same information.
  4. The CPU runs two instructions. The kernel loads the binary, jumps to _main, and the CPU runs mov w0, #42 and ret. Register w0 ends up holding 42. The C runtime passes w0 to the operating system as the process exit status.
  5. The shell reads the status. The shell keeps the status in $?, so echo $? prints 42. Every example in this track records that status, so you can compare what runs on your machine with what the page shows.

AArch64 exit42: build, run, read the bytes Python · exit42_session.py
"""Builds and runs the AArch64 exit42 program natively on Apple silicon, then shows the bytes a Linux x86-64 and
RISC-V assembler would produce for the same idea.

AArch64 is the native ISA of Apple silicon Macs, so Apple clang 21 assembles the .s file, ld links it to a Mach-O
executable, the shell runs it and echo $? reads its exit status: 42, in full. The x86-64 and RISC-V versions make a
Linux system call (exit) that the macOS kernel does not understand, so the session assembles them to object files with
the matching clang target and reads the bytes with llvm-objdump. No foreign code runs.
"""

import sys
import pathlib

sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import session  # noqa: E402

# Each line is one /bin/sh call, so ./prog and echo must stay on the same line to share $?.
session.run(
    """
# AArch64 (Apple silicon) assembles, links and runs natively. The shell's exit status is echoed back.
clang -o aarch64_exit42 aarch64_exit42.s
./aarch64_exit42; echo "aarch64 exit=$?"

# Read the three instructions of the executable with Apple's otool, Mach-O's disassembler.
otool -tv aarch64_exit42

# x86-64 (Linux). Assemble to an ELF object with the Homebrew LLVM 23 driver, then read its bytes.
# macOS cannot run the program: its kernel does not know the Linux exit system call.
/opt/homebrew/opt/llvm/bin/clang -c -target x86_64-linux-gnu x86_64_exit42.s -o x86_64_exit42.o
/opt/homebrew/opt/llvm/bin/llvm-objdump -d --no-print-imm-hex -M intel x86_64_exit42.o

# RISC-V (Linux). Same route: assemble to an ELF object, read its bytes with llvm-objdump.
/opt/homebrew/opt/llvm/bin/clang -c -target riscv64-linux-gnu riscv_exit42.s -o riscv_exit42.o
/opt/homebrew/opt/llvm/bin/llvm-objdump -d --no-print-imm-hex riscv_exit42.o
"""
)

Output

# AArch64 (Apple silicon) assembles, links and runs natively. The shell's exit status is echoed back.
$ clang -o aarch64_exit42 aarch64_exit42.s
$ ./aarch64_exit42; echo "aarch64 exit=$?"
aarch64 exit=42

# Read the three instructions of the executable with Apple's otool, Mach-O's disassembler.
$ otool -tv aarch64_exit42
aarch64_exit42:
(__TEXT,__text) section
_main:
00000001000002d8	mov	w0, #0x2a
00000001000002dc	ret

# x86-64 (Linux). Assemble to an ELF object with the Homebrew LLVM 23 driver, then read its bytes.
# macOS cannot run the program: its kernel does not know the Linux exit system call.
$ /opt/homebrew/opt/llvm/bin/clang -c -target x86_64-linux-gnu x86_64_exit42.s -o x86_64_exit42.o
$ /opt/homebrew/opt/llvm/bin/llvm-objdump -d --no-print-imm-hex -M intel x86_64_exit42.o

x86_64_exit42.o:	file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <_start>:
       0: b8 3c 00 00 00               	mov	eax, 60
       5: bf 2a 00 00 00               	mov	edi, 42
       a: 0f 05                        	syscall

# RISC-V (Linux). Same route: assemble to an ELF object, read its bytes with llvm-objdump.
$ /opt/homebrew/opt/llvm/bin/clang -c -target riscv64-linux-gnu riscv_exit42.s -o riscv_exit42.o
$ /opt/homebrew/opt/llvm/bin/llvm-objdump -d --no-print-imm-hex riscv_exit42.o

riscv_exit42.o:	file format elf64-littleriscv

Disassembly of section .text:

0000000000000000 <_start>:
       0: 05d00893     	li	a7, 93
       4: 02a00513     	li	a0, 42
       8: 00000073     	ecall

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 exit42_session.py

The build command, clang -o aarch64_exit42 aarch64_exit42.s, assembles and links in one step; ./aarch64_exit42; echo "aarch64 exit=$?" runs the resulting executable and prints aarch64 exit=42. The shell has read a status that two instructions set. The lower part of the recording shows the x86-64 and RISC-V versions of the same idea as bytes, which the next section looks at side by side.

Key idea

A line of assembly stands for one instruction, and a few bits of that instruction, the opcode, say what the processor should do. Operands, modes and offsets fit around the opcode, so the source and the bytes carry the same information in two forms.

Checkpoint

Check: Instructions, machine code and assembly

  1. Question 1 of 2 What does an assembler do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Turns a text file of mnemonics into the bytes a processor runs

    The assembler turns assembly text into machine code. It does not run, decompile or optimise the program; the compiler, disassembler and emulator are the three other tools that often come up around it.

  2. Question 2 of 2 An AArch64 instruction is four bytes wide. Which part of those four bytes decides what operation runs?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: A fixed group of bits chosen by the ISA (the opcode), with other bits around it picking registers and the operand

    An opcode is a few bits inside the instruction, picked by the ISA. On AArch64 those bits sit at known positions in the 32-bit word; a disassembler reads them first to decide which operation to print, then reads the register and immediate fields.

The same idea in three ISAs

The three programs in the recording above do the same thing on three different processors: they place 42 somewhere the operating system reads and ask it to end the process. The difference is in which register holds the status, which instruction asks the operating system to end the process and what the resulting bytes look like.

An instruction set architecture: The contract between software and a processor: the registers a program may name, the instructions that act on them, how those instructions are encoded as bytes and the rules for memory, interrupts and privilege. x86-64, AArch64 and RISC-V are three ISAs. (ISA) is the contract between the software a programmer writes and the processor that runs it: the registers available to a program, the instructions that act on them, the way those instructions are encoded as bytes, and the rules for memory, interrupts and privilege. x86-64 is the ISA of today’s PCs and servers; Intel’s SDM and AMD’s APM are its two primary manuals. AArch64 is the 64-bit mode of Arm’s A-profile processors (Arm ARM DDI 0487 and the A64 ISA DDI 0602), used by every modern smartphone, every tablet and every Apple silicon Mac. RISC-V is a newer, open ISA (the RISC-V ratified specification library), common in embedded and research work and growing in India’s own Shakti and Vega chips and in Western server and GPU designs.

Three different ISAs, three different sets of registers, three different sets of bytes. The exit path in the recording above shows what that looks like for one small program:

  • x86-64 Linux uses eax and edi and the syscall instruction. The three bytes behind syscall are 0f 05, and the two moves that load 60 (the number for exit) and 42 take five bytes each: b8 3c 00 00 00 and bf 2a 00 00 00. Twelve bytes together.
  • RISC-V Linux uses a7 and a0 and the ecall instruction. Each instruction is four bytes wide: 05d00893 is li a7, 93, 02a00513 is li a0, 42 and 00000073 is ecall. Twelve bytes together as well.
  • AArch64 (Apple silicon) returns 42 from _main with mov w0, #42 and ret, eight bytes. The C runtime that called _main passes w0 on to the operating system, so no svc or syscall is needed in the function itself.

A nerdy coincidence

The two Linux versions here produce exactly twelve bytes of .text each, with the number 42 (hex 0x2a) sitting as 2a 00 00 00 on x86-64 and as part of the 02a00513 word on RISC-V. The same idea, two different wrappings of the same number.

A later lesson of this module writes each of the three programs in full and shows how each one ends. This section is about seeing that assembly is a family of languages, one per ISA, with the same underlying ideas, and that an engineer reading more than one of them meets most of the hardware they will ever work on.

Checkpoint

Check: x86-64, AArch64 and RISC-V

  1. Question 1 of 2 Which of the following are set by the ISA, rather than by the operating system or the assembler?

    Choose every answer that is right.

    Show the answer: Question 1 of 2

    Answer:

    • The byte encoding of each instruction
    • The names and widths of registers a program may use

    An ISA is the contract between software and processor: the registers, the instructions, their byte encodings and the rules for memory and interrupts. The operating system picks system call numbers and conventions, and the assembler and the writer pick the syntax.

  2. Question 2 of 2 On which ISA / Linux combination is 93 the exit call number, in a7, with ecall as the instruction that enters the kernel?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: RISC-V Linux

    RISC-V Linux is the only one of the three with that combination: a7 for the call number, 93 for exit, ecall to enter the kernel. The other two ISAs each use a different register and a different instruction, even when the call number happens to be 93 on arm64 as well.

Why reading assembly still matters

A high-level language usually hides the instructions a processor runs, so asking why anyone should still read assembly is a fair question. Six answers come up often in a working engineer’s life.

Compiler output. Compilers rearrange, inline, specialise and vectorise code enough that the shortest route to knowing what runs is to read the assembly they wrote. The same C function below becomes a single instruction on each of the three ISAs:

add() in C as AArch64, x86-64 and RISC-V assembly Python · add_three_isas_session.py
"""Shows what one C function looks like as assembly on each of the three ISAs the track teaches.

Homebrew LLVM 23 holds every target the track uses, so clang -S -O2 writes the assembly text for the host (AArch64)
and for the two cross targets (x86-64 and RISC-V) without running anything. For each ISA the driver prints the four
lines of the function: the label, its one add instruction, and the return. The lesson quotes those lines directly.
"""

import sys
import pathlib

sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import session  # noqa: E402

# sed prints every line from "add:" to the matching .cfi_endproc, which is the whole function body.
session.run(
    """
# AArch64: one 32-bit add, then return. The W registers hold the low 32 bits of X0 and X1.
/opt/homebrew/opt/llvm/bin/clang -S -O2 -target arm64-linux-gnu add.c -o add.aarch64.s
sed -n '/^add:/,/.cfi_endproc/p' add.aarch64.s

# x86-64, AT&T order (source first, with % on registers): leal (%rdi,%rsi), %eax does the add.
/opt/homebrew/opt/llvm/bin/clang -S -O2 -target x86_64-linux-gnu add.c -o add.x86_64.s
sed -n '/^add:/,/.cfi_endproc/p' add.x86_64.s

# RISC-V: addw works on the low 32 bits of a0 and a1, so the C int add fits in one instruction.
/opt/homebrew/opt/llvm/bin/clang -S -O2 -target riscv64-linux-gnu add.c -o add.riscv64.s
sed -n '/^add:/,/.cfi_endproc/p' add.riscv64.s
"""
)

Output

# AArch64: one 32-bit add, then return. The W registers hold the low 32 bits of X0 and X1.
$ /opt/homebrew/opt/llvm/bin/clang -S -O2 -target arm64-linux-gnu add.c -o add.aarch64.s
$ sed -n '/^add:/,/.cfi_endproc/p' add.aarch64.s
add:                                    // @add
	.cfi_startproc
// %bb.0:
	add	w0, w1, w0
	ret
.Lfunc_end0:
	.size	add, .Lfunc_end0-add
	.cfi_endproc

# x86-64, AT&T order (source first, with % on registers): leal (%rdi,%rsi), %eax does the add.
$ /opt/homebrew/opt/llvm/bin/clang -S -O2 -target x86_64-linux-gnu add.c -o add.x86_64.s
$ sed -n '/^add:/,/.cfi_endproc/p' add.x86_64.s
add:                                    # @add
	.cfi_startproc
# %bb.0:
                                        # kill: def $esi killed $esi def $rsi
                                        # kill: def $edi killed $edi def $rdi
	leal	(%rdi,%rsi), %eax
	retq
.Lfunc_end0:
	.size	add, .Lfunc_end0-add
	.cfi_endproc

# RISC-V: addw works on the low 32 bits of a0 and a1, so the C int add fits in one instruction.
$ /opt/homebrew/opt/llvm/bin/clang -S -O2 -target riscv64-linux-gnu add.c -o add.riscv64.s
$ sed -n '/^add:/,/.cfi_endproc/p' add.riscv64.s
add:                                    # @add
	.cfi_startproc
# %bb.0:
	addw	a0, a0, a1
	ret
.Lfunc_end0:
	.size	add, .Lfunc_end0-add
	.cfi_endproc

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 add_three_isas_session.py

On AArch64 the compiler writes add w0, w1, w0 followed by ret. On x86-64, in AT&T order (source first, with % on register names), it writes leal (%rdi,%rsi), %eax followed by retq — using the lea instruction, meant for address arithmetic, to add two integers in one step. On RISC-V it writes addw a0, a0, a1 followed by ret. Four mnemonics, one addition each, no stack, no spilling. Reading those lines is the shortest way to see whether a change to the C source will cost a branch, a memory access or a cache miss.

Crashes without source. A production segfault, a Windows crash dump or a stripped mobile build gives an engineer an address and a few bytes of context. Everything at that address is assembly; nothing else is available until a symbol server catches up or a core file is downloaded.

Performance work. SIMD, atomic operations, memory barriers, false sharing, dependency chains and branch prediction all sit below the C level. Measurements that disagree with a mental model are usually settled by reading the loop’s assembly.

Security hardening. Stack canaries, control-flow integrity, pointer authentication on AArch64, shadow stacks on x86-64 and RISC-V, and Spectre workarounds all leave visible marks in the compiled binary. Checking that a build really has the hardening its build flags asked for means reading its disassembly.

Operating systems and firmware. A boot sector, a context switch and the first instructions of a kernel have no higher-level language to hide inside. The same is true of inline assembly inside a kernel, a cryptographic library’s constant-time routine or a hot loop in a numerical library.

Generated and third-party code. Protocol buffers, machine-learning kernels, interpreters, just-in-time compilers and bytecode virtual machines often end at an assembly layer. Reading what the build really ships, rather than what the source implies, is the last line of trust.

A quiet but steady demand

Stack Overflow’s 2025 developer survey reports that 19.4 % of people learning to code and 7.1 % of all respondents had worked with assembly in the past year. The TIOBE programming community index placed assembly at number 16 of the languages it ranks, with a share of 0.89 %, in a recent monthly reading. Treat both numbers as directional, as both samples are self-selected; they are consistent with the kind of job assembly keeps, a smaller share of day-to-day work than C or Python, present wherever performance, security and systems work meet. Indian employers in chip design, embedded systems, mobile platforms and operating-system work hire for all three ISAs this track teaches.

Checkpoint

Check: Why engineers read assembly

  1. Question 1 of 2 A C function int add(int a, int b) { return a + b; } compiled with -O2 produced the disassembly addw a0, a0, a1; ret. Which ISA is this?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: RISC-V

    The register names a0 and a1 are RISC-V's convention for the first two arguments, and addw is its 32-bit add. The compiler-output recording above shows the three ISAs side by side, so this one matches the RISC-V row.

  2. Question 2 of 2 Which of these jobs best fits "reading assembly to confirm that a C program's hardening really runs"?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Looking at the disassembly to confirm that stack protectors, control-flow integrity or pointer authentication are present

    Release notes say what a compiler offers; a sanitizer catches test-time bugs; size differences are too noisy to judge hardening. Only the disassembly shows that stack canaries, CFI or PAC instructions really appear in the compiled binary.

How every example on this page is proved

Every example on every page of this track is a real file in the lesson’s folder, built and run on a pinned toolchain. The recording of that run — the exact command, the toolchain’s version line, the standard output and standard error merged as a terminal would show them, and the exit status — is saved as JSON beside the file. The lesson’s text reads from the same recording, so a number the prose quotes is a number the run really produced.

Interactive · step by step What every example on this track records Step through what the track captures the first time an example is run, where the record lives, and what the page shows a learner.
What every example on this track records, step 6 of 6. Showing your file, pinned toolchain, build and run, run.json, the lesson page, a learner. In focus: a learner.your file.s or _session.pypinned toolchainclang 21, macOS 26.7build and runrun twice, must agreerun.jsonbeside the filethe lesson pageshows the recorda learnerreads and repeatsread and repeat

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The file the record is about. An assembly source or a Python session driver sits in the lesson's examples folder. Its content is what the record points at; a change to it stales the record and a check will say so.
  2. The toolchain is pinned. For this lesson the toolchain is Apple clang 21.0.0 on macOS 26.7.1 on Apple silicon. The pins are written in the track's metadata, and the recorded run always names them.
  3. Build and run, twice. The checker runs the file twice on that toolchain. The two runs must print the same thing and end with the same exit status, so a run that depends on timing or on random data is caught at this step.
  4. Command, version, output, exit. One JSON file beside the source holds the exact command, the toolchain's version line, the stdout and stderr of the two runs together, the exit status and the time taken. The page reads from it; no number is typed by hand.
  5. The page shows the record. Each Example on the page shows the command, the printed output and the exit status, taken from the record. The lesson prose cites the same numbers.
  6. You repeat it on your machine. Because the command and the pinned toolchain are both on the page, a reader can run the same example and compare, line for line. A learner who gets a different exit status knows at once which step did not match.

For this lesson the host is an Apple M5 Pro laptop on macOS 26.7.1, and the pinned toolchain for the AArch64 code is Apple clang 21.0.0 with the ld-27037.1 linker. The x86-64 and RISC-V object files were produced by Homebrew’s clang 23.1.2 with -target x86_64-linux-gnu and -target riscv64-linux-gnu, without ever running the resulting Linux ELF files: the macOS kernel does not know those system calls, so they run only on Linux, natively or under qemu-user. Reading the bytes with llvm-objdump, by contrast, works here natively; no foreign code is executed to show the three encodings of the exit call.

Three practices make the recording trustworthy. Each example is run twice, and the two runs must print the same thing — a test that depends on random data or on a wall clock fails this step. Addresses that change between runs, such as the base load address otool prints beside each instruction, are written as 0x… by the recording helper, so the record does not look wrong on a re-run. And the pinned clang and linker versions appear in the record itself, so a reader can tell at once whether their own tools match.

Checkpoint

Check: What this track records

  1. One question Which pieces of information does the recording of a run (the run.json beside the file) include?

    Choose every answer that is right.

    Show the answer: One question

    Answer:

    • The toolchain's version line (clang 21.0.0, llvm-objdump 23.1.2 and so on)
    • The combined standard output and standard error of the run
    • The exact shell command that was run

    A run.json carries the command, the pinned toolchain's version, the merged output, the exit status and the elapsed time. Editor or author details are not part of it.

Practise

Four questions from the lesson, one at a time, with the idea you know least first. Each answer is explained at once; a miss brings the question back later in the session:

Practice that adapts to you

Practise this lesson

4 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 4 An engineer has a stripped binary with no symbols. Which tool reads the bytes of its .text section and prints them as assembly instructions?

    Choose one answer.

    Show the answer: Question 1 of 4

    Answer: A disassembler (otool, objdump, llvm-objdump)

    A disassembler reads bytes and prints the instructions they encode. On a stripped binary the labels are missing, so a block at 0x100000234 appears as sub_100000234, but the instructions themselves do not depend on the symbols.

  2. Question 2 of 4 A team is designing a new smartphone application processor and wants the existing operating system and apps to run on it without a rewrite. Which ISA fits that constraint?

    Choose one answer.

    Show the answer: Question 2 of 4

    Answer: AArch64

    AArch64 is the ISA of modern smartphones, so a 2026 phone application processor fits straight into Android or iOS stacks already built for it. RISC-V is growing elsewhere and may fit a later generation; a brand-new ISA cannot inherit an existing app ecosystem.

  3. Question 3 of 4 A senior engineer is weighing when to pull up a disassembler. For which of these situations does reading the assembly really help?

    Choose every answer that is right.

    Show the answer: Question 3 of 4

    Answer:

    • A hot loop that profiles slower than its arithmetic alone would suggest
    • A production segfault on a stripped mobile build
    • Confirming that -fstack-protector-strong actually produced a canary in a binary

    Assembly helps where behaviour depends on what the compiler really wrote: a hot loop, a crash without source, a hardening check. A JSON serialisation bug is better fixed in source; the disassembly only clutters the search.

  4. Question 4 of 4 The track runs each example twice before saving its recording. What is that catching?

    Choose one answer.

    Show the answer: Question 4 of 4

    Answer: An example whose output depends on random data or on the clock, so two runs do not agree

    The two-run rule catches examples whose output depends on something the record cannot capture: random data from a seed that moves, wall-clock time, process ids that differ. Those are rewritten or masked (as addresses are masked) before the record is saved.

Interview questions

What is the difference between an ISA, assembly language and machine code?

They are three layers of the same idea. An ISA is the contract: the registers a processor exposes, the instructions it accepts, how they are encoded in bytes, and the rules for memory, interrupts and privilege. Machine code is the stream of bytes a processor really reads, written to that contract. Assembly language is a human-readable spelling of those bytes, one line per instruction, with directives, labels and constants that make the file easier to write. An assembler turns the spelling into the bytes, and a disassembler reads the bytes back as the spelling. Each ISA has its own assembly language, because the instructions and registers differ, so a binary built for one does not run on another.

Which three ISAs does this track teach, and where does each one run?

x86-64, AArch64 and RISC-V. x86-64 (Intel 64 and AMD64) runs most PCs and data-centre servers today, developed from the 1970s 8086 line through many extensions. AArch64 is the 64-bit mode of Arm’s A-profile processors, used by every modern smartphone, every tablet and every Apple silicon Mac, with Windows on Arm as a growing desktop case. RISC-V is a newer, open ISA, used in embedded and research work and increasingly in India’s own Shakti and Vega chips as well as Western server and GPU designs. The lesson’s AArch64 example runs natively on Apple silicon; the x86-64 and RISC-V examples need Linux on their own ISA, or qemu-user, to run.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    Your team lead asks why a backend engineer should ever learn to read assembly in 2026. Give three concrete situations where reading assembly saves time or catches something no higher-level view would.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    This track records a JSON file beside every example. What goes into that record, what does it protect against, and how would you use it on a reader's machine to spot where their setup differs from the track's?

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. How do an ISA, assembly language and machine code relate to each other?

    The ISA is the contract a processor offers: its registers, its instructions, how they are encoded and the rules for memory and privilege. Machine code is the byte stream written to that contract, and assembly language spells those same bytes as readable lines, about one instruction per line.

  2. What does an assembler do, and what does a disassembler do?

    An assembler turns assembly text into the matching instruction bytes in an object file. A disassembler goes the other way: it reads the bytes of a binary and prints the instructions they encode, so code without source can still be read.

  3. Inside one instruction, what job does the opcode do?

    The opcode is the group of bits that picks the operation. The other bits of the instruction name the registers, constants and modes it works on, and the ISA fixes where each field sits.

  4. Which three ISAs does the track cover, and where is each one found?

    x86-64 runs most PCs and servers, AArch64 runs phones and Apple silicon Macs, and RISC-V is the open ISA of new and emerging hardware. The same tiny program gets different registers and different bytes on each.

  5. What are four reasons people still read assembly?

    To check what a compiler produced, to debug a crash when no source is at hand, to tune hot code, and to confirm that security hardening really made it into the binary. Operating systems, firmware and trusting third-party code need it too.

  6. Why does a program assembled for one ISA not run on another?

    Each ISA has its own instructions, registers and encodings, so bytes written for one processor family mean something else, or nothing, to another. That is also why every ISA has its own assembly language.

Key takeaways

  • Machine code is the stream of bytes a processor reads; assembly language is a human-readable spelling of those bytes, one line per instruction, written to the rules of a particular ISA.
  • Three ISAs matter today: x86-64 on PCs and servers, AArch64 on phones and Apple silicon, and RISC-V on open and emerging hardware. The same “return 42” idea becomes different registers and different bytes on each.
  • People read assembly to check compiler output, debug crashes without source, work on performance, verify security hardening, write operating systems and firmware, and trust generated or third-party code.
  • Every example on this track is a real file built and run on a pinned toolchain; its command, versions, output and exit status are saved as JSON beside the source and shown on the page.
  • A disassembler reads the bytes a build wrote and prints the same instructions the assembler produced, so a binary and a listing of its instructions carry the same information in two different forms.

Terms in this lesson

assembler
A program that reads assembly-language text and writes the matching bytes to an object file, with any labels, constants and directives the source used. clang, nasm and GNU as are three widely used assemblers.
assembly language
A human-readable spelling of a processor's instructions, one line per instruction, written to the rules of a single ISA. An assembler turns the text into the matching bytes; a program for one ISA does not run on another.
disassembler
A program that reads the bytes of a compiled binary and prints the assembly instructions they encode, so a build with no source can still be read. otool, objdump and llvm-objdump are three widely used disassemblers.
instruction set architecture
The contract between software and a processor: the registers a program may name, the instructions that act on them, how those instructions are encoded as bytes and the rules for memory, interrupts and privilege. x86-64, AArch64 and RISC-V are three ISAs.
machine code
The stream of bytes a processor really reads and runs, written to the rules of an ISA. Assembly language is a human-readable spelling of the same bytes; a disassembler reads the bytes and prints the spelling back.
opcode
The group of bits inside an instruction that tells the processor which operation to run, with the remaining bits of the instruction selecting registers, immediates and modes. The ISA fixes where each opcode sits and what it means.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.