Использование 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 префикс).

Другие вопросы по тегам