LEA is an ALU shift+add instruction that uses addressing-mode syntax and machine-code encoding to take advantage of hardware support for decoding this kind of operation. (It doesn't care if the inputs are addresses or not, so the 2nd part of your question is answered there: lea eax, [ecx + eax*2]
implements x*2 + y
efficiently.)
Under no circumstances does lea
ever load or store from memory. See Intel's instruction-manual entry for it.
Fun fact: the only exception it can take is if the ModR/M byte encodes a register source instead of memory. e.g. lea eax, eax
would fault with #UD (UnDefined instruction) if your assembler didn't refuse to assemble it, or if you manually encoded it with a db
pseudo-instruction. This is not something to worry about in practice if you're writing in asm, not in hex machine code. But there are no data-dependent exceptions it can take; it doesn't care at all what values it's operating on.
In the 3rd one, I think they're talking about something like val equ 4
or val = 4
, so "the value of val
" is an assemble-time constant, not stored in memory.
Yes you can use LEA for that (or any 32-bit constant), but mov eax, val
is shorter and more efficient. Using an LEA with an absolute disp32
addressing mode is pointless.
Fun fact: MASM ignores []
around assemble-time constants: mov eax, [val]
is a mov eax, imm32
, the same as mov eax, val
. Ross Ridge wrote a nice answer on Confusing brackets in MASM32.
lea eax, [var] — the value in var is placed in EAX.
The comment is wrong. The address of var
is placed in EAX. In normal asm terminology, the value in a symbol name means the value stored in memory at that address.
mov eax, OFFSET var
is more efficient and shorter than lea eax, [var]
.
Some people like to write lea
because of the "semantic" meaning for human readers: taking the address. But if you're writing in assembly, human readability should come after efficiency, and only win as a tie-breaker, e.g. choosing esi
for a source pointer when the choice makes no other difference. (Format / indent your code nicely, and comment it well.)
lea eax, [var + edi]
would make sense, you can't do that with mov
. But you can do mov eax, OFFSET var + 1234
, because assemblers + linkers have to be able to support filling in a 32-bit symbol+offset values for addressing modes like [var + 1234]
.
In 64-bit mode, lea rax, [rel var]
makes sense in position-independent code: you can't get a RIP-relative address with mov
.