Skip to content

03 — Number Systems

Assembly works directly with binary data. Decimal is a human convenience; the CPU only knows bits. You must be comfortable converting between bases and understanding how negative numbers and characters are encoded.


Positional Number Systems

Every positional number system has a base (radix). The value of each digit is multiplied by the base raised to its position.

Base Name Digits Used Prefix in NASM
2 Binary 0, 1 0b or b suffix
8 Octal 0–7 0o or o suffix
10 Decimal 0–9 (none)
16 Hexadecimal 0–9, A–F 0x or h suffix

Binary (Base 2)

Each digit is a bit. Groupings: - 4 bits = nibble - 8 bits = byte - 16 bits = word - 32 bits = doubleword (dword) - 64 bits = quadword (qword)

Binary to Decimal

1011₂ = 1×2³ + 0×2² + 1×2¹ + 1×2⁰
       = 8    + 0    + 2    + 1
       = 11₁₀

Decimal to Binary

Repeatedly divide by 2, collect remainders bottom-up:

42 ÷ 2 = 21 R 0
21 ÷ 2 = 10 R 1
10 ÷ 2 =  5 R 0
 5 ÷ 2 =  2 R 1
 2 ÷ 2 =  1 R 0
 1 ÷ 2 =  0 R 1
             ↑ read upward: 101010₂

Hexadecimal (Base 16)

Hex is the most important base for assembly. One hex digit = exactly 4 bits = one nibble.

Hex Decimal Binary
0 0 0000
1 1 0001
... ... ...
9 9 1001
A 10 1010
B 11 1011
C 12 1100
D 13 1101
E 14 1110
F 15 1111

Hex to Binary (instant conversion)

Replace each hex digit with its 4-bit binary:

0xCAFE → C    A    F    E
       → 1100 1010 1111 1110

A 64-bit register in hex

0xDEADBEEFCAFEBABE
  DE AD BE EF CA FE BA BE  (8 bytes)

This is why hex is preferred — it's compact and maps directly to bytes.


Powers of 2 (Memorize These)

2ⁿ Value Hex
2⁸ 256 0x100
2¹⁰ 1,024 (1K) 0x400
2¹² 4,096 (4K = page size) 0x1000
2¹⁶ 65,536 (64K) 0x10000
2²⁰ 1,048,576 (1M) 0x100000
2³² 4,294,967,296 (4G) 0x100000000
2⁶³ ~9.2 × 10¹⁸ 0x8000000000000000

Signed Integers: Two's Complement

x86 uses two's complement to represent negative numbers. This lets the same ADD/SUB hardware handle both signed and unsigned arithmetic.

The Rule

For an N-bit number: - If the most significant bit (MSB) is 0 → positive (same as unsigned) - If the MSB is 1 → negative

Range

Size Unsigned Range Signed Range
8-bit 0 to 255 -128 to 127
16-bit 0 to 65,535 -32,768 to 32,767
32-bit 0 to 4,294,967,295 -2,147,483,648 to 2,147,483,647
64-bit 0 to 2⁶⁴-1 -2⁶³ to 2⁶³-1

Computing Two's Complement (negation)

To negate a number: flip all bits, then add 1

42  = 0b00101010
~42 = 0b11010101  (flip all bits)
+1  = 0b11010110  = -42 in two's complement

Verification: 42 + (-42) = 0

  00101010
+ 11010110
──────────
 100000000  (carry out of 8 bits = overflow, ignored → 0)  ✓

Why Two's Complement?

  • Only one representation of zero (unlike sign-magnitude)
  • Addition hardware works identically for signed and unsigned
  • Subtraction is just a + (-b)

Bit Manipulation Essentials

These operations are used constantly in assembly:

Operation Effect Example
x & mask Keep only masked bits 0xFF & 0x0F → 0x0F
x \| mask Set bits 0xF0 \| 0x0F → 0xFF
x ^ mask Toggle bits 0xFF ^ 0x0F → 0xF0
~x Flip all bits ~0x00 → 0xFF
x << n Multiply by 2ⁿ 1 << 3 → 8
x >> n Divide by 2ⁿ (unsigned) 16 >> 2 → 4

The Flags Register (RFLAGS)

After arithmetic and logic operations, the CPU updates flags in the RFLAGS register. These control conditional jumps.

Flag Name Set When
CF Carry Flag Unsigned overflow / borrow
ZF Zero Flag Result equals zero
SF Sign Flag Result is negative (MSB=1)
OF Overflow Flag Signed overflow
PF Parity Flag Result has even number of 1-bits
AF Auxiliary Carry Carry from bit 3 (BCD arithmetic)

Example: sub rax, rax → result is 0 → ZF=1, SF=0, CF=0, OF=0


ASCII and Character Encoding

Characters in memory are just numbers. ASCII assigns a number to each printable character.

'A' = 0x41 = 65
'a' = 0x61 = 97   (lowercase = uppercase + 0x20)
'0' = 0x30 = 48   (digit '0' is not value 0!)
'\n'= 0x0A = 10   (newline)

In NASM, character literals can be written directly:

mov al, 'A'      ; al = 65
mov al, 'A' + 32 ; al = 97 = 'a'  (to lowercase)

Number Literals in NASM

mov rax, 42          ; decimal
mov rax, 0x2A        ; hexadecimal
mov rax, 0b00101010  ; binary
mov rax, 0o52        ; octal
mov rax, 'A'         ; character (ASCII 65)

Practice Problems

  1. Convert 0xBEEF to decimal and binary.
  2. What is -1 in 8-bit two's complement? In 64-bit?
  3. What is 0x80000000 as a signed 32-bit integer?
  4. Given rax = 0xFF, what is rax & 0x0F? rax | 0x100?
  5. What ASCII character is at position 0x48?
Answers
  1. 0xBEEF = 48879; binary = 1011 1110 1110 1111
  2. -1 (8-bit) = 0xFF; -1 (64-bit) = 0xFFFFFFFFFFFFFFFF
  3. 0x80000000 = -2,147,483,648 (minimum signed 32-bit int)
  4. 0xFF & 0x0F = 0x0F; 0xFF | 0x100 = 0x1FF
  5. 0x48 = 'H'

Next: 04 — Setting Up the Environment