Какова цель инструкции LEA? - PullRequest
609 голосов
/ 01 ноября 2009

Для меня это выглядит просто как фанк MOV. Каково его назначение и когда я должен его использовать?

Ответы [ 14 ]

7 голосов
/ 05 июня 2013

Инструкция LEA может использоваться, чтобы избежать трудоемких вычислений эффективных адресов ЦП. Если адрес используется неоднократно, более эффективно сохранять его в регистре, а не вычислять эффективный адрес каждый раз, когда он используется.

6 голосов
/ 16 мая 2014

Вот пример.

// compute parity of permutation from lexicographic index
int parity (int p)
{
  assert (p >= 0);
  int r = p, k = 1, d = 2;
  while (p >= k) {
    p /= d;
    d += (k << 2) + 6; // only one lea instruction
    k += 2;
    r ^= p;
  }
  return r & 1;
}

С -O (оптимизировать) в качестве опции компилятора, gcc найдет инструкцию lea для указанной строки кода.

4 голосов
/ 03 января 2019

Кажется, что многие ответы уже завершены, я хотел бы добавить еще один пример кода для демонстрации того, как команды lea и move работают по-разному, когда они имеют одинаковый формат выражения.

Короче говоря, можно использовать как инструкции Le, так и инструкции MOV с круглыми скобками, включающими операнд src инструкций. Когда они заключены в () , выражение в () вычисляется таким же образом; однако две инструкции по-разному интерпретируют вычисленное значение в операнде src.

Независимо от того, используется ли выражение с lea или mov, значение src рассчитывается следующим образом.

D (Rb, Ri, S) => (Reg [Rb] + S * Reg [Ri] + D)

Однако, когда он используется с командой mov, он пытается получить доступ к значению, на которое указывает адрес, сгенерированный вышеприведенным выражением, и сохранить его в месте назначения.

В отличие от этого, когда инструкция lea выполняется с вышеуказанным выражением, она загружает сгенерированное значение в том виде, в котором оно находится, к месту назначения.

Приведенный ниже код выполняет инструкцию lea и инструкцию mov с одним и тем же параметром. Однако, чтобы уловить разницу, я добавил обработчик сигнала уровня пользователя, чтобы отследить ошибку сегментации, вызванную обращением к неправильному адресу в результате команды mov.

Пример кода

#define _GNU_SOURCE 1  /* To pick up REG_RIP */
#include <stdio.h> 
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>


uint32_t
register_handler (uint32_t event, void (*handler)(int, siginfo_t*, void*))
{
        uint32_t ret = 0;
        struct sigaction act;

        memset(&act, 0, sizeof(act));
        act.sa_sigaction = handler;
        act.sa_flags = SA_SIGINFO;
        ret = sigaction(event, &act, NULL);
        return ret;
}

void
segfault_handler (int signum, siginfo_t *info, void *priv)
{
        ucontext_t *context = (ucontext_t *)(priv);
        uint64_t rip = (uint64_t)(context->uc_mcontext.gregs[REG_RIP]);
        uint64_t faulty_addr = (uint64_t)(info->si_addr);

        printf("inst at 0x%lx tries to access memory at %ld, but failed\n",
                rip,faulty_addr);
        exit(1);
}

int
main(void)
{
        int result_of_lea = 0;

        register_handler(SIGSEGV, segfault_handler);

        //initialize registers %eax = 1, %ebx = 2

        // the compiler will emit something like
           // mov $1, %eax
           // mov $2, %ebx
        // because of the input operands
        asm("lea 4(%%rbx, %%rax, 8), %%edx \t\n"
            :"=d" (result_of_lea)   // output in EDX
            : "a"(1), "b"(2)        // inputs in EAX and EBX
            : // no clobbers
         );

        //lea 4(rbx, rax, 8),%edx == lea (rbx + 8*rax + 4),%edx == lea(14),%edx
        printf("Result of lea instruction: %d\n", result_of_lea);

        asm volatile ("mov 4(%%rbx, %%rax, 8), %%edx"
                       :
                       : "a"(1), "b"(2)
                       : "edx"  // if it didn't segfault, it would write EDX
          );
}

Результат выполнения

Result of lea instruction: 14
inst at 0x4007b5 tries to access memory at 14, but failed
4 голосов
/ 06 мая 2015

LEA: просто «арифметическая» инструкция.

MOV передает данные между операндами, но lea только вычисляет

...