2.0 Core IA-32 Architectural Concepts
A programmer’s effectiveness in assembly is directly tied to their mastery of the processor’s architecture. This section provides a detailed reference for the essential components an assembly programmer must understand: the processor’s registers, its model for memory organization, and the various modes for addressing data.
2.1 The Register Set
Registers are high-speed internal memory storage locations located directly within the processor chip. Their primary function is to hold data elements and addresses during processing, which speeds up operations significantly by minimizing the need to access the much slower main memory. The IA-32 registers are organized into three primary categories: General Registers, Control Registers, and Segment Registers.
2.1.1 General Registers
The general registers are the workhorses of the processor, used for arithmetic, logical, and other common operations. They are further subdivided into Data, Pointer, and Index registers.
Data Registers
These four 32-bit registers are primarily used for arithmetic and logical operations. They can be accessed in their full 32-bit size, as 16-bit halves, or as individual 8-bit components.
| 32-bit | 16-bit | 8-bit Components | Specialized Role |
| EAX | AX | AH / AL | The primary accumulator used in I/O and arithmetic instructions. |
| EBX | BX | BH / BL | The base register, which can be used in indexed addressing. |
| ECX | CX | CH / CL | The count register, used to store the loop count in iterative operations. |
| EDX | DX | DH / DL | The data register, used in I/O and for large multiplication/division operations. |
Pointer Registers
These registers are primarily used to hold memory addresses and manage the program stack.
- Instruction Pointer (EIP/IP): Stores the offset address of the next instruction to be executed within the code segment. The processor uses the CS:EIP (Code Segment:Instruction Pointer) pair to locate the current instruction.
- Stack Pointer (ESP/SP): Provides the offset value within the program stack, pointing to the top of the stack. It is used with the Stack Segment (SS) register, forming the pair SS:ESP to reference the current stack location.
- Base Pointer (EBP/BP): Primarily helps in referencing parameter variables that have been passed to a subroutine on the stack.
Index Registers
These registers are used for indexed addressing and are essential for processing strings and arrays.
- Source Index (ESI/SI): Used as the source index for string operations.
- Destination Index (EDI/DI): Used as the destination index for string operations.
2.1.2 Control Registers and Flags
The 32-bit instruction pointer (EIP) and the 32-bit flags register are considered the primary control registers. The flags register is a collection of status flags, which are single-bit values that indicate the outcome of arithmetic and comparison operations. Conditional instructions test the state of these flags to make decisions and alter the flow of program control.
| Mnemonic | Flag Name | Description |
| OF | Overflow Flag | Indicates an overflow of the high-order (leftmost) bit after a signed arithmetic operation. |
| DF | Direction Flag | Determines the direction for string operations. 0 for left-to-right, 1 for right-to-left. |
| IF | Interrupt Flag | When set to 1, enables external interrupts (e.g., keyboard). When 0, they are disabled. |
| TF | Trap Flag | Allows the processor to operate in single-step mode for debugging. |
| SF | Sign Flag | Shows the sign of an arithmetic result. 0 for positive, 1 for negative. |
| ZF | Zero Flag | Indicates the result of an operation. Set to 1 if the result is zero; cleared to 0 otherwise. |
| AF | Auxiliary Carry Flag | Contains the carry from bit 3 to bit 4 after an arithmetic operation. Used for specialized arithmetic. |
| PF | Parity Flag | Indicates if the number of set bits in the least significant byte of a result is even or odd. Set to 1 for an even number of set bits; cleared to 0 for an odd number. |
| CF | Carry Flag | Contains the carry (0 or 1) from the high-order (leftmost) bit after an arithmetic operation. |
2.1.3 Segment Registers
Memory segments are defined areas in a program for containing the code, data, and stack. The segment registers store the starting addresses of these segments.
- CS (Code Segment): Stores the starting address of the code segment, which contains all executable instructions.
- DS (Data Segment): Stores the starting address of the data segment, where data, constants, and work areas are stored.
- SS (Stack Segment): Stores the starting address of the stack segment.
Additionally, there are extra segment registers—ES, FS, and GS—which provide additional segments for storing data.
To locate a specific instruction or piece of data, the processor uses Segment:Offset addressing. It combines the starting address of a segment (stored in a segment register) with an offset value (often from a pointer or index register) to calculate the exact physical memory address.
2.2 The Memory Segmentation Model
The IA-32 architecture employs a segmented memory model, which divides the system memory into a series of independent segments. Each segment is intended to contain a specific type of information, providing a structured approach to memory management within a program. The three primary segments are:
- Data Segment: This segment is where data elements for the program are stored. It is represented by two sections in a NASM program:
- The .data section is used to declare and initialize data or constants. This memory region is static and cannot be expanded at runtime.
- The .bss section is also a static memory section but is used to reserve space for uninitialized data or buffers. This memory is typically zero-filled by the operating system when the program loads.
- Code Segment: Represented by the .text section, this is a fixed-size area in memory that stores the program’s executable instruction codes.
- Stack Segment: This segment is used as a temporary storage area for data values passed to functions and procedures, as well as for storing return addresses during function calls.
2.3 Data Addressing and Storage
The processor operates on a continuous fetch-decode-execute cycle:
- Fetch: The processor retrieves the next instruction from memory.
- Decode: The processor identifies the instruction to be performed.
- Execute: The processor carries out the instruction.
When storing multi-byte data in memory, the IA-32 architecture uses a reverse-byte sequence, also known as little-endian byte ordering. In this method, the low-order byte of a number is stored at the lower memory address, and the high-order byte is stored at the next higher address.
For example, the 16-bit hexadecimal number 0725H would be stored in memory as follows:
- The low-order byte 25 is stored at the starting memory address.
- The high-order byte 07 is stored at the subsequent memory address.
When the processor retrieves this data from memory back into a register, it automatically reverses the bytes back to their original order.
2.4 Addressing Modes
Addressing modes are the different ways an instruction can specify the location of its operands (the data it will operate on). IA-32 provides several modes to access data.
- Register Addressing: The operand is located directly within a processor register. This is the fastest mode as it does not require memory access.
- MOV EAX, EBX
- Immediate Addressing: The operand is a constant value embedded directly into the instruction itself.
- ADD BYTE_VALUE, 65
- Direct Memory Addressing: The operand’s offset address is specified directly by a variable’s name. The assembler calculates the offset and stores it in a symbol table.
- MOV BX, WORD_VALUE
- Direct-Offset Addressing: An address is modified using arithmetic operators to access elements within a data structure like an array or table.
- MOV CL, BYTE_TABLE[2]
- Indirect Memory Addressing: A register holds the memory address of the operand. This is highly useful for iterating through data structures like arrays. The register name is enclosed in square brackets [] to indicate that it contains an address, not the data itself. A complete usage sequence involves first loading the address of the data into a base register (like EBX) or index register (DI, SI) and then using that register to access the data.
- MY_TABLE TIMES 10 DW 0 ; Define a 10-word array
- MOV EBX, MY_TABLE ; Load the effective address of the array into EBX
- MOV WORD [EBX], 110 ; Access memory via the register to set the first element
Understanding this architecture provides the necessary foundation for structuring a program and writing effective instructions.