For me, it just seems like a funky MOV. What's its purpose and when should I use it?
The LEA (Load Effective Address) instruction is a way of obtaining the address which arises from any of the Intel processor's memory addressing modes. it moves the contents of the designated memory location into the target register.
LEA − Used to load the address of operand into the provided register. LES − Used to load ES register and other provided register from the memory.
The lea (load effective address) instruction is used to put a memory address into the destination.
MOV computes an address, using x86's rather rich set of addressing modes, and then either reads or writes the data at that address. LEA computes an address by the same means, and then stores the address itself in the target register.
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
.
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:
- the ability to perform addition with either two or three operands, and
- the ability to store the result in any register; not just one of the source operands.
And LEA
does not alter the flags.
Examples
LEA EAX, [ EAX + EBX + 1234567 ]
calculates EAX + EBX + 1234567
(that's three operands)LEA EAX, [ EBX + ECX ]
calculates EBX + ECX
without overriding either with the result.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With