Пересылка данных: mov, lea, обмен

Урок разбирает основу всего ассемблера — пересылку данных между регистрами и памятью.

mov — главная команда ассемблера: копирует значение из источника в приёмник, не меняя источник.

Все формы mov

Команда mov куда, что читается справа налево: «положи что в куда». Возможные комбинации:

mov rax, 42        ; константа -> регистр
mov rax, rbx       ; регистр -> регистр
mov rax, [rbx]     ; память -> регистр (чтение)
mov [rbx], rax     ; регистр -> память (запись)
mov [rbx], 42      ; константа -> память (нужен размер: mov qword [rbx], 42)

Чего mov не умеет — копировать память в память напрямую: mov [rax], [rbx] запрещено. Нужно через регистр в два шага.

lea — вычислить адрес, а не значение

Команда lea (load effective address) считает адрес по той же формуле, что и квадратные скобки, но не лезет в память, а кладёт сам адрес:

lea rax, [rbx + rcx*4 + 8]   ; rax = rbx + rcx*4 + 8 (адрес)
mov rax, [rbx + rcx*4 + 8]   ; rax = значение по этому адресу

Хитрость: lea часто используют для быстрой арифметики. lea rax, [rbx + rbx*2] вычисляет rbx·3 одной командой, не трогая память и флаги.

Как работает под капотом

Сравним «значение» и «адрес» на Python-модели, где память — словарь адрес→значение:

mem = {100: 7, 104: 8, 108: 9}   # память: адрес -> значение
base = 100
index = 2
scale = 4
addr = base + index * scale      # lea: вычисляем адрес
print("lea  ->", addr)           # сам адрес 108
print("mov  ->", mem[addr])      # значение по адресу 9

Вывод:

lea  -> 108
mov  -> 9

lea остановилась на вычислении адреса (108), а mov пошла дальше и достала значение (9). Это ровно та разница, что между указателем и тем, на что он указывает.

Частые ошибки

  • Память в память. mov [a], [b] недопустимо — разбейте на чтение в регистр и запись.
  • Путать lea и mov со скобками. lea даёт адрес, mov [..] — содержимое.
  • Забыть размер при записи константы в память. NASM требует byte/dword/qword.

Итог

  • mov куда, что — копирование, не меняющее источник.
  • Память-в-память напрямую запрещена, нужен промежуточный регистр.
  • lea вычисляет адрес по формуле и кладёт его, не обращаясь к памяти.
  • lea удобна и для быстрой арифметики (умножение на 3, 5, 9 без флагов).
Проверьте себя
1. Что делает команда lea rax, [rbx + rcx*4]?
AЧитает значение по адресу rbx + rcx*4 в rax
BВычисляет адрес rbx + rcx*4 и кладёт его в rax
CЗаписывает rax в память
DСкладывает rbx и rcx
2. Почему mov [rax], [rbx] недопустима?
AТак слишком медленно
Bmov не умеет копировать память в память напрямую
CСкобки нельзя использовать дважды
Drax и rbx несовместимы
3. Как читается mov rax, rbx?
AПоложить rax в rbx
BПоложить rbx в rax (rax = rbx)
CОбменять rax и rbx
DСравнить rax и rbx