16-битная сборка x86 против 8-битного непосредственного кодирования операнда - PullRequest
2 голосов
/ 10 июня 2019

Я пишу свой собственный ассемблер и пытаюсь кодировать инструкцию АЦП, у меня вопрос о немедленных значениях, особенно при добавлении 8-битного значения в регистр AX.

При добавлении 16-битного значения: adc ax, 0xff33 кодируется как 15 33 ff, что правильно.Но будет ли иметь значение, если adc ax, 0x33 закодировать как 15 33 00?

Насм закодирует это в 83 d0 33, что, очевидно, правильно, но мой подход также корректен?

1 Ответ

3 голосов
/ 10 июня 2019

Для x86 характерно иметь более 1 допустимого способа кодирования инструкции.Например, большинство op reg, reg инструкций могут выбирать кодировку с помощью операционного кода op r/m, reg или op reg, r/m.

И да, обычно вы хотите, чтобы ассемблер всегда выбирал для инструкции самую короткую кодировку.NASM даже оптимизирует mov rax, 1 (7 байт для mov r64, sign_extended_imm32) в mov eax, 1 (5 байт) для x86-64, изменяя размер операнда, чтобы использовать нулевое расширение вместо записи 32-битного регистра вместо явного знака-расширение 32-битного немедленного.

Использование кодировки sign-extended-imm8, когда доступно, всегда хорошо

Это равная длина для 16-битного, но короче для 32-битного размера операндаТаким образом, это упрощает ваш код, чтобы он всегда выбирал imm8.

. Размер операнда 32-битный, op eax, imm32 равен 5 байтам, тогда как op r/m32, imm8 все еще равен 3 байтам.(Не считая префиксов, необходимых для установки размера операнда или других вещей; они будут одинаковыми для обоих.)

Преимущества производительности кодировки imm8

Если требуется префикс размера операнда, требуется(например, в 32-битном режиме для adc ax, 0x33), использование кодировки adc ax/eax/rax, imm16/32/32 с префиксом размера операнда создаст стойку LCP на процессорах Intel (префикс изменения длины означает, что префикс изменяет длину rest инструкции. Этого не происходит для кодировки imm8, потому что она все еще (префикс) + код операции + modrm + imm8 независимо от размера операнда.

См. Agner Fog's microarch.pdf и другие ссылки на производительность в теге x86 вики . См. Также x86 инструкция, кодирующая, как выбрать код операции , который является его дубликатом, крометот факт, что adc является особым случаем.


В конкретном случае adc / sbb есть еще одно преимущество, позволяющее избежать кодировки ax, imm16: См. Какой Intelмикроархитектура яне представил ADC reg, 0 особый случай с одним мопом? На Sandybridge через Haswell, adc ax, 0 имеет специальный регистр как инструкция с одним мопом, вместо обычного 2 для мопов с 3 входами (ax, flags,Немедленно).

Но этот специальный регистр не работает для кодировок коротких форм без ModRM, поэтому 3-байтовый adc ax, imm16 все еще декодирует до 2 моп .Только декодер для формы imm8 проверяет, является ли непосредственный ноль перед декодированием в один моп.(И это все еще не работает для adc al, imm8.)

Так что всегда лучше выбирать вариант sign-extended-imm8, когда это возможно, для этого тоже даже в 16-битном режимегде префикс размера операнда не потребуется для adc ax,0, и, следовательно, проблема с остановкой LCP не возникнет.


Большинство ассемблеров не предоставляют переопределения, чтобы избежать краткой формы no-ModRM,Когда они были спроектированы, не было ни одного варианта использования производительности, кроме намеренного удлинения инструкций для получения выравнивания без добавления NOP перед вершиной цикла или другой целью ветвления: Какие методы можно использовать для эффективного увеличения длины инструкции насовременный x86?

Если вы разрабатываете новый вариант синтаксиса asm, вы можете подумать о предоставлении большего контроля над кодированием с помощью переопределенных ключевых слов.Для существующих конструкций проверьте ключевые слова strict и nosplit NASM, а также префиксы GAS {vex2}, {vex3}, {disp32} и т. Д.

...