Dlaczego nie ma rejestru zawierającego wyższe bajty EAX?

%AX = (%AH + %AL)

Więc dlaczego nie %EAX = (%SOME_REGISTER + %AX) dla jakiegoś rejestru %SOME_REGISTER?

Author: Digital Trauma, 2008-10-23

3 answers

Dla wyjaśnienia. We wczesnych latach siedemdziesiątych Procesory miały tylko niewielką liczbę rejestrów i bardzo ograniczony zestaw instrukcji. Zazwyczaj Jednostka arytmetyczna może działać tylko na jednym rejestrze procesora, często określanym jako "akumulator". Akumulator na 8-bitowych procesorach 8080 i Z80 nosił nazwę "A". Istnieje 6 innych 8-bitowych rejestrów ogólnego przeznaczenia: B, C, D, E, H & L. te sześć rejestrów można było sparować tworząc 3 16-bitowe rejestry: BC, DE i HL. Wewnętrznie akumulator został połączony z rejestrem Flags, tworząc 16-bitowy rejestr Af.

Kiedy Intel opracował 16-bitową rodzinę 8086, chcieli być w stanie portować kod 8080, więc zachowali tę samą podstawową strukturę rejestru:]}
8080/Z80  8086
A         AX
BC        BX
DE        CX
HL        DX
IX        SI    
IY        DI

Ze względu na konieczność portowania 8-bitowego kodu musieli być w stanie odwoływać się do poszczególnych 8-bitowych części AX, BX, CX i DX. Są one nazywane AL, AH dla niskich i wysokich bajtów AX i tak dalej dla BL/BH, CL/CH & DL/DH. IX I IY na Z80 były używane tylko jako 16-bitowe rejestry wskaźnikowe, więc nie było potrzeby dostępu do dwóch połówek SI & DI.

Kiedy 80386 został wydany w połowie lat 80-tych, stworzyli "rozszerzone" wersje wszystkich rejestrów. Tak więc AX stał się EAX, BX stał się EBX itp. Nie byĹ 'o potrzeby dostÄ ™ pu do 16 gĹ' Ăłwnych bităłw tych nowych rozszerzonych rejestrăłw, wiÄ ™ c nie tworzyli oni pseudo rejestru EAXH.

AMD zastosowało ten sam trik, gdy wyprodukowało pierwsze 64-bitowe procesory. 64-bitowa wersja rejestru AX nazywa się RAX. Więc teraz masz coś, co wygląda tak:
|63..32|31..16|15-8|7-0|
               |AH.|AL.|
               |AX.....|
       |EAX............|
|RAX...................|
 129
Author: Mike Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-17 10:25:54

W dawnych 8-bitowych czasach był rejestr A.

W dniach 16-bitowych istniał 16-bitowy rejestr AX, który był podzielony na dwie 8-bitowe części, AH i AL, dla tych czasów, gdy nadal chciałeś pracować z wartościami 8-bitowymi.

W dniach 32-bitowych wprowadzono 32-bitowy rejestr EAX, ale wszystkie rejestry AX, AH i AL były przechowywane. Projektanci nie uznali za konieczne wprowadzenie nowego 16-bitowego rejestru adresującego bity od 16 do 31 EAX.

 25
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-23 01:41:50

Jest tu wiele odpowiedzi, ale żadna tak naprawdę nie odpowiada na zadane pytanie: Dlaczego nie ma rejestru, który bezpośrednio koduje wysokie 16 bitów EAX lub wysokie 32 bity RAX? Odpowiedź sprowadza się do ograniczeń samego kodowania instrukcji x86.

16-Lekcja Historii Bitów

Kiedy Intel projektował 8086, używali schematu kodowania o zmiennej długości dla wielu instrukcji. Oznaczało to, że pewne niezwykle powszechne instrukcje, podobnie jak POP AX, może być reprezentowany jako pojedynczy bajt (58), podczas gdy rzadkie (ale potencjalnie przydatne) instrukcje, takie jak MOV CX, [BX*4+BP+1023], mogą być reprezentowane, nawet jeśli przechowywanie ich zajęło kilka bajtów (w tym przykładzie, 8B 8C FF 03). To może wydawać się rozsądnym rozwiązaniem, ale kiedy je zaprojektowali, wypełnili większość dostępnej przestrzeni. Tak więc, na przykład, było osiem POP Instrukcji dla ośmiu pojedynczych rejestrów (AX, CX, DX, BX, SP, BP, SI, DI) i one opcode 60 był czymś zupełnie innym (PUSHA), podobnie jak opcode 57 (PUSH DI). Nie ma miejsca na nic po tym, ani przed tym. Nawet wypychanie i wyskakiwanie rejestrów segmentów-co jest koncepcyjnie prawie identyczne z wypychaniem i wyskakiwaniem rejestrów ogólnego przeznaczenia-musiało być zakodowane w innym miejscu (około 06/0E/16/1E) tylko dlatego, że nie było miejsca obok reszty instrukcji push/pop.

Podobnie, " mod R / M" bajt używany w złożonej instrukcji MOV CX, [BX*4+BP+1023] ma tylko trzy bity do kodowania rejestru, co oznacza, że może reprezentować tylko osiem rejestrów. To jest w porządku, jeśli masz tylko osiem rejestrów, ale stanowi prawdziwy problem, jeśli chcesz mieć więcej.

(tutaj znajduje się doskonała mapa wszystkich alokacji bajtów w architekturze x86: http://i.imgur.com/xfeWv.png . Zauważ, że nie ma miejsca na mapie podstawowej, a niektóre instrukcje nakładają się na bajty, a nawet ile z drugiej mapy "0F" jest teraz używana dzięki instrukcjom MMX i SSE.)

W kierunku 32 i 64 bitów

Aby nawet umożliwić rozszerzenie projektu PROCESORA z 16 bitów do 32 bitów, mieli już problem projektowy i rozwiązali to za pomocą prefiksu bajtów: dodając specjalny bajt "66" przed wszystkimi standardowymi instrukcjami 16-bitowymi, procesor wie, że chcesz tę samą instrukcję, ale 32-bitową wersję (EAX) zamiast 16-bitowej instrukcji wersja (AX). Reszta projektu pozostała bez zmian: w ogólnej architekturze procesora nadal było tylko osiem rejestrów ogólnego przeznaczenia.

Podobne hackery trzeba było zrobić, aby rozszerzyć architekturę do 64-bitów (RAX i przyjaciele); tam problem został rozwiązany przez dodanie kolejnego zestawu kodów prefiksowych (REX, 40-4F), które oznaczało " 64-bit "(i skutecznie dodano kolejne dwa bity do pola "mod r / m"), a także odrzucenie dziwnych starych instrukcji, których nikt nigdy nie używał i ponowne użycie ich kody bajtowe dla nowszych rzeczy.

Zapis na rejestrach 8-bitowych

Jednym z większych pytań, które należy zadać, jest to, jak do cholery rzeczy takie jak AH i AL kiedykolwiek działało na pierwszym miejscu, jeśli w projekcie jest tylko miejsce na osiem rejestrów. Pierwsza część odpowiedzi jest taka, że nie ma czegoś takiego jak "PUSH AL" - niektóre instrukcje po prostu nie mogą w ogóle operować na rejestrach o wielkości bajtów! Jedyne, które mogą to kilka specjalnych dziwactw (jak AAD i XLAT) i specjalne wersje instrukcji "mod r/M": mając bardzo specyficzny bit w bajcie" mod r / m", te" rozszerzone instrukcje " mogą być odwrócone, aby operować na 8-bitowych rejestrach zamiast na 16-bitowych. Tak się składa, że jest dokładnie osiem rejestrów 8-bitowych: AL, CL, DL, BL, AH, CH, DH I BH (w tej kolejności), a to bardzo ładnie łączy się z ośmioma slotami rejestrów dostępnymi w bajcie "mod r/m".

Intel zauważył wówczas, że konstrukcja 8086 miał być "zgodny ze źródłami" z 8080/8085: w 8086 była równoważna instrukcja dla każdej z instrukcji 8080/8085, ale nie używała tych samych kodów bajtowych (nie są nawet blisko), i trzeba było przekompilować (ponownie zmontować) swój program, aby mógł używać nowych kodów bajtowych. Ale "kompatybilność ze źródłami" była drogą naprzód dla starego oprogramowania i pozwalała na indywidualne A, B, C itp. i kombi" BC "i" DE " rejestry nadal pracować na nowym procesorze, nawet jeśli były teraz nazywane " AL " i " BL "oraz" BX " i " DX "( czy czymkolwiek było mapowanie).

Więc to jest naprawdę prawdziwa odpowiedź: nie chodzi o to, że Intel czy AMD celowo "pominęli" wysoki 16-bitowy rejestr dla EAX, czy wysoki 32-bitowy rejestr dla RAX: chodzi o to, że wysokie 8-bitowe rejestry są dziwną pozostałością historycznej anomalii, a powielanie ich konstrukcji przy wyższych rozmiarach bitów byłoby naprawdę trudne, biorąc pod uwagę wymóg, aby architektura była kompatybilna wstecz.

A Performance Rozważanie

Jest jeszcze jedna kwestia, dlaczego te "wysokie rejestry" nie zostały dodane od tego czasu: we współczesnych architekturach procesorów, ze względu na wydajność, rejestry o różnej wielkości nie nakładają się na siebie w rzeczywistości: AH i AL nie są częścią AX, AX nie jest częścią EAX, a EAX nie jest częścią RAX: wszystkie są oddzielnymi rejestrami pod maską, a procesor ustawia flagę unieważnienia na innych, gdy manipulujesz jednym z nich, tak aby nie było problemu. wie, że będzie musiał skopiować dane, gdy czytasz od innych.

(na przykład: jeśli ustawisz AL = 5, procesor nie aktualizuje AX. Ale jeśli potem odczytasz z AX, procesor szybko skopiuje to 5 z AL do dolnych bitów AX.)

Zachowując oddzielne rejestry, procesor może wykonywać różne sprytne rzeczy, takie jak niewidzialna zmiana nazwy rejestru, aby Kod działał szybciej, ale oznacza to, że Twój kod działa wolniej , jeśli używasz starego schematu leczenia małe rejestry jako kawałki większych rejestrów, ponieważ procesor będzie musiał je opóźnić i zaktualizować. Aby nie wymknąć się spod kontroli tej wewnętrznej księgowości, projektanci procesorów mądrze zdecydowali się dodać oddzielne rejestry na nowszych procesorach, zamiast dodawać więcej nakładających się rejestrów.

(i tak, oznacza to, że na nowoczesnych procesorach jest naprawdę szybciej "MOVZX EAX, value", niż robić to w stary, niechlujny sposób "MOV AX, value / use EAX".)

Wniosek

Czy Intel i AMD mogą dodać więcej "nakładających się" rejestrów, jeśli naprawdę tego chcą? Jasne. Są sposoby, aby je wmieszać, jeśli było wystarczająco dużo popytu. Ale biorąc pod uwagę znaczący bagaż historyczny, obecne ograniczenia architektoniczne, znaczące ograniczenia wydajności i fakt, że większość kodu w dzisiejszych czasach jest generowana przez kompilatory zoptymalizowane pod kątem nie nakładających się rejestrów, jest bardzo mało prawdopodobne, że dodadzą takie rzeczy w najbliższym czasie.
 25
Author: Sean Werkema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-09 06:32:34