Сборка - перемещение по регистру / массиву со смещением 5 - PullRequest
0 голосов
/ 24 марта 2020

Быстрый вопрос. Этот код не будет компилироваться:

mov eax, dword [rbx+rsi*5]

Я не ожидаю этого с объяснением, что mov и умножение - это две разные операции ЦП. Единственная причина, по которой это может быть достигнуто, - сдвиг битов.

Тем не менее, он компилируется:

mov eax, dword [lst+rsi*5]

С "lst" является переменным массивом. Он также производит вывод при использовании в контексте (поэтому код компилируется и выполняется). Как объяснить, почему это работает?

yasm -Worphan-labels -g dwarf2 -f elf64 NAME.asm -l NAME.lst

1 Ответ

0 голосов
/ 24 марта 2020
Режимы адресации

x86 должны соответствовать форме [base + idx*scale + disp0/8/32]. (Или относительно RIP.)

*scale фактически кодируется как 2-битный счетчик сдвигов , так что это может быть 1, 2, 4 или 8. См. Несколько вопросов о [base + index * scale + disp] и Ссылка на содержимое ячейки памяти. (режимы адресации x86)

Здесь происходит то, что ваш ассемблер разлагает [lst + rsi*5]
на [lst + rsi + rsi*4] для вас.
(или другие масштабные коэффициенты вида 1 + (1<<0..3))
(где lst - это 4-байтовый (32-битный) абсолютный адрес, который расширяется до 64-битного знака. И да, это работает в Linux non-P IE исполняемые файлы ; stati c code + data находятся на 2 ГБ виртуального адресного пространства точно так, что это может сработать.)

Но если у вас уже есть базовый регистр, его невозможно разделить и до сих пор есть кодируемый режим адресации. [rbx + rsi + rsi*4] невозможно.

Аналогично, NASM и YASM позволяют писать такие вещи, как vaddps xmm0, [rbp] вместо vaddps xmm0, xmm0, [rbp+0] (даже если RBP в качестве базового регистра не кодируется без смещения Также опуская первый исходный операнд, когда он совпадает с адресатом). Или, например, написать [rbp + rax] вместо [rbp + rax*1] - режим адресации может иметь не более 1 для каждой базы или индекса.

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


mov и умножение - две разные операции ЦП

Режимы адресации do включают сложение и смещение, хотя shl и add также являются отдельными инструкциями. Это не почему. Кроме того, imul ecx, [lst + rsi + rsi*4], 12345 является действительной инструкцией. То же самое происходит с аналогичным сдвигом или добавлением с использованием источника памяти или операнда назначения.

Но да, режимы адресации x86 не могут кодировать произвольные умножения, только счетчик сдвига в 2 бита.


Цикл массива произвольного шага / размера элемента:

Обычно вы получаете указатель в регистре и увеличиваете его внутри l oop

add  rsi, 5*4      ; 5*4 = 20 as an assemble time constant expression
add  eax, [rsi]

Это в основном уменьшение силы масштабирования, которое превращает умножение или сдвиг в сложение. Это означает, что вы можете использовать простые неиндексированные режимы адресации, которые более эффективны (размер кода и позволяют избежать ламинации в семействе Sandybridge.)

...