Кажется, что многие ответы уже завершены, я хотел бы добавить еще один пример кода для демонстрации того, как команды 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