Take the 2-minute tour ×

For me, it just seems like a funky MOV. What's its purpose and when should I use it?

share|improve this question

11 Answers 11

As others have pointed out, LEA (load effective address) is often used as a "trick" to do certain computations, but that's not its primary purpose. The x86 instruction set was designed to support high-level languages like Pascal and C, where arrays—especially arrays of ints or small structs—are common. Consider, for example, a struct representing (x, y) coordinates:

struct Point
     int xcoord;
     int ycoord;

Now imagine a statement like:

int y = points[i].ycoord;

where points[] is an array of Point. Assuming the base of the array is already in EBX, and variable i is in EAX, and xcoord and ycoord are each 32 bits (so ycoord is at offset 4 bytes in the struct), this statement can be compiled to:

MOV EDX, [EBX + 8*EAX + 4]    ; right side is "effective address"

which will land y in EDX. The scale factor of 8 is because each Point is 8 bytes in size. Now consider the same expression used with the "address of" operator &:

int *p = &points[i].ycoord;

In this case, you don't want the value of ycoord, but its address. That's where LEA (load effective address) comes in. Instead of a MOV, the compiler can generate

LEA ESI, [EBX + 8*EAX + 4]

which will load the address in ESI.

share|improve this answer
Wouldn't it have been cleaner to extend the mov instruction and leave off the brackets? MOV EDX, EBX + 8*EAX + 4 –  Natan Yellin Aug 15 '11 at 12:43
@imacake By replacing LEA with a specialized MOV you keep the syntax clean: [] brackets are always the equivalent of dereferencing a pointer in C. Without brackets, you always deal with the pointer itself. –  Natan Yellin Nov 4 '11 at 13:54
@Natan Hey ASM is never trivial anyway! :D –  imacake Nov 4 '11 at 18:40
Doing math in a MOV instruction (EBX+8*EAX+4) isn't valid. LEA ESI, [EBX + 8*EAX + 4] is valid because this is an addressing mode that x86 supports. en.wikipedia.org/wiki/X86#Addressing_modes –  Erik Jan 7 '12 at 6:07
@JonathanDickinson LEA is like a MOV with an indirect source, except it only does the indirection and not the MOV. It doesn't actually read from the computed address, just computes it. –  hobbs Aug 28 '13 at 2:57

From the "Zen of Assembly" by Abrash:

LEA, the only instruction that performs memory addressing calculations but doesn't actually address memory. LEA accepts a standard memory addressing operand, but does nothing more than store the calculated memory offset in the specified register, which may be any general purpose register.

What does that give us? Two things that ADD doesn't provide:

  1. the ability to perform addition with either two or three operands, and
  2. the ability to store the result in any register; not just one of the source operands.
share|improve this answer
+1; short, simple, and to the point. –  Unsigned Sep 9 '11 at 16:29
+1 - Can you please add examples for those two features it provides? –  Abid Rahman K Apr 6 '13 at 6:58
@AbidRahmanK some examples: LEA EAX, [ EAX + EBX + 1234567 ] calculates the sum of EAX, EBX and 1234567 (that's three operands). LEA EAX, [ EBX + ECX ] calculates EBX + ECX without overriding either with the result. The third thing LEA is used for (not listed by Frank) is multiplication by constant (by two, three, five or nine), if you use it like LEA EAX, [ EBX + N * EBX ] (N can be 1,2,4,8). Other usecase is handy in loops: the difference between LEA EAX, [ EAX + 1 ] and INC EAX is that the latter changes EFLAGS but the former does not; this preserves CMP state –  FrankH. Aug 22 '13 at 10:01
@FrankH. I still don't understand, so it loads a pointer onto somewhere else? –  rip Daddy 69 Oct 27 '13 at 15:04
@ripDaddy69 yes, sort of - if by "load" you mean "performs the address calculation / pointer arithmetics". It does not access memory (i.e. not "dereference" the pointer as it'd be called in C programming terms). –  FrankH. Oct 29 '13 at 9:04

Despite all the explanations, LEA is an arithmetic operation:

LEA Rt, [Rs1+a*Rs2+b] => Rt = Rs1 + a*Rs2 + b

It's just that its name is extremelly stupid for a shift+add operation. The reason for that was already explained in the top rated answers (i.e. it was designed to directly map high level memory references).

share|improve this answer
And that the arithmetic is performed by the address-calculation hardware. –  Ben Voigt Jul 12 '13 at 17:37
@BenVoigt I used to say that, because I'm an old bloke :-) Traditionally, x86 CPUs did use the addressing units for this, agreed. But the "separation" has become very blurry these days. Some CPUs no longer have dedicated AGUs at all, others have chosen not to execute LEA on the AGUs but on the ordinary integer ALUs. One has to read the CPU specs very closely these days to find out "where stuff runs" ... –  FrankH. Aug 22 '13 at 10:06

lea is an abbreviation of "load effective address". It loads the address of the location reference by the source operand to the destination operand. For instance, you could use it to:

lea ebx, [ebx+eax*8]

to move ebx pointer eax items further (in a 64-bit/element array) with a single instruction. Basically, you benefit from complex addressing modes supported by x86 architecture to manipulate pointers efficiently.

share|improve this answer

Maybe just another thing about LEA instruction. You can also use LEA for fast multiplaing registers by 3, 5 or 9.

LEA EAX, [EAX * 2 + EAX]   ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX]   ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX]   ;EAX = EAX * 9
share|improve this answer
+1 for the trick. But I would like to ask a question (may be stupid), why not directly multiply with three like this LEA EAX, [EAX*3] ? –  Abid Rahman K Apr 6 '13 at 6:57
@Abid Rahman K: There is no such as instruction unde x86 CPU instruction set. –  GJ. Apr 6 '13 at 17:23
@AbidRahmanK despite the intel asm syntax makes it look like a multiplication, the lea instruction can encode only shift operations. The opcode has 2 bits to describe the shift, hence you can multiply only by 1,2,4 or 8. –  ithkuil Aug 5 '13 at 13:03

Another important feature of the LEA instruction is that it does not alter the condition codes such as CF and ZF, while computing the address by arithmetic instructions like ADD or MUL does. This feature decreases the level of dependency among instructions and thus makes room for further optimization by the compiler or hardware scheduler.

share|improve this answer
That's a really good point missed by previous comments. –  Огњен Шобајић May 13 at 7:47

The 8086 has a large family of instructions which accept a register operand and an effective address, perform some computations to compute the offset part of that effective address, and perform some operation involving the register and the memory referred to by the computed address. It was fairly simple to have one of the instructions in that family behave as above except for skipping that actual memory operation. This, the instructions:

  mov ax,[bx+si+5]
  lea ax,[bx+si+5]

were implemented almost identically internally. The difference is a skipped step. Both instructions work something like:

  temp = fetched immediate operand (5)
  temp += bx
  temp += si
  address_out = temp  (skipped for LEA)
  trigger 16-bit read  (skipped for LEA)
  temp = data_in  (skipped for LEA)
  ax = temp

As for why Intel thought this instruction was worth including, I'm not exactly sure, but the fact that it was cheap to implement would have been a big factor. Another factor would have been the fact that Intel's assembler allowed symbols to be defined relative to the BP register. If fnord was defined as a BP-relative symbol (e.g. BP+8), one could say:

  mov ax,fnord  ; Equivalent to "mov ax,[BP+8]"

If one wanted to use something like stosw to store data to a BP-relative address, being able to say

  mov ax,0 ; Data to store
  mov cx,16 ; Number of words
  lea di,fnord
  rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

was more convenient than:

  mov ax,0 ; Data to store
  mov cx,16 ; Number of words
  mov di,bp
  add di,offset fnord (i.e. 8)

Note that forgetting the world "offset" would cause the contents of location [BP+8], rather than the value 8, to be added to DI. Oops.

share|improve this answer

The LEA instruction can be used to avoid time consuming calculations of effective addresses by the CPU. If an address is used repeatedly it is more effective to store it in a register instead of calculating the effective address every time it is used.

share|improve this answer

it because instead you write the code

mov dx,offset something

you can simply write

lea dx,something
share|improve this answer
Care to explain the difference? mov dx,offset something is totally valid since the address of something is known at the time of Linking. –  Gunner Dec 22 '13 at 20:01

Here is an example.

// compute parity of permutation from lexicographic index
int parity (int p)
  assert (p >= 0);
  int r = p, k = 1, d = 2;
  while (p >= k) {
    p /= d;
    d += (k << 2) + 6; // only one lea instruction
    k += 2;
    r ^= p;
  return r & 1;

With -O (optimize) as compiler option, gcc will find the lea instruction for the indicated code line.

share|improve this answer

As the existing answers mentioned, LEA has the advantages of performing memory addressing arithmetic without accessing memory, saving the arithmetic result to a different register instead of the simple form of add instruction. The real underlying performance benefit is that modern processor has a separate LEA ALU unit and port for effective address generation (including LEA and other memory reference address), this means the arithmetic operation in LEA and other normal arithmetic operation in ALU could be done in parallel in one core.

Check this article of Haswell architecture for some details about LEA unit: http://www.realworldtech.com/haswell-cpu/4/

share|improve this answer

Your Answer


