Skip to main content

x86 Architecture

Introduction to x86 Architecture​

The x86 architecture forms the foundation of modern computing systems, enabling the execution of complex programs and applications. To grasp the inner workings of this architecture, we need to delve into its fundamental components and operational modes.

Processor as a Library and Framework​

At its core, the processor functions as both a library and a framework. In the context of a library, the processor provides a set of instructions that can be called to perform specific operations. On the other hand, it operates as a framework by establishing general rules for organizing the overall execution of instructions.

Operating Modes of the Processor​

The x86 processor can operate in different modes, each with distinct characteristics. These modes determine factors such as the maximum size of registers and available features. For instance, the x86 architecture supports real mode, which operates with a 16-bit maximum register size. Additionally, it supports protected mode with 32 bits and long mode with 64 bits.

Security Concerns and Solutions​

Security is a critical concern in computer systems, especially when running programs from unknown sources. To mitigate potential risks, the x86 architecture implements various security mechanisms:

Kernel Memory Protection​

Kernel memory is safeguarded against unauthorized read and write operations. Furthermore, kernel code cannot be accessed without explicit consent.

Sensitive Instructions​

Certain instructions, such as the transition from real mode to protected mode, are restricted to the kernel. This prevents unauthorized access and ensures that essential system functions are controlled.

Multitasking Protection​

In multitasking environments, tasks must be isolated from one another to prevent interference. This is achieved through the use of privilege levels. There are typically four (or two) privilege levels: kernel, device drivers, and user applications. Segmentation and paging mechanisms are also employed for protection.

Numbering System and Memory​

The x86 architecture employs different numbering systems, such as binary, hexadecimal, and decimal. For instance, 1 hex is equivalent to 4 bits in binary.

Basic View of Memory​

Memory can be viewed from both a logical and a physical perspective. Logical memory space represents the organization of memory as perceived by software, while physical memory space refers to the actual storage in the hardware.

x86 Segmentation​

In the x86 architecture, memory segmentation involves both a physical and a logical view. Physically, memory is organized as an array of bytes, while logically, segments are created through software or hardware, such as the x86 processor itself.

In the process of translating between physical and logical addresses, the processor employs segmentation and paging. This facilitates the transformation from physical memory addresses to linear memory addresses, and further to logical addresses.

Logical memory is divided into segments such as code, data, and stack segments. Segmentation is a critical aspect of the x86 architecture, and it cannot be turned off.

x86 Logical View in Different Modes​

In the real mode of the x86 architecture, segment registers store the starting memory addresses for different segments. These registers include CS (code segment), SS, DS, ES, FS, and GS, each of which is 16 bits in size. Each segment corresponds to a maximum of 64 KB.

When performing calls or jumps within the same segment, the segment register remains unchanged. However, when transitioning between different segments, such as with a far call or jump, the segment register is modified to reflect the new segment.

Protected Mode and Memory Protection​

Protected mode extends the functionality of real mode by introducing memory protection. This is achieved through the Global Descriptor Table (GDT), stored in main memory. The GDTR (Global Descriptor Table Register) points to the GDT and serves as a reference.

Segment descriptors within the GDT define segment information, such as starting memory addresses and limits. These descriptors are accessed using segment selectors. Unlike real mode, where segment registers contain actual addresses, in protected mode, they store segment selectors.

Segment descriptors include information about memory protection and other attributes. They consist of various flags, such as the Segment Type Flag, which designates the segment as system or application, and the Granularity Flag, which determines the unit of memory limit.

x86 Run-Time Stack​

The run-time stack is a critical element in program execution, facilitating the management of function calls and local variables. In the x86 architecture, the stack grows downward, which means that newer items are placed in memory addresses with smaller values. This convention aligns with the organization of function call frames, where each frame corresponds to a single function.

The stack frame consists of the EBP (Extended Base Pointer) and ESP (Extended Stack Pointer) registers. EBP points to the base of the current stack frame, while ESP indicates the top of the stack. Instructions like "push" and "pop" manipulate these registers to allocate and deallocate memory for function calls.

Calling Convention​

When one function calls another, a specific calling convention is followed to ensure proper parameter passing and return value handling. Parameters are passed by pushing them onto the stack in reverse order. Additionally, the return address is saved before the call, and control is transferred to the called function using the "call" instruction.

The callee function sets up its own stack frame by saving the old value of EBP and creating a new EBP for the new frame. Local variables are also pushed onto the stack, and EBP can be used to access previous values without altering the stack.

Upon completion of the callee function, the return value is stored in EAX. The stack frame is then deallocated, and the return address is loaded into EIP (Instruction Pointer) using the "ret" instruction.

Interrupts and Interrupt Descriptor Table (IDT)​

Interrupts play a vital role in managing the interactions between the processor and external devices. Interrupts can be triggered by various events, such as timer signals, keyboard presses, and software requests (system calls). Interrupts are distinct from exceptions, which are triggered by exceptional conditions in the program's execution.

The Interrupt Descriptor Table (IDT) contains entries that define the handling of different interrupt types. Each entry corresponds to a gate descriptor and contains information about the interrupt's location and behavior.

Interrupts are categorized into task, interrupt, and trap gates. A key distinction between interrupts and traps is that interrupts cannot be interrupted themselves, while traps can be.