Режимы адресации
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.)