2.0 Foundational Data Representation and Memory Addressing
The strategic importance of number systems in low-level programming cannot be overstated. Because all data is ultimately stored and manipulated in a binary format, proficiency in the binary and hexadecimal systems is non-negotiable for understanding memory layouts, data structures, and the machine instructions themselves. These systems are not abstractions; they are the language of the hardware.
The Binary Number System
The binary system uses positional notation with a base of 2. Each position in a binary number represents a power of two, starting from 2⁰ on the rightmost side. The value of a number is determined by summing the positional values where a ‘1’ is present. For an 8-bit number where all bits are set, the positional values are as follows:
| Bit Value | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| Power of 2 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| Bit Position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
If all 8 bits are set to 1, the total value is the sum of all position values: 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255, which is equivalent to 2⁸ – 1.
The Hexadecimal Number System
The hexadecimal system (base 16) serves as a compact and convenient representation for binary data. It uses digits 0-9 and letters A-F to represent decimal values 0-15. Since 16 is a power of 2 (2⁴), each hexadecimal digit corresponds directly to a unique 4-bit binary sequence. This makes conversion between the two systems straightforward.
| Decimal | Binary | Hexadecimal |
| 0 | 0000 | 0 |
| 1 | 0001 | 1 |
| 2 | 0010 | 2 |
| 3 | 0011 | 3 |
| 4 | 0100 | 4 |
| 5 | 0101 | 5 |
| 6 | 0110 | 6 |
| 7 | 0111 | 7 |
| 8 | 1000 | 8 |
| 9 | 1001 | 9 |
| 10 | 1010 | A |
| 11 | 1011 | B |
| 12 | 1100 | C |
| 13 | 1101 | D |
| 14 | 1110 | E |
| 15 | 1111 | F |
- Binary to Hexadecimal Example: To convert 1000110011010001, group it into 4-bit sections from the right: 1000 1100 1101 0001. This corresponds to the hexadecimal digits 8 C D 1, so the value is 0x8CD1.
- Hexadecimal to Binary Example: To convert 0xFAD8, convert each digit to its 4-bit binary equivalent: F -> 1111, A -> 1010, D -> 1101, 8 -> 1000. The result is 1111101011011000.
Rules of Binary Arithmetic
Binary addition follows four simple rules:
| (i) | (ii) | (iii) | (iv) |
| 0 | 1 | 1 | 1 |
| +0 | +0 | +1 | +1 |
| +1 | |||
| =0 | =1 | =10 | =11 |
Rules (iii) and (iv) demonstrate a “carry” of a 1-bit into the next position to the left. Rule (iv) accounts for a carry from a previous operation.
To represent negative numbers, IA-32 processors use two’s complement notation. This is a two-step process:
- Reverse all bits of the positive binary number (0s become 1s, and 1s become 0s).
- Add 1 to the result.
Subtraction is performed by converting the number to be subtracted into its two’s complement form and then adding the two numbers together. Any final overflow bit is discarded.
Example: Subtract 42 from 53
- Represent the numbers in binary:
- 53 = 00110101
- 42 = 00101010
- Find the two’s complement of 42:
- Reverse bits: 11010101
- Add 1: 11010101 + 1 = 11010110 (This is -42)
- Add 53 and -42:
- 00110101 (53)
- + 11010110 (-42)
- = (1)00001011 (11)
- The overflow bit is lost, leaving the correct result of 11.
Addressing Data in Memory
The IA-32 processor stores multi-byte data in memory using a reverse-byte sequence, also known as little-endian format. The low-order byte is stored at the lower memory address, and the high-order byte is stored at the higher memory address. For example, the number 0x0725 would be stored with 0x25 at the first memory address and 0x07 at the next. This is critical knowledge for debugging memory dumps or interfacing with network protocols, which often use big-endian (network byte order).
There are two primary kinds of memory addresses:
- An Absolute address is a direct reference to a specific memory location.
- A Segment address (or offset) is a relative address within a memory segment. It consists of the starting address of the segment combined with an offset value to locate the specific data.
These abstract concepts of data representation form the bedrock for all practical assembly programming. The next step is to configure a development environment where they can be applied.