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.
That is to say, if we have a data move like this:
MOV EAX, <MEM-OPERAND>
it moves the contents of the designated memory location into the target register.
If we replace the MOV
by LEA
, then the address of the memory location is calculated in exactly the same way by the <MEM-OPERAND>
addressing expression. But instead of the contents of the memory location, we get the location itself into the destination.
LEA
is not a specific arithmetic instruction; it is a way of intercepting the effective address arising from any one of the processor's memory addressing modes.
For instance, we can use LEA
on just a simple direct address. No arithmetic is involved at all:
MOV EAX, GLOBALVAR ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR ; fetch the address of GLOBALVAR into EAX.
This is valid; we can test it at the Linux prompt:
$ as
LEA 0, %eax
$ objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 8d 04 25 00 00 00 00 lea 0x0,%eax
Here, there is no addition of a scaled value, and no offset. Zero is moved into EAX. We could do that using MOV with an immediate operand also.
This is the reason why people who think that the brackets in LEA
are superfluous are severely mistaken; the brackets are not LEA
syntax but are part of the addressing mode.
LEA is real at the hardware level. The generated instruction encodes the actual addressing mode and the processor carries it out to the point of calculating the address. Then it moves that address to the destination instead of generating a memory reference. (Since the address calculation of an addressing mode in any other instruction has no effect on CPU flags, LEA
has no effect on CPU flags.)
Contrast with loading the value from address zero:
$ as
movl 0, %eax
$ objdump -d a.out | grep mov
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
It's a very similar encoding, see? Just the 8d
of LEA
has changed to 8b
.
Of course, this LEA
encoding is longer than moving an immediate zero into EAX
:
$ as
movl $0, %eax
$ objdump -d a.out | grep mov
0: b8 00 00 00 00 mov $0x0,%eax
There is no reason for LEA
to exclude this possibility though just because there is a shorter alternative; it's just combining in an orthogonal way with the available addressing modes.