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

%AX = (%AH + %AL)

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

Ответ 1

Просто для некоторых разъяснений. В ранние микропроцессорные дни 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...................|

Ответ 2

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

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

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

Ответ 3

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

Урок истории 16-бит

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

Это может показаться разумным решением, но когда они его разработали, они заполнили большую часть доступного пространства. Так, например, для восьми отдельных регистров (AX, CX, DX, BX, SP, BP, SI, DI) было восемь команд POP, и они заполнили коды операций с 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-разрядные инструкции, 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, но она не использовала одинаковые байтовые коды (они даже не близки), и вам придется перекомпилировать (собрать) свою программу, чтобы заставить ее использовать новые байт-коды. Но "совместимый с исходным кодом" был способом продвижения старого программного обеспечения, и это позволило 8085 отдельным A, B, C и т.д. И комбо "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", чем на старом, sloppier пути "MOV AX, value / use EAX".)

Заключение

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