What's the purpose of the LEA instruction?

Learn what's the purpose of the lea instruction? with practical examples, diagrams, and best practices. Covers assembly, x86, x86-64 development techniques with visual explanations.

Understanding the LEA Instruction in x86 Assembly

Hero image for What's the purpose of the LEA instruction?

Explore the purpose and common uses of the LEA (Load Effective Address) instruction in x86, x86-64, and x86-16 assembly, differentiating it from MOV.

The LEA (Load Effective Address) instruction is a fundamental component of x86 assembly language, often misunderstood or confused with data transfer instructions like MOV. While MOV copies data from one location to another, LEA calculates the memory address of its source operand and places that address into the destination operand, without actually accessing the memory location itself. This distinction makes LEA incredibly versatile for address calculations, pointer arithmetic, and even general-purpose integer arithmetic.

What LEA Does: Address Calculation, Not Data Loading

At its core, LEA computes the effective address of its source operand and stores this computed address in the destination register. The source operand can be a memory operand specified using various addressing modes (e.g., [base + index*scale + displacement]). Crucially, LEA does not dereference this address; it simply performs the arithmetic to determine what the address would be if memory were accessed. This behavior is key to its utility.

lea eax, [ebx + ecx*4 + 10h]
mov eax, [ebx + ecx*4 + 10h]

Comparison of LEA and MOV with an identical memory operand.

In the example above, LEA will calculate the address ebx + ecx*4 + 10h and store this numerical address into EAX. MOV, on the other hand, would calculate the same address, then fetch the value stored at that memory location, and place that value into EAX. This fundamental difference is what makes LEA a powerful tool for address manipulation.

Common Use Cases for LEA

LEA is not just for loading addresses; its ability to perform arithmetic using the full range of x86 addressing modes makes it a highly optimized instruction for several common tasks.

flowchart TD
    A[Start]
    A --> B{Need an address or pointer?}
    B -->|Yes| C[Use LEA to calculate address]
    C --> D[Address stored in register]
    B -->|No| E{Need data from memory?}
    E -->|Yes| F[Use MOV to load data]
    F --> G[Data stored in register]
    E -->|No| H[Other operations]

Decision flow for choosing between LEA and MOV.

1. Pointer Arithmetic and Array Indexing

One of the most straightforward uses of LEA is for calculating the address of an element within an array or structure. This is particularly useful when you need the address itself, rather than the content at that address.

; Calculate address of array[i]
lea esi, [array_base + edi*4] ; ESI now holds the address of array_base + EDI*4

; Equivalent to: esi = array_base + edi * 4
; (assuming array_base is a constant or loaded into a register)

Using LEA for array indexing to get an address.

2. Efficient General-Purpose Arithmetic

Due to its ability to perform additions and scaled multiplications (by 1, 2, 4, or 8) in a single instruction, LEA is frequently used as a general-purpose arithmetic instruction, even when no memory address is involved. This is a common optimization technique.

; Multiply EAX by 5 (EAX * 4 + EAX)
lea eax, [eax*4 + eax]

; Add 10 to EBX
lea ebx, [ebx + 10]

; Calculate (EAX * 2) + EBX + 7
lea ecx, [eax*2 + ebx + 7]

LEA used for various arithmetic operations.

3. Getting the Address of a Local Variable or Function

In position-independent code (PIC) or when working with stack-based local variables, LEA is used to obtain their addresses. For local variables, it calculates the offset from the stack base pointer (EBP or RBP). For functions, it can be used to get the address of a label relative to the instruction pointer (RIP) in x64.

; Get address of a local variable on the stack
lea eax, [ebp - 8]

; Get address of a function (x64 RIP-relative addressing)
lea rax, [function_label]
; or
lea rax, [rel function_label]

Using LEA to get addresses of stack variables and functions.