Использование 8-битных регистров в индексированных режимах адресации x86-64
Можно ли использовать 8-битные регистры (al, ah, bl, bh, r8b
) в индексированных режимах адресации в x86-64? Например:
mov ecx, [rsi + bl]
mov edx, [rdx + dh * 2]
В частности, это позволит вам использовать младшие 8 битов регистра в качестве смещения 0-255, что может быть полезно для некоторых ядер.
Я ознакомился с руководствами Intel, и они не содержат четких указаний по этому вопросу, но во всех приведенных ими примерах приведены только 32-битные или 64-битные регистры базы и индекса. В 32-битном коде я видел только 16 или 32-битные регистры. Рассмотрение деталей байт-кодирования mod-r/m и SIB также, похоже, указывает на "нет", но это достаточно сложно с достаточным количеством угловых случаев, поэтому я не уверен, что понял правильно.
Меня больше всего интересует поведение x86-64, но, конечно, если это возможно в 32-битном режиме, я бы хотел знать.
Поскольку вопрос надстройки слишком мал и связан с тем, чтобы заслуживать другого поста, можно ли использовать 16-битные регистры для базы или индекса? Например, mov rax, [rbx + cx]
, Мое расследование указывало на тот же ответ, что и выше: вероятно, нет.
1 ответ
Нет, вы не можете использовать 8-битные или 16-битные регистры при адресации вычислений в 64-битном режиме, равно как вы не можете использовать 8-битные регистры в 32-битном режиме. Вы можете использовать 16-битные регистры в 32-битном режиме и 32-битные регистры в 64-битном режиме, используя 0x67
байт префикса размера адреса.
Эта таблица хорошо суммирует различные варианты размеров операндов и адресов. Общая схема состоит в том, что размер адреса по умолчанию совпадает с текущим режимом (т. Е. 32-разрядным в 32-разрядном режиме, 64-разрядным в 64-разрядном режиме) 1, а затем, если 0x67
префикс включен, размер адреса изменяется на половину обычного размера (то есть 16-бит в 32-битном режиме, 32-бит в 64-битном режиме).
Вот выдержка из полной таблицы, приведенной выше, показывающая только 64-битное поведение в длинном режиме, для различных значений REX.W
, 0x66
операнд и 0x67
префиксы размера адреса:
╔════════╦═════════════╦═════════════╦═══════════════╦══════════════╗
║ REX.W ║ 0x66 prefix ║ 0x67 prefix ║ Operand size ║ Address size ║
║ ║ (operand) ║ (address) ║ (footnote 2) ║ ║
╠════════╬═════════════╬═════════════╬═══════════════╬══════════════╣
║ 0 ║ No ║ No ║ 32-bit ║ 64-bit ║
║ 0 ║ No ║ Yes ║ 32-bit ║ 32-bit ║
║ 0 ║ Yes ║ No ║ 16-bit ║ 64-bit ║
║ 0 ║ Yes ║ Yes ║ 16-bit ║ 32-bit ║
║ 1 ║ Ignored ║ No ║ 64-bit ║ 64-bit ║
║ 1 ║ ignored ║ Yes ║ 64-bit ║ 32-bit ║
╚════════╩═════════════╩═════════════╩═══════════════╩══════════════╝
1 Это может показаться очевидным, но это противоположно тому, как размеры операндов работают в 64-битном режиме: большинство по умолчанию 32-битные, даже в 64-битном режиме, и префикс REX необходим для их преобразования в 64-битные.
2 В некоторых инструкциях по умолчанию используется размер 64-битного операнда без каких-либо REX
префикс, а именно push
, pop
, call
и условные переходы, и, как указывает Питер ниже, это приводит к странной ситуации, когда хотя бы некоторые из этих инструкций (push
а также pop
не могут быть закодированы для использования 32-битных операндов, но могут использовать 16-битные операнды (с 0x66
префикс).