Инструкция LEA (Load Effective Address) - это способ получения адреса, который возникает в любом из режимов адресации памяти процессора Intel.
То есть, если у нас есть данные, перемещающиеся следующим образом:
MOV EAX, <MEM-OPERAND>
перемещает содержимое назначенной ячейки памяти в целевой регистр.
Если мы заменим MOV
на LEA
, то адрес ячейки памяти будет точно таким же образом вычислен с помощью выражения адресации <MEM-OPERAND>
. Но вместо содержимого ячейки памяти мы получаем само местоположение в месте назначения.
LEA
не является конкретной арифметической инструкцией; это способ перехвата эффективного адреса, возникающего в любом из режимов адресации памяти процессора.
Например, мы можем использовать LEA
только по простому прямому адресу. Никакая арифметика не используется вообще:
MOV EAX, GLOBALVAR ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR ; fetch the address of GLOBALVAR into EAX.
Это действительно; мы можем проверить это в командной строке Linux:
$ 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
Здесь нет добавления масштабированного значения и смещения. Ноль перемещается в EAX. Мы могли бы сделать это, используя MOV с непосредственным операндом.
Именно по этой причине люди, которые считают, что скобки в LEA
являются излишними, сильно ошибаются; скобки не являются синтаксисом LEA
, а являются частью режима адресации.
LEA реально на аппаратном уровне. Сгенерированная инструкция кодирует фактический режим адресации, и процессор выполняет его до момента вычисления адреса. Затем он перемещает этот адрес к месту назначения вместо генерации ссылки на память. (Поскольку вычисление адреса в режиме адресации в любой другой инструкции не влияет на флаги ЦП, LEA
не влияет на флаги ЦП.)
Контраст с загрузкой значения с нулевого адреса:
$ as
movl 0, %eax
$ objdump -d a.out | grep mov
0: 8b 04 25 00 00 00 00 mov 0x0,%eax
Это очень похожая кодировка, понимаете? Просто 8d
из LEA
изменилось на 8b
.
Конечно, эта LEA
кодировка длиннее, чем перемещение непосредственного нуля в EAX
:
$ as
movl $0, %eax
$ objdump -d a.out | grep mov
0: b8 00 00 00 00 mov $0x0,%eax
Нет никаких оснований для LEA
исключать эту возможность, хотя бы потому, что есть более короткая альтернатива; он просто комбинируется ортогонально с доступными режимами адресации.