Почему размер операнда по умолчанию составляет 32 бита в режиме 64? - PullRequest
0 голосов
/ 22 января 2020

Я читаю Intel do c, vol. 1 и Существует глава 3.6.1 Размер операнда и размер адреса в 64-битном режиме . Существует три префикса REX.W, размер операнда 66 и префикс размера адреса 67. И там упоминается, что операнд по умолчанию имеет размер 32 бита. И возможно изменить его только с помощью префикса инструкции REX.W (после других префиксов), чтобы сделать его длиной 64 бита.

Я не знаю почему, почему я не могу использовать все 64-битное пространство, например, для int операнд? Это как-то связано со знаком? Или почему существует это ограничение? (Таким образом, C unsigned int использует префикс REX.W с операцией над int (как также упоминалось, префикс действует только для конкретной инструкции, но не для всего сегмента, который должен быть (размер (адрес или операнд) по умолчанию и содержится в дескрипторе сегмента).

Правильно ли я понимаю?

1 Ответ

2 голосов
/ 22 января 2020

TL: DR: у вас есть 2 отдельных вопроса. 1 о C размерах шрифта, а другой о том, как машинный код x86-64 кодирует 32, а не 64-битный размер операнда. Выбор кодировки довольно произвольный и мог бы быть сделан другим. Но int является 32-битным, потому что именно это и выбрали разработчики компилятора, ничего общего с машинным кодом.


int - 32-битный, потому что это все еще полезный размер для использования. Он использует половину пропускной способности памяти / кэш-памяти int64_t. Большинство C реализаций для 64-битных ISA имеют 32-битные int, включая оба основных ABI для x86-64 (x86-64 System V и Windows). В Windows даже long является 32-разрядным типом, предположительно для совместимости исходного кода с кодом, написанным для 32-разрядных, в котором делались предположения о размерах шрифта.

Кроме того, целочисленный множитель AMD в то время был несколько быстрее для 32-битных, чем для 64-битных, и так было до Ryzen. (Кремний AMD64 первого поколения был микроархитектурой AMD K8; см. https://agner.org/optimize/ для таблиц инструкций.)

Преимущества использования 32-битных регистров / инструкций в x86-64

x86-64 был разработан AMD в 2000 году как AMD64. Intel была привержена Itanium и не участвовала; все проектные решения для x86-64 были приняты архитекторами AMD.

AMD64 разработан с неявным расширением нуля при записи 32-битного регистра, поэтому 32-битный размер операнда может использоваться эффективно при отсутствии ни одного из махинаций с частичным регистром, которые вы получаете с 8- и 16-битным режимами .

TL: DR: ЦПУ имеют веские причины хотеть сделать доступным 32-битный размер операнда каким-то образом и для систем типа C иметь легко доступный 32-битный тип. Использование int для этого вполне естественно.

Если вы хотите 64-битный операнд Размер, используйте его. (А затем опишите его для C компилятора как long long или [u]int64_t, если вы пишете объявления C для ваших глобальных переменных asm или прототипов функций). Ничто не мешает вам (за исключением несколько большего размера кода, когда вам не нужны префиксы REX, которых у вас раньше не было).


Все это совершенно отдельный вопрос о том, как кодируется машинный код x86-64 32-битный размер операнда.

AMD решила сделать 32-битный размер по умолчанию, а для 64-битного размера операнда требуется префикс REX.

Они могли бы пойти другим путем и сделал размер по умолчанию 64-битным операндом, требуя REX.W = 0, чтобы установить его на 32, или 0x66 размер операнда, чтобы установить его на 16. Это могло привести к меньшему машинному коду для кода, который в основном манипулирует вещами в любом случае они должны быть 64-битными (обычно указатели), если для этого не требуется r8..r15.

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

В большом количестве кода для многих используется int вещи, так что 32-битный операнд Размер не редкость. И, как отмечено выше, это иногда быстрее. Так что имеет смысл сделать самые быстрые инструкции максимально компактными (если вы избегаете r8d..r15d).

Возможно, аппаратное обеспечение декодера будет проще, если один и тот же код операции декодирует аналогичным образом без префиксов в 32- и 64-битном режиме. Я думаю, что это была реальная мотивация AMD для этого выбора дизайна. Они, конечно, могли бы убрать много бородавок x86, но предпочли не делать этого, возможно, продолжать декодирование, более похожее на 32-битный режим.

Было бы интересно посмотреть, сохраните ли вы общий размер кода для версия x86-64 с размером операнда по умолчанию 64-битным. например, настроить компилятор и скомпилировать некоторые существующие кодовые базы. Однако вы бы хотели научить его оптимизатор отдавать предпочтение устаревшим регистрам RAX..RDI для 64-битных операндов вместо 32-битных, чтобы попытаться минимизировать количество инструкций, которым требуются префиксы REX.

(Многие инструкции, такие как add или imul reg,reg, могут безопасно использоваться с размером 64-битных операндов, даже если вы заботитесь только о младших 32, хотя высокий мусор повлияет на результат FLAGS.)


Re: дезинформация в комментариях: сравнение с 32-битным машинным кодом не имеет к этому никакого отношения. 64-битный режим не двоично совместим с существующим 32-битным машинным кодом; Вот почему в x86-64 введен новый режим . 64-разрядные ядра запускают 32-разрядные двоичные файлы в режиме сжатия, где декодирование работает точно так же, как в 32-разрядном защищенном режиме.

https://en.wikipedia.org/wiki/X86-64#OPMODES имеет полезную таблицу режимов, включая длинный режим ( и 64-битные и 32-битные и 16-битные режимы сжатия) и устаревший режим (если вы загружаете ядро, которое не поддерживает x86-64).

В 64-битном режиме некоторые коды операций отличаются, и операнд -размер по умолчанию 64-битный для push / pop и других кодов команд стека.

32-битный машинный код будет некорректно декодироваться в этом режиме. Например, 0x40 - это inc eax в режиме Compat, но префикс REX в 64-битном режиме. См. x86-32 / x86-64 фрагмент машинного кода полиглота, который обнаруживает 64-битный режим во время выполнения? для примера.

Также

* Декодирование в 1096 * 64-битном режиме в основном аналогичным образом - это вопрос совместного использования транзисторов в декодерах, а не двоичной совместимости. Предположительно, для декодеров проще иметь только 2 зависимых от режима размера операнда по умолчанию (16 или 32-бит) для коды операций, такие как 03 add r, r/m, а не 3. Только специальный корпус для кодов операций, таких как push / pop, которые гарантируют это. (Также обратите внимание, что REX.W = 0 делает не , позволяющим вам кодировать push r32; размер операнда остается на 64-битном.)

Решения AMD по дизайну Похоже, что основное внимание было уделено обмену транзисторами декодера в максимально возможной степени, возможно, в случае, если AMD64 не завоевала популярность, и они застряли, поддерживая его без людей, использующих его.

Они могли бы сделать много тонких вещей, которые убрали досадные причуды x86, например, сделали setcc 32-битной инструкцией размера операнда в 64-битном режиме, чтобы избежать необходимости сначала обнуления xor. Или CIS C раздражения, такие как флаги, оставшиеся неизменными после сдвигов с нулевым счетом (хотя процессоры AMD обрабатывают это более эффективно, чем Intel, поэтому, возможно, они намеренно оставили это в силе.)

Или, возможно, они думали, что тонкие изменения могут повредить портирование исходного кода в asm, или в краткосрочной перспективе усложнит работу бэкэндов компилятора для поддержки 64-битного кода.

...