LEA Instruction is Powerful
A quick note on the LEA instruction of x86 family.
[ Check out all posts in “low-level” series here. ]
In my previous post on low-level code, we deconstructed a few assembly patterns. There were a few lea
instructions in the example assembly. I figured I can share a few links on why lea
is interesting.
Here is one occurrance of it:
...
lea rax, [var_11h]
mov rdi, rax
call sym.Foo::RandChar
...
For this discussion, let’s get a more raw disassembly of that part.
Below command is for binutils
version of objdump
(this_is_rdi
being the executable):
objdump --disassemble=main -C -M intel this_is_rdi
This is the relevant part of the output:
...
lea rax,[rbp-0x9]
mov rdi,rax
call 11fc <Foo::RandChar()>
...
You can check out the definition of lea
here. Basically, it stores the “effective address” computed in a register, rather than accessing the data at the calculated address.
We already discussed that rbp
stores a pointer to the base of the stack frame. What this lea
did is to get the address stored in rbp
, subtract 0x9
from that, and write the result in rax. So rax
now stores the memory address of some data on stack.1
This kind of address calculation can be called the main function of lea
. However, an address is a number, so lea
can also be used for some generic, combined arithmetic operations. And that use does often show up in optimized generated code.
Take this example:
lea r8d,[rcx+rcx*2]
Or same instruction, in att
syntax:
leal (%rcx,%rcx,2), %r8d
As it should be clear from the intel
syntax, the instruction is used to “multiply the value stored in rcx by 3”, and write the result to r8d
. In this case, the value that was originally stored in rcx
was not an address at all. You can find:
- a brief description of this use in this StackOverflow answer.
- a detailed explanation in this other answer.
Some more details on the subtleties around lea
instruction is available in the “16.1 LEA instruction (all processors)” section of Agner Fog’s manual called: “Optimizing subroutines in assembly language: An optimization guide for x86 platforms”. The manual can be found in this page. It states:
The LEA instruction is useful for many purposes because it can do a shift operation, two additions, and a move in just one instruction.
That’s all for today. If you find technical errors, please report in the blog’s Issues page.
Thanks for reading!
-
To remind what we already explained in a previous post: The
mov
will copy that address tordi
. The copy inrdi
is “thethis
pointer” being passed as an implicit argument to thecall
toFoo::RandChar
. ↩