Почему нет регистра, который содержит старшие байты EAX? - PullRequest
64 голосов
/ 23 октября 2008

%AX = (%AH + %AL)

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

Ответы [ 3 ]

130 голосов
/ 23 октября 2008

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

Когда 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...................|
27 голосов
/ 09 сентября 2015

Здесь размещено много ответов, но никто не отвечает на данный вопрос: почему нет регистра, который непосредственно кодирует старшие 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://i.imgur.com/xfeWv.png. Обратите внимание, что на первичной карте не осталось места с некоторыми инструкциями, перекрывающими байты, и даже сколько вторичной памяти Карта «0F» теперь используется благодаря инструкциям MMX и SSE.)

К 32 и 64 битам

Таким образом, даже для того, чтобы разрешить расширение ЦП с 16 бит до 32 бит, у них уже была проблема проектирования, и они решили ее с префиксными байтами : добавив специальный байт "66" в Перед всеми стандартными 16-битными инструкциями процессор знает, что вам нужна та же инструкция, но 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 не является частью AX, и AX не является частью EAX, а EAX не является частью RAX: все они являются отдельными регистрами внутри, и процессор устанавливает флаг недействительности для других, когда вы манипулируйте одним из них, чтобы он знал, что ему нужно будет копировать данные, когда вы читаете из других.

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

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

(И да, это означает, что на современных процессорах действительно быстрее явно "MOVZX EAX, value", чем делать это старым, небрежным способом "MOV AX, value / use EAX".)

Заключение

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

25 голосов
/ 23 октября 2008

В старые 8-битные дни существовал регистр А.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...