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 16 – Privilege, exceptions and bare metal

16-bit x86: real mode and the 8086

How the 8086 forms 20-bit addresses from a segment and an offset, why PCs still start in real mode, and a 512-byte boot sector built with NASM.

  • Intermediate
  • 25 minutes
  • Examples run with Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 9 of 25 minutes free
Free: Real mode builds a 20-bit address from a segment and an offset · Every x86 processor still leaves reset in real mode · A legacy BIOS runs the 512 bytes it loads at 0x7C00 · Practise: change the sector and predict the bytes. With a pass: 2 in-depth parts and 3 interview answers, about 16 minutes.

What you will learn

  • Explain how real mode turns a segment and an offset into a 20-bit physical address
  • Find the physical address of a segment:offset pair, and a second pair that names the same byte
  • Explain why every x86 processor still starts in real mode and what a legacy BIOS does next
  • Build a 512-byte boot sector with NASM and check its size, signature and load address
  • Map the directives and operands of a MASM lab program to their NASM forms

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain how real mode turns a segment and an offset into a 20-bit physical address
  • Find the physical address of a segment:offset pair, and a second pair that names the same byte
  • Explain why every x86 processor still starts in real mode and what a legacy BIOS does next
  • Build a 512-byte boot sector with NASM and check its size, signature and load address
  • Map the directives and operands of a MASM lab program to their NASM forms

Before you start

On this page

A 64-bit x86 processor that boots through a legacy BIOS runs its first instructions in a 16-bit mode that reaches only 1 MiB, the 1,048,576 bytes of the 8086’s 20-bit address space. That mode, real mode, is how every x86 machine still starts, so boot loaders, firmware and the 8086 labs of many universities all live in it.

Real mode forms each address as segment x 16 + offset, from two 16-bit numbers. A BIOS copies 512 bytes to 0x7C00 and runs them in this mode; you will build such a sector and prove its layout from its bytes.

Real mode builds a 20-bit address from a segment and an offset

The 8086 has eight 16-bit general-purpose register: A register a program may freely use for integer values and addresses, as opposed to a special register with a fixed job. x86-64 has 16 (rax..r15), AArch64 31 (x0..x30) and RISC-V 32 (x0..x31). More in “Registers on x86-64, AArch64 and RISC-V”: ax, bx, cx and dx, whose halves are al, ah and so on, and si, di, bp and sp, which mostly hold addresses. One 16-bit register reaches only 64 KiB, so four segment register: One of the x86 registers cs, ds, ss and es (later also fs and gs) that selects a segment of memory. In real mode its value times 16 is the base address of the segment. extend it: cs for code, ds for data, ss for the stack and es for a second data area. ip holds the next instruction’s offset.

In real mode: The 16-bit mode every x86 processor starts in, inherited from the 8086. An address is segment x 16 + offset, about 1 MiB is reachable, and there is no memory protection or privilege check. the processor shifts the segment left by 4 bits, multiplying it by 16, and adds the offset, so 07C0:0000 and 0000:7C00 name one physical address: The address that reaches the memory bus after any translation the processor does. In real mode it is segment x 16 + offset; with paging it is the address a virtual address maps to., 0x07C00 (Intel’s manual, real-address mode). FFFF:FFFF gives 0x10FFEF, past 1 MiB: the 8086 had 20 address lines and wrapped it to 0x0FFEF, while later processors keep the carry unless the A20M# signal masks A20 line: Address line 20 of an x86 processor, the 21st address bit. The 8086 had only 20 lines, so its addresses wrapped at 1 MiB; later processors could mask line 20 with the A20M# signal to imitate that wrap..

Six pairs, their addresses and their aliases Python · segaddr.py
"""Real-mode addresses: physical = segment x 16 + offset, for a few pairs.

The 8086 had 20 address lines, so a sum above 0xFFFFF lost its carry and wrapped
to the bottom of memory. Later processors keep the carry on address line 20 (A20)
unless the A20M# signal masks it, so one pair can name two different bytes.
"""

ONE_MIB = 1 << 20  # 1,048,576 bytes: all that 20 address lines can reach


def physical(segment: int, offset: int) -> int:
    """The address formed when line A20 is enabled: no wrap."""
    return (segment << 4) + offset


def on_8086(segment: int, offset: int) -> int:
    """The 8086 drops the carry out of bit 19, so the sum wraps at 1 MiB."""
    return physical(segment, offset) % ONE_MIB


def pairs_naming(address: int) -> int:
    """How many segment:offset pairs name one byte below 1 MiB."""
    lowest = max(0, -(-(address - 0xFFFF) // 16))  # first segment that reaches it
    highest = min(0xFFFF, address // 16)  # last segment that starts at or below it
    return highest - lowest + 1


PAIRS = [
    (0x07C0, 0x0000, "the boot sector, as one BIOS loads it"),
    (0x0000, 0x7C00, "the same byte through another pair"),
    (0xB800, 0x0000, "colour text video memory"),
    (0xF000, 0xFFF0, "the reset CS:IP by the normal rule"),
    (0xFFFF, 0x0010, "one byte past the first MiB"),
    (0xFFFF, 0xFFFF, "the highest pair of all"),
]

print("pair        segment*16+offset  8086 (wraps)  note")
for segment, offset, note in PAIRS:
    full = physical(segment, offset)
    wrapped = on_8086(segment, offset)
    print(
        f"{segment:04X}:{offset:04X}   0x{full:06X}           0x{wrapped:05X}       {note}"
    )

print()
for address in (0x00000, 0x07C00, 0xB8000, 0xFFFF0):
    print(f"pairs that name 0x{address:05X}: {pairs_naming(address)}")
above = physical(0xFFFF, 0xFFFF) - ONE_MIB + 1
print(f"bytes above 1 MiB that real mode reaches with A20 on: {above}")

Output

pair        segment*16+offset  8086 (wraps)  note
07C0:0000   0x007C00           0x07C00       the boot sector, as one BIOS loads it
0000:7C00   0x007C00           0x07C00       the same byte through another pair
B800:0000   0x0B8000           0xB8000       colour text video memory
F000:FFF0   0x0FFFF0           0xFFFF0       the reset CS:IP by the normal rule
FFFF:0010   0x100000           0x00000       one byte past the first MiB
FFFF:FFFF   0x10FFEF           0x0FFEF       the highest pair of all

pairs that name 0x00000: 1
pairs that name 0x07C00: 1985
pairs that name 0xB8000: 4096
pairs that name 0xFFFF0: 4096
bytes above 1 MiB that real mode reaches with A20 on: 65520

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

1985 pairs name 0x07C00, every byte from 0x0FFF0 to the top of the first MiB has 4,096 names, and with A20 enabled real mode reaches 65,520 bytes above 1 MiB.

Interactive · step by step Forming one real-mode address Follow the pair FFFF:0010 from two registers to the address bus, then see two pairs land on one byte.
Forming one real-mode address, step 5 of 5. Showing Segment (07C0 or 0000), Offset (0000 or 7C00), Segment x 16 (07C00 or 00000), Address bus sum (0x07C00 twice), Kept by an 8086 (same byte). In focus: Segment, Offset, Address bus sum.shift left 4add20 bitsSegment07C0 or 0000Offset0000 or 7C00Segment x 1607C00 or 00000Address bus sum0x07C00 twiceKept by an 8086same byte

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

Every step as text
  1. Two 16-bit numbers. Real mode names a byte with two 16-bit values, a segment and an offset. Take the pair FFFF:0010: segment 0xFFFF and offset 0x0010.
  2. Shift the segment. The processor multiplies the segment by 16, which is a shift left by 4 bits and one more hex zero: 0xFFFF becomes 0xFFFF0. A segment always starts on a 16-byte boundary.
  3. Add the offset. The offset is added to the shifted segment: 0xFFFF0 + 0x0010 = 0x100000. The sum is exactly 1 MiB and needs 21 bits.
  4. The 8086 drops the carry. The 8086 has 20 address lines, so the carry out of bit 19 is lost and the byte read is 0x00000. Later processors keep the carry on line A20 unless the A20M# signal masks it.
  5. Two pairs, one byte. Pairs overlap every 16 bytes. 07C0:0000 and 0000:7C00 both give 0x07C00, because 0x07C0 x 16 is 0x7C00, and the run counts 1985 pairs for that one byte.

Checkpoint

Check: Segment and offset addresses

  1. Question 1 of 2 Which pair names the same byte as 0000:7C00?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 07C0:0000

    Real mode adds the offset to the segment times 16, so any pair whose segment x 16 + offset is 0x07C00 names the byte. The run counts 1985 such pairs.

  2. Question 2 of 2 Which byte does an 8086 read for the pair FFFF:0010?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 0x00000, because the carry out of bit 19 is lost

    The sum is 0x100000. An 8086 drops bit 20 and reads 0x00000; later processors keep the carry unless the A20M# signal masks address line 20.

Every x86 processor still leaves reset in real mode

Reset puts an x86 processor of any generation in real mode. Intel’s manual gives the state: the visible cs selector holds F000H, its hidden base FFFF0000H and eip FFF0H, so the first fetch, the reset vector: The address a processor fetches its first instruction from after a reset. On x86 it is FFFFFFF0H, 16 bytes below 4 GiB, where the board maps its firmware., is at FFFFFFF0H, just below 4 GiB, where the board keeps its firmware. The first far jump reloads cs, and the segment x 16 rule holds from then on.

Timeline · 5 events in order Every x86 generation kept the 8086 start Step through four processors and today's, and see what each added while reset stayed the same.
  1. 8086 (1978)

    16-bit registers and 20-bit addresses

    The 8086 builds 20-bit addresses from a segment and an offset, so it reaches 1 MByte. Real mode is the only mode it has.

  2. Intel 286 (1982)

    Protected mode arrives

    Segment registers can now hold selectors into descriptor tables, with 24-bit bases and up to 16 MBytes of memory. The processor still comes out of reset in real mode.

  3. Intel386 (1985)

    32-bit registers

    Registers grow to 32 bits and the address space to 4 GBytes. Old 16-bit code still runs, because reset still starts the 8086 way.

  4. Intel486 (1989)

    A20M# keeps the old wrap

    From the Intel486 on, the A20M# signal can mask address line 20 in real mode, so code that relied on the 8086 wrap at 1 MiB keeps working.

  5. Intel 64 today

    Reset still enters real mode

    A processor of today still leaves reset in real-address mode and fetches its first instruction at FFFFFFF0H. The A20M# pin may be absent now.

The timeline has 5 events, from 8086 (1978) to Intel 64 today.

The firmware decides how long real mode lasts. A legacy BIOS: Basic Input/Output System, the firmware of the original PC design. It tests and sets up the hardware, offers services through software interrupts, and boots a disk by running its first sector at 0x7C00 in real mode. starts a 512-byte boot sector in real mode. UEFI: Unified Extensible Firmware Interface, the firmware standard that replaced the PC BIOS. On x64 machines it switches the processor to 64-bit long mode itself and starts the operating-system loader as a 64-bit program. firmware switches an x64 processor to 64-bit long mode: The 64-bit mode of x86-64 processors, which Intel calls IA-32e mode, with 64-bit registers and paging always on. Operating systems run in it, and UEFI firmware on x64 machines starts loaders in it. itself and calls the operating-system loader as a 64-bit program (the UEFI specification, x64 platforms), so a UEFI loader never sees real mode.

A legacy BIOS runs the 512 bytes it loads at 0x7C00

A boot sector: The first 512-byte sector of a disk. A legacy BIOS loads it at physical address 0x7C00 and jumps to it in real mode, so it holds the first code of a BIOS boot. is the first 512-byte sector of a disk. SeaBIOS, the BIOS that QEMU uses for its PC machines, reads it to 07C0:0000, refuses a hard disk whose bytes 510 and 511 are not 55 AA, and jumps to it as 0000:7C00 (its boot.c). The code must fit in front of the boot signature: The bytes 55 AA at offsets 510 and 511 of a boot sector, the word 0xAA55 stored little-endian. A BIOS that checks it refuses to boot a hard disk whose first sector lacks it. and know its own load address.

In boot16.asm, org 0x7c00 makes NASM count labels from the load address, ds = 0 makes ds:si the plain address of the message, and times pads to byte 510 before dw 0xaa55, stored little-endian: The byte-order rule in which the lowest-value byte of a multi-byte value sits at the lowest address. Every mainstream x86-64, AArch64 and RISC-V system is little-endian in practice. More in “Endianness, strings and text in memory” as 55 AA. Each character leaves through COM1, the first serial port: An interface that sends data one bit after another over a line, driven by a UART. PCs name their serial ports COM1, COM2 and so on, and an emulator can wire one to a terminal., and a write to port 0xF4 ends QEMU.

boot16.asm ASM · boot16.asm
; boot16.asm: a 512-byte boot sector for a PC that starts in real mode.
; A legacy BIOS copies this sector to physical address 0x7C00 and jumps to it.
bits 16
org 0x7c00                  ; labels count from the load address, not from 0

start:
    cli                     ; nothing may interrupt this short program
    xor ax, ax
    mov ds, ax              ; DS = 0, so DS:SI is the physical address SI
    cld                     ; lodsb steps forward through the string
    mov si, msg

next_char:
    lodsb                   ; AL = byte at DS:SI, then SI = SI + 1
    test al, al
    jz finished             ; a zero byte ends the string
    mov bl, al
    mov dx, 0x3fd           ; COM1 line status register
wait_ready:
    in al, dx
    test al, 0x20           ; is the transmitter ready for a byte?
    jz wait_ready
    mov al, bl
    mov dx, 0x3f8           ; COM1 data register
    out dx, al
    jmp next_char

finished:
    mov al, 0x10
    out 0xf4, al            ; the exit device the QEMU command line adds
halt:
    hlt
    jmp halt

msg: db "Hello from 16-bit real mode", 13, 10, 0

times 510 - ($ - $$) db 0   ; fill the sector up to byte 510
dw 0xaa55                   ; bytes 55 AA: the boot signature
Build the sector and read its bytes back Python · build_boot_session.py
"""Assemble boot16.asm as a 512-byte boot sector and read it back."""

import pathlib
import sys

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

session.run("""
# Assemble a flat binary: no header, so byte 0 of the file is byte 0 of the sector
nasm -f bin -o boot16.bin boot16.asm
# A legacy BIOS reads exactly one 512-byte sector
wc -c boot16.bin
# Offsets 510 and 511 must hold 55 AA, the boot signature
xxd -s 510 -l 2 boot16.bin
# Read the code back as 16-bit instructions at the address the BIOS loads them to
ndisasm -b 16 -o 0x7c00 boot16.bin | head -n 9
""")

Output

# Assemble a flat binary: no header, so byte 0 of the file is byte 0 of the sector
$ nasm -f bin -o boot16.bin boot16.asm
# A legacy BIOS reads exactly one 512-byte sector
$ wc -c boot16.bin
     512 boot16.bin
# Offsets 510 and 511 must hold 55 AA, the boot signature
$ xxd -s 510 -l 2 boot16.bin
000001fe: 55aa                                     U.
# Read the code back as 16-bit instructions at the address the BIOS loads them to
$ ndisasm -b 16 -o 0x7c00 boot16.bin | head -n 9
00007C00  FA                cli
00007C01  31C0              xor ax,ax
00007C03  8ED8              mov ds,ax
00007C05  FC                cld
00007C06  BE277C            mov si,0x7c27
00007C09  AC                lodsb
00007C0A  84C0              test al,al
00007C0C  7412              jz 0x7c20
00007C0E  88C3              mov bl,al

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

The run proves the layout: 512 bytes, 55 AA at offset 0x1FE, and mov si,0x7c27, the message’s address after 39 bytes of code.

Interactive · step by step The first MiB of a PC that boots from a BIOS Walk up the 1 MiB that real mode reaches, from the interrupt vectors at 0 to the BIOS at the top.
The first MiB of a PC that boots from a BIOS, step 6 of 6. Showing BIOS ROM (from 0xF0000), Option ROMs (from 0xC0000), Video memory (from 0xA0000), More RAM (up to 0x9FFFF), Boot sector (0x07C00, 512 bytes), Low RAM (from 0x00400), Interrupt vectors (0x00000, 1 KiB). In focus: Option ROMs, BIOS ROM.BIOS ROMfrom 0xF0000Option ROMsfrom 0xC0000Video memoryfrom 0xA0000More RAMup to 0x9FFFFBoot sector0x07C00, 512 bytesLow RAMfrom 0x00400Interrupt vectors0x00000, 1 KiB

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

Every step as text
  1. 1 MiB in all. Real mode reaches 1,048,576 bytes, 0x00000 to 0xFFFFF, the 20-bit space of the 8086. RAM, video memory and ROM share it, so a boot sector must know where each one sits.
  2. Vectors at address 0. The processor keeps 256 interrupt vectors of 4 bytes each at physical 0, up to 0x003FF. Each one is a segment and an offset, so writing over them breaks every interrupt.
  3. The sector lands at 0x7C00. SeaBIOS, the BIOS QEMU ships for its PC machines, reads the first sector of the disk into 07C0:0000 and jumps to it as 0000:7C00. The 512 bytes fill 0x07C00 to 0x07DFF.
  4. RAM ends at 640 KiB. Ordinary RAM goes on up to 0x9FFFF; SeaBIOS names 0xA0000 the end of low RAM. Everything above it in the first MiB is set aside for devices and firmware.
  5. Video windows. The VGA card answers from 0xA0000 to 0xBFFFF. In colour text mode QEMU maps its text buffer at 0xB8000, the pair B800:0000.
  6. Firmware at the top. Option ROMs of cards start at 0xC0000, and SeaBIOS is built to run in the last 64 KiB, 0xF0000 to 0xFFFFF.

The script below boots the image on QEMU’s PC machine in your Linux lab. In this sector, in and out each move one byte between al and an I/O port. MASM lab programs differ from NASM mostly in directives and operands.

run_on_qemu.sh: boot the sector on QEMU Shell · run_on_qemu.sh
#!/bin/sh
# Boot boot16.bin on QEMU's PC machine, in your Linux lab.
# -drive format=raw         the file is a raw disk image: sector 0 is the boot sector
# -serial stdio             COM1 is wired to this terminal
# -display none             no window: the program talks only through COM1
# -device isa-debug-exit    an I/O port at 0xf4 that ends QEMU when the guest writes it
set -eu
nasm -f bin -o boot16.bin boot16.asm
status=0
qemu-system-i386 -drive format=raw,file=boot16.bin -serial stdio -display none \
  -device isa-debug-exit,iobase=0xf4,iosize=0x04 || status=$?
echo "qemu exit status: $status"
run_on_qemu.sh in the Linux lab Python · qemu_lab_session.py
import pathlib
import sys

sys.path.insert(0, str(pathlib.Path(__file__).parent / "sessions"))
import linux_lab

# In the Linux lab: the sector built with NASM and booted on QEMU's PC machine, whose COM1 is this terminal.
linux_lab.run("""
sh run_on_qemu.sh
""")

Output

$ sh run_on_qemu.sh
Hello from 16-bit real mode
qemu exit status: 33

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

The BIOS ran the sector, COM1 carried its message to the terminal, and the write to port 0xF4 ended QEMU, which reported status 33.

Checkpoint

Check: Reset starts in real mode · The 512-byte boot sector

  1. Question 1 of 2 Right after reset, cs shows the selector F000H and eip holds FFF0H. Where is the first instruction fetched from?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: FFFFFFF0H, through the hidden cs base FFFF0000H

    The visible selector and the hidden base disagree at reset on purpose: the base points at the firmware ROM just below 4 GiB. The first far jump makes cs follow the segment x 16 rule again.

  2. Question 2 of 2 The code and the message of boot16.asm take 69 bytes. How many zero bytes does its times line add?

    Type a number.

    A hint

    The times line fills the file up to byte 510, and the signature takes the last two bytes.

    Show the answer: Question 2 of 2

    Answer: 441

    times 510 - ($ - $$) repeats db 0 for 510 - 69 = 441 bytes. With the 2 signature bytes the file is 69 + 441 + 2 = 512 bytes, the size the run prints.

Practise: change the sector and predict the bytes

Work on copies of segaddr.py, boot16.asm and the build session, and write each prediction down before you run.

  1. Add the pairs 0040:0000, 1234:5678 and FFFF:000F to PAIRS in segaddr.py, predict all three addresses, and run it.
  2. Put two nop lines in front of mov si, msg in boot16.asm and predict the operand of mov si in the read-back.
  3. Change dw 0xaa55 to dw 0x1234, then predict the two bytes xxd prints at offset 0x1FE.

Practice that adapts to you

Practise this lesson

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

  1. Question 1 of 10 Which physical address does the pair 2000:0010 name?

    Choose one answer.

    Show the answer: Question 1 of 10

    Answer: 0x20010

    Shift the segment left by 4 bits, one hex zero, then add the offset.

  2. Question 2 of 10 What does real mode do to the segment value before it adds the offset?

    Choose one answer.

    Show the answer: Question 2 of 10

    Answer: Multiplies it by 16, a shift left by 4 bits

    Segment x 16 + offset gives a 20-bit address, enough for 1 MiB.

  3. Question 3 of 10 Colour text memory starts at 0xB8000. With the offset 0x0100, which segment reaches that byte?

    Choose one answer.

    Show the answer: Question 3 of 10

    Answer: 0xB7F0

    Subtract the offset from the address and divide by 16, (0xB8000 - 0x100) / 16 = 0xB7F0.

  4. Question 4 of 10 In which mode does an x86-64 processor run its first instruction after reset?

    Choose one answer.

    Show the answer: Question 4 of 10

    Answer: Real mode

    Reset always starts in real mode, which is why the 8086's addressing still matters on a 64-bit machine.

  5. Question 5 of 10 On an x64 PC with UEFI firmware, which mode is the processor in when the operating-system loader starts?

    Choose one answer.

    Show the answer: Question 5 of 10

    Answer: 64-bit long mode, set up by the firmware

    A BIOS boot hands a boot sector real mode; a UEFI boot hands the loader long mode.

  6. Question 6 of 10 The firmware's first far jump loads cs with F000H. Which base does cs have from then on?

    Choose one answer.

    Show the answer: Question 6 of 10

    Answer: 0xF0000

    The reset base is a one-time exception; the first far jump returns cs to segment x 16.

  7. Question 7 of 10 Where must the boot signature sit in a 512-byte sector?

    Choose one answer.

    Show the answer: Question 7 of 10

    Answer: At offsets 510 and 511, the bytes 55 then AA

    The run shows 55 AA at offset 0x1FE, which is 510.

  8. Question 8 of 10 In boot16.asm the message starts 0x27 bytes into the file. Which value does mov si, msg load?

    Choose one answer.

    Show the answer: Question 8 of 10

    Answer: 0x7C27

    The read-back shows mov si,0x7c27, the label's value with the load address added.

  9. Question 9 of 10 A sector's code and data take 100 bytes before its times line. How many zero bytes does the times line add?

    Type a number.

    A hint

    The padding ends at byte 510, before the 2 signature bytes.

    Show the answer: Question 9 of 10

    Answer: 410

    510 - 100 = 410 zero bytes, then 2 signature bytes, 512 in all.

  10. Question 10 of 10 A legacy BIOS must start a 600-byte program from a disk. What has to change?

    Choose one answer.

    Show the answer: Question 10 of 10

    Answer: A 512-byte sector must load the rest from the disk itself

    A legacy boot loads only the first sector, so larger programs start with a small loader that reads the rest.

A boot sector that prints over COM1 and exits QEMU Pro: opens with a Pro, Premium or Ultimate pass

Three port instructions carry every byte of boot16.asm to the outside world and then stop the machine. Their encodings, the status bit they wait for and the ways a sector breaks all show up in the sector’s own bytes.

In this part:

  • Driving COM1 with in and out, one byte at a time
  • Turning one byte into QEMU’s exit status, with the arithmetic checked
  • Three broken boot sectors, caught in their bytes

3 runnable examples (Python) · about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

MASM lab programs in NASM, with a translation table Pro: opens with a Pro, Premium or Ultimate pass

Many 8086 lab manuals are written for MASM or TASM, while NASM runs on every current system. The two assemblers describe the same machine code under different rules, and one table covers the differences a lab program meets.

In this part:

  • Translating MASM directives and operands into NASM forms
  • One string reversal in both syntaxes, read back byte by byte
  • DOS services 09h and 4Ch, read in the MS-DOS source

1 diagram · 5 runnable examples (ASM, MASM, NASM, Python) · about 10 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

How does an 8086 turn a segment and an offset into a physical address, and why can two different pairs name the same byte?

The 8086 shifts the 16-bit segment left by 4 bits and adds the 16-bit offset, which gives a 20-bit address. Segments start every 16 bytes and span 64 KiB each, so they overlap: 07C0:0000 and 0000:7C00 both name 0x07C00. FFFF:FFFF needs 21 bits, 0x10FFEF, which the 8086 wrapped to 0x0FFEF; later processors keep the carry unless A20M# masks it.

Three harder questions from the module’s bank start where that answer stops: a sector that boots wrongly, the wrap that old software relied on, and a MASM lab program to port:

  1. Mid to senior

    A boot sector built with NASM is 512 bytes and ends in 55 AA, yet when it boots it sends a few wrong bytes over COM1 instead of its message, and then stops. How would you find the cause from the image's bytes, and what would you fix?

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

  2. Mid to staff

    An old real-mode program reads a table through the pair FFFF:0010 and expects the bytes at physical address 0. On a newer PC it reads other bytes. Explain why, what address line 20 has to do with it, and how you would make the program independent of it.

    Model answer, Pro. First step and follow-ups

  3. Fresher to senior

    A MASM lab program declares count DW 5, then runs mov cx, count and mov si, OFFSET table before a loop that counts cx down. Ported to NASM by deleting OFFSET and keeping the rest, it assembles without a message, but the loop runs far more than 5 times. What went wrong, and how do you port each line?

    Model answer, Pro. First step and follow-ups

Flashcards · 5 cards

Recall it, then check

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

  1. How does an 8086 form a physical address from a segment and an offset?

    It shifts the 16-bit segment left by 4 bits, which multiplies it by 16, and adds the 16-bit offset, giving a 20-bit address. Segments start every 16 bytes and overlap, so 07C0:0000 and 0000:7C00 name the same byte, 0x07C00.

  2. What happened to FFFF:FFFF on an 8086, and what do later processors do?

    It needs 21 bits, 0x10FFEF, so the 8086 wrapped it to 0x0FFEF. Later processors keep the carry unless the A20M# signal masks address line 20.

  3. In which mode does every x86 processor leave reset, and where is its first instruction?

    In 16-bit real mode, fetching its first instruction at FFFFFFF0H, 16 bytes below 4 GiB, where the board maps its firmware.

  4. What does a legacy BIOS do with the first sector of a disk?

    It loads those 512 bytes at physical address 0x7C00 and jumps to them in real mode, provided the sector ends with the signature bytes 55 AA at offsets 510 and 511.

  5. How does UEFI differ from a legacy BIOS when it starts a loader on x64?

    UEFI switches the processor into 64-bit long mode itself and starts the operating-system loader as a 64-bit program, instead of running a 512-byte sector in real mode.

Key takeaways

  • Real mode forms a 20-bit physical address as segment x 16 + offset, so one byte has many segment:offset names.
  • The 8086 wrapped addresses past 0xFFFFF to 0, and later processors keep the carry unless A20M# masks line 20.
  • Every x86 processor leaves reset in real mode and fetches its first instruction at FFFFFFF0H.
  • A legacy BIOS runs the first 512-byte sector at 0x7C00 when it ends in 55 AA, and a boot sector’s size, signature and addresses can all be checked from its bytes.

Terms in this lesson

A20 line
Address line 20 of an x86 processor, the 21st address bit. The 8086 had only 20 lines, so its addresses wrapped at 1 MiB; later processors could mask line 20 with the A20M# signal to imitate that wrap.
BIOS
Basic Input/Output System, the firmware of the original PC design. It tests and sets up the hardware, offers services through software interrupts, and boots a disk by running its first sector at 0x7C00 in real mode.
boot sector
The first 512-byte sector of a disk. A legacy BIOS loads it at physical address 0x7C00 and jumps to it in real mode, so it holds the first code of a BIOS boot.
boot signature
The bytes 55 AA at offsets 510 and 511 of a boot sector, the word 0xAA55 stored little-endian. A BIOS that checks it refuses to boot a hard disk whose first sector lacks it.
interrupt vector table
In real mode, the table of 256 four-byte entries at physical address 0. Each entry holds the segment and offset of the handler for one interrupt or exception vector.
long mode
The 64-bit mode of x86-64 processors, which Intel calls IA-32e mode, with 64-bit registers and paging always on. Operating systems run in it, and UEFI firmware on x64 machines starts loaders in it.
physical address
The address that reaches the memory bus after any translation the processor does. In real mode it is segment x 16 + offset; with paging it is the address a virtual address maps to.
port-mapped I/O
Device access through a separate address space of I/O ports, which x86 reaches only with the in and out instructions, instead of loads and stores to memory addresses.
real mode
The 16-bit mode every x86 processor starts in, inherited from the 8086. An address is segment x 16 + offset, about 1 MiB is reachable, and there is no memory protection or privilege check.
reset vector
The address a processor fetches its first instruction from after a reset. On x86 it is FFFFFFF0H, 16 bytes below 4 GiB, where the board maps its firmware.
segment register
One of the x86 registers cs, ds, ss and es (later also fs and gs) that selects a segment of memory. In real mode its value times 16 is the base address of the segment.
serial port
An interface that sends data one bit after another over a line, driven by a UART. PCs name their serial ports COM1, COM2 and so on, and an emulator can wire one to a terminal.
UEFI
Unified Extensible Firmware Interface, the firmware standard that replaced the PC BIOS. On x64 machines it switches the processor to 64-bit long mode itself and starts the operating-system loader as a 64-bit program.

References

Related tools

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.