X86 assembly language

assembly language used in x86 architecture From Wikipedia, the free encyclopedia

Remove ads
x86 assembly language is a low-level programming language that directly controls processors based on the x86 architecture, using human-readable instructions that correspond closely to machine code.

Introduction

X86 assembly language is a family of backward-compatible instruction set architectures based on the Intel 8086 microprocessor. It is used in personal computers and servers. X86 assembly refers to the low-level programming language that directly corresponds to the machine code instructions understood by x86 processors.

Assembly language acts as a mnemonic representation of machine code, making it more human-readable than raw binary or hexadecimal. Programmers use assemblers to translate assembly code into executable machine code. While most modern software is written in high-level languages like C++, Java, or Python, assembly language remains crucial for tasks requiring direct hardware manipulation, performance-critical sections, device drivers, and embedded systems programming.

Remove ads

History

The x86 architecture began with the 16-bit Intel 8086 microprocessor in 1978, followed by the 8088 (used in the original IBM PC). These processors introduced a segmented memory model and a set of instructions that laid the foundation for future generations. Key milestones include:

  • 80286 (1982): Introduced protected mode, allowing access to more memory and multitasking.
  • 80386 (1985): The first 32-bit x86 processor, establishing the IA-32 (Intel Architecture, 32-bit) standard. This was a monumental shift, introducing flat memory models and paving the way for modern operating systems.
  • Pentium Series (1993 onwards): Introduced superscalar architecture and various multimedia extensions (MMX, SSE).
  • AMD64 (2003) / EM64T (2004): The first widespread 64-bit extension to the x86 instruction set, also known as x86-64. This doubled the number of general-purpose registers and expanded addressable memory significantly, becoming the dominant architecture for modern computing.

Each generation maintained backward compatibility, meaning code written for older x86 processors could still run on newer ones, a key factor in the architecture's enduring success.

Remove ads

Registers

Registers are small, high-speed storage locations within the CPU. X86 processors have various types of registers:

General-Purpose Registers (GPRs)

These are used for arithmetic, logical operations, and storing operands. In 32-bit (IA-32) mode, they are EAX, EBX, ECX, EDX, EBP, ESP, ESI, EDI. In 64-bit (x86-64) mode, they are RAX, RBX, RCX, RDX, RBP, RSP, RSI, RDI, plus R8-R15. Each can be accessed as smaller registers (e.g., EAX can be split into AX, AH, AL).

Segment Registers

In older 16-bit and 32-bit protected mode, these registers (CS, DS, SS, ES, FS, GS) are used to define memory segments. While their role is diminished in modern flat memory models, they are still present for compatibility and specific OS tasks.

Instruction Pointer (IP/EIP/RIP)

Points to the next instruction to be executed. RIP (64-bit) is crucial for PC-relative addressing.

Flags Register (EFLAGS/RFLAGS)

Contains various status and control flags, such as the zero flag (ZF), carry flag (CF), sign flag (SF), and overflow flag (OF), which are set by arithmetic and logical operations.

SIMD/XMM Registers

Used for Single Instruction, Multiple Data operations, especially for multimedia and scientific computing (e.g., SSE, AVX instructions).

Instruction Set

The x86 instruction set is Complex Instruction Set Computing (CISC), meaning instructions can perform multiple operations and vary in length. Common categories include:

  • Data Transfer: MOV (move data), PUSH (push onto stack), POP (pop from stack), XCHG (exchange data).
  • Arithmetic: ADD, SUB, MUL, DIV, INC (increment), DEC (decrement).
  • Logical: AND, OR, XOR, NOT, TEST (AND without storing result).
  • Control Flow: JMP (jump), CALL (call procedure), RET (return from procedure), conditional jumps (e.g., JE - jump if equal, JNE - jump if not equal).
  • String Operations: MOVS (move string), CMPS (compare string), SCAS (scan string).
  • Bit Manipulation: SHL (shift left), SHR (shift right), ROL (rotate left), ROR (rotate right).

Many instructions can operate on various operand sizes (byte, word, doubleword, quadword) and addressing modes (register, immediate, direct, indirect).

Remove ads

Data Types

X86 assembly supports several fundamental data types, primarily defined by their size:

  • Byte (8 bits): Smallest addressable unit.
  • Word (16 bits): Two bytes.
  • Doubleword (32 bits): Four bytes.
  • Quadword (64 bits): Eight bytes.

These can be interpreted as signed or unsigned integers. Floating-point numbers are handled by specific FPU (Floating Point Unit) instructions or SSE/AVX extensions, typically using 32-bit (single-precision) or 64-bit (double-precision) IEEE 754 formats.

Remove ads

Memory Addressing

X86 processors offer powerful and flexible memory addressing modes:

  • Register Addressing: Operand is in a register (e.g., MOV EAX, EBX).
  • Immediate Addressing: Operand is part of the instruction itself (e.g., MOV EAX, 123).
  • Direct Addressing: Operand's memory address is specified directly (e.g., MOV EAX, [0x1000]).
  • Indirect Addressing (Register Indirect): Operand's memory address is in a register (e.g., MOV EAX, [EBX]).
  • Base-Index Addressing: Combines a base register and an index register (e.g., MOV EAX, [EBX + ESI]).
  • Base-Index-Scale-Displacement (SIB) Addressing: The most complex, allowing a base register, an index register scaled by 1, 2, 4, or 8, and a displacement (e.g., MOV EAX, [EBX + ESI*4 + 0x20]). This is very common for accessing array elements.
Remove ads

Programming Example

Here's a simple x86-64 assembly program (using NASM syntax) that calculates the sum of two numbers and exits.

section .data
    msg db "The sum is: ", 0 ; Null-terminated string

section .bss
    sum_ascii resb 10 ; Buffer for ASCII representation of sum

section .text
    global _start

_start:
    ; Define two numbers
    mov rax, 10         ; First number
    mov rbx, 20         ; Second number

    ; Add them
    add rax, rbx        ; RAX = RAX + RBX (RAX now holds 30)

    ; Convert sum (in RAX) to ASCII string for printing
    mov rdi, sum_ascii  ; Destination buffer
    call itoa           ; Convert integer to ASCII

    ; Print "The sum is: "
    mov rax, 1          ; syscall number for write (sys_write)
    mov rdi, 1          ; file descriptor 1 (stdout)
    mov rsi, msg        ; address of string to output
    mov rdx, 12         ; length of string
    syscall

    ; Print the calculated sum (ASCII)
    mov rax, 1          ; syscall number for write (sys_write)
    mov rdi, 1          ; file descriptor 1 (stdout)
    mov rsi, sum_ascii  ; address of sum_ascii
    mov rdx, 2          ; length of sum_ascii (e.g., "30") - assumes 2 digits for this example
    syscall

    ; Print newline
    mov rax, 1
    mov rdi, 1
    mov rsi, newline_char
    mov rdx, 1
    syscall

    ; Exit program
    mov rax, 60         ; syscall number for exit (sys_exit)
    mov rdi, 0          ; exit code 0
    syscall

; --- Helper function: itoa (integer to ASCII) ---
; Input:  RAX = integer to convert
; Output: RDI points to the buffer where ASCII string is stored
; Clobbers: RCX, RDX
itoa:
    mov rcx, rdi        ; RCX = pointer to buffer (to store digits from right to left)
    add rcx, 9          ; Move to the end of the buffer (max 10 chars + null)
    mov byte [rcx], 0   ; Null terminate the string
    dec rcx             ; Point to the last digit position

    mov rbx, 10         ; Divisor

.divide_loop:
    xor rdx, rdx        ; Clear RDX for division (RDX:RAX / RBX)
    div rbx             ; RAX = RAX / RBX, RDX = RAX % RBX (remainder)

    add rdx, '0'        ; Convert remainder to ASCII digit
    mov [rcx], rdx      ; Store digit in buffer

    dec rcx             ; Move to the next digit position
    cmp rax, 0          ; Check if quotient is zero
    jnz .divide_loop    ; If not zero, continue

    mov rdi, rcx        ; Update RDI to point to the start of the string
    ret

section .data
    newline_char db 0xA ; Newline character
Remove ads
Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads