Почему нет регистра, который содержит более высокие байты EAX?

%AX = (%AH + %AL)

Итак, почему нет %EAX = (%SOME_REGISTER + %AX) для некоторого регистра %SOME_REGISTER ?

Просто для некоторых разъяснений. В ранние микропроцессорные дни 1970-х годов у процессоров было только небольшое количество регистров и очень ограниченный набор инструкций. Как правило, арифметический блок может работать только на одном регистре CPU, который часто называют «аккумулятором». Аккумулятор на 8-битных процессорах 8080 и Z80 назывался «А». Было также 6 других 8-разрядных регистров общего назначения: B, C, D, E, H & L. Эти шесть регистров можно было спаривать, чтобы сформировать 3 16-битных регистра: BC, DE & HL. Внутри накопитель был объединен с регистром Flags для формирования битового регистра AF 16.

Когда Intel разработала 16-битное семейство 8086, они хотели иметь возможность порт 8080-кода, поэтому они сохранили одну и ту же базовую структуру регистров:

 8080/Z80 8086 A AX BC BX DE CX HL DX IX SI IY DI 

Из-за необходимости порта 8-битного кода им нужно было иметь возможность обращаться к отдельным 8-битным частям AX, BX, CX & DX. Они называются AL, AH для низких и высоких байтов AX и т. Д. Для BL / BH, CL / CH & DL / DH. IX и IY на Z80 использовались только как 16-битовые регистры указателей, поэтому не нужно было обращаться к двум половинам SI и DI.

Когда 80386 был выпущен в середине 1980-х годов, они создали «расширенные» версии всех регистров. Таким образом, AX стал EAX, BX стал EBX и т. Д. Не нужно было получать доступ к верхним 16 битам этих новых расширенных регистров, поэтому они не создали псевдо-регистр EAXH.

AMD применила тот же трюк, когда они выпустили первые 64-разрядные процессоры. 64-разрядная версия регистра AX называется RAX. Итак, теперь у вас есть что-то похожее на это:

 |63..32|31..16|15-8|7-0| |AH.|AL.| |AX.....| |EAX............| |RAX...................| 

В старые 8-битные дни был регистр A.

В 16-битные дни существовал 16-битный регистр AX, который был разделен на две 8-битные части, AH и AL, в те моменты, когда вы все еще хотели работать с 8-битными значениями.

В 32-битные дни был введен 32-битный регистр EAX, но все регистры AX, AH и AL были сохранены. Дизайнеры не чувствовали необходимости вводить новый 16-битный регистр, который адресовал биты с 16 по 31 EAX.

Здесь много ответов, но никто не отвечает на данный вопрос: почему нет регистра, который напрямую кодирует 16 бит EAX или 32 бита RAX? Ответ сводится к ограничениям самой кодировки инструкции x86.

16-разрядный урок истории

Когда Intel разработала 8086, они использовали схему кодирования переменной длины для многих инструкций. Это означало, что некоторые чрезвычайно общие инструкции, такие как POP AX , могут быть представлены как один байт (58), в то время как редкие (но все же потенциально полезные) инструкции, такие как MOV CX, [BX*4+BP+1023] могут быть представлены , даже если для их хранения потребовалось несколько байтов (в этом примере 8B 8C FF 03).

Это может показаться разумным решением, но когда они его разработали, они заполнили большую часть доступного пространства . Так, например, было восемь инструкций POP для восьми отдельных регистров (AX, CX, DX, BX, SP, BP, SI, DI), и они заполнили коды операций с 58 по 5F, а код операции 60 был чем-то еще полностью ( PUSHA ), также как и код 57 ( PUSH DI ). Там не осталось места ни для чего, ни после этого. Даже нажатие и выскакивание сегментных регистров, которое концептуально почти идентично нажатию и выскакиванию регистров общего назначения, должно было быть закодировано в другом месте (около 06 / 0E / 16 / 1E) только потому, что не было места рядом остальные инструкции push / pop.

Аналогично, байт mod r / m, используемый для сложной команды, такой как MOV CX, [BX*4+BP+1023] имеет только три бита для кодирования регистра, что означает, что он может представлять только восемь регистров. Это нормально, если у вас только восемь регистров, но представляет собой настоящую проблему, если вы хотите иметь больше.

(Здесь есть превосходная карта всех этих байтовых распределений в архитектуре x86: http://sofru.miximages.com/assembly/xfeWv.png . Обратите внимание, что на основной карте нет места, с некоторыми инструкциями, перекрывающими байты, и даже с тем, как большая часть вторичной карты «0F» используется теперь благодаря инструкциям MMX и SSE.)

К 32 и 64 бит

Таким образом, чтобы разрешить расширение дизайна процессора с 16 бит до 32 бит, у них уже была проблема с дизайном, и они решили это с помощью префиксных байтов : добавив специальный «66» байт перед всеми стандартными 16-разрядными инструкции, CPU знает, что вы хотите использовать ту же инструкцию, но 32-разрядную версию (EAX) вместо 16-разрядной версии (AX). Остальная часть дизайна осталась прежней: в общей архитектуре ЦП оставалось всего восемь общих регистров общего назначения.

Подобный хакер должен был быть сделан для расширения архитектуры до 64 бит (RAX и друзей); там проблема была решена путем добавления еще одного набора префиксных кодов ( REX , 40-4F), что означало «64-бит» (и эффективно добавило еще два бита в поле «mod r / m»), а также отбросило странные старые инструкции, которые никогда не использовались, и повторное использование их байтовых кодов для новых вещей.

Помимо 8-битных регистров

Один из самых больших вопросов, которые нужно задать, – это то, как черты, подобные AH и AL, когда-либо работали в первую очередь, если в дизайне для восьми регистров есть только действительно место. Первая часть ответа состоит в том, что нет такой вещи, как « PUSH AL » – некоторые инструкции просто не могут работать в байтовых размерах вообще! Единственные, которые могут быть несколькими особыми странностями (например, AAD и XLAT ) и специальными версиями команд «mod r / m»: благодаря тому, что бит «mod r / m» имеет очень специфический бит, эти «расширенные инструкции» «может быть перевернуто для работы с 8-разрядными регистрами вместо 16-разрядных. Так получилось, что имеется также восемь 8-битных регистров: AL, CL, DL, BL, AH, CH, DH и BH (в этом порядке), и это очень хорошо сочетается с восемью доступными слотами регистра в байте «mod r / m».

В то время Intel отметила, что дизайн 8086 должен был быть «совместим с исходным кодом» с 8080/8085: в 8086 для каждой из инструкций 8080/8085 была эквивалентная инструкция, но она не использовала одни и те же байтовые коды (они даже не близки), и вам придется перекомпилировать (собрать) свою программу, чтобы заставить ее использовать новые байтовые коды. Но «совместимый с исходным кодом» был способом продвижения старого программного обеспечения, и это позволяло индивидуальным спискам A, B, C и т. Д. 8085 и комбо «BC» и «DE» по-прежнему работать над новым процессором, даже если бы они были теперь называемые «AL» и «BL» и «BX» и «DX» (или независимо от того, какое отображение было).

Так что это действительно реальный ответ. Не то, чтобы Intel или AMD намеренно «оставили» высокий 16-разрядный регистр для EAX или высокий 32-разрядный регистр для RAX: это то, что высокие 8-битные регистры – это странные оставшиеся исторические аномалии и репликации их дизайна при более высоких размерах бит, было бы действительно сложно, учитывая требование, чтобы архитектура была обратно совместимой.

Оценка эффективности

Есть еще одно соображение относительно того, почему эти «высокие регистры» еще не добавлены: в современных процессорных архитектурах по соображениям производительности регистры с переменным размером фактически не перекрываются для реального: AH и AL aren ‘ t часть AX, и AX не является частью EAX, и EAX не является частью RAX: все они находятся в разных регистрах под капотом, а процессор устанавливает флаг недействительности на других, когда вы управляете одним из чтобы они знали, что вам придется копировать данные, когда вы читаете их.

(Например: если вы устанавливаете AL = 5, процессор не обновляет AX. Но если вы затем прочитаете от AX, процессор быстро скопирует эти 5 из AL в нижние бит AX.)

Сохраняя регистры отдельно, ЦП может делать всевозможные умные вещи, такие как невидимое переименование регистров, чтобы сделать ваш код более быстрым, но это означает, что ваш код работает медленнее, если вы используете старый шаблон обработки небольших регистров как части большего размера регистры, потому что процессору придется останавливать и обновлять их. Чтобы сохранить всю эту внутреннюю бухгалтерскую отчетность из-под контроля, разработчики процессоров мудро решили добавить отдельные регистры на более новые процессоры, а не добавлять больше перекрывающихся регистров.

(И да, это означает, что на современных процессорах на самом деле быстрее « MOVZX EAX, value », чем для старого, sloppier-способа « MOV AX, value / use EAX ».)

Вывод

С учетом всего сказанного, могли ли Intel и AMD добавлять более «перекрывающиеся» регистры, если они действительно этого хотели? Конечно. Есть способы черви их, если будет достаточно спроса. Но учитывая значительный исторический багаж, существующие архитектурные ограничения, заметные ограничения производительности и тот факт, что большинство кодов в эти дни генерируются компиляторами, оптимизированными для неперекрывающихся регистров, маловероятно, что они добавят такие вещи в ближайшее время.

  • Как слить скаляр в вектор без компилятора, теряющего инструкцию обнуления верхних элементов? Ограничение дизайна в встроенных средах Intel?
  • Что означают префиксы E и R в именах 32-битных и 64-битных регистров Intel?
  • Почему SSE скалярный sqrt (x) медленнее, чем rsqrt (x) * x?
  • Почему (или нет?) SFENCE + LFENCE эквивалентно MFENCE?
  • Может ли x86's MOV быть «свободным»? Почему я не могу воспроизвести это вообще?
  • Ошибка сегментации сборки после выполнения системного вызова, в конце моего кода
  • Инструкции SSE: какие процессоры могут выполнять атомные операции памяти 16B?
  • Что такое 0x10 в инструкции по сборке «leal 0x10 (% ebx),% eax» x86?
  • Что означает `rep ret`?
  • Почему GCC, скомпилированный программой C, нуждается в разделе .eh_frame?
  • Как выглядит многоярусный язык ассемблера?
  • Давайте будем гением компьютера.