Intel x86 Assembly Language & Microarchitecture
Zarejestruj podstawy
Szukaj…
Rejestry 16-bitowe
Kiedy Intel zdefiniował oryginalny model 8086, był to 16-bitowy procesor z 20-bitową szyną adresową (patrz poniżej). Zdefiniowali 8 rejestrów 16-bitowych ogólnego przeznaczenia - ale nadali im określone role dla niektórych instrukcji:
-
AXRejestr akumulatorów.
Wiele kodów operacyjnych albo przyjmowało ten rejestr, albo było szybszych, jeśli został określony. -
DXRejestr danych.
Czasami było to łączone jako wysokie 16 bitów 32-bitowej wartości zAX- na przykład w wyniku zwielokrotnienia. -
CXRejestr rejestru.
Zostało to wykorzystane w szeregu instrukcji zorientowanych na pętlę jako domyślny licznik dla tych pętli - na przykładLOOPNE(pętla, jeśli nie jest równa) iREP(powtarzany ruch / porównanie) -
BXRejestr podstawowy.
Można to wykorzystać do indeksowania podstawy struktury w pamięci - żaden z powyższych rejestrów nie może być użyty do bezpośredniego indeksowania do pamięci. -
SIRejestr indeksu źródłowego.
Był to domyślny indeks źródła do pamięci dla niektórych operacji przenoszenia i porównywania. -
DIRejestr indeksu celu podróży.
Był to domyślny indeks miejsca docelowego w pamięci dla niektórych operacji przenoszenia i porównywania. -
SPRejestr wskaźnika stosu.
Jest to najmniej rejestr ogólnego przeznaczenia w zestawie! Wskazywał na bieżącą pozycję na stosie, która została jawnie użyta do operacjiPUSHiPOP, domyślnie dlaCALLiRETz podprogramami oraz BARDZO niejawnie podczas przerwań. Używanie go do wszystkiego innego było niebezpieczne dla twojego programu! -
BPRejestr wskaźnika bazowego.
Kiedy podprogramy wywołują inne podprogramy, stos zawiera wiele „ramek stosu”.BPmożna wykorzystać do przechowywania bieżącej ramki stosu, a następnie, gdy zostanie wywołany nowy podprogram, można go zapisać na stosie, utworzyć nową ramkę stosu i użyć, a po powrocie z wewnętrznego podprogramu można przywrócić starą wartość ramki stosu .
Uwagi:
Pierwsze trzy rejestry nie mogą być używane do indeksowania do pamięci.
BX,SIiDIdomyślnie indeksują do bieżącego segmentu danych (patrz poniżej).MOV AX, [BX+5] ; Point into Data Segment MOV AX, ES:[DI+5] ; Override into Extra SegmentDI, gdy jest stosowany w operacjach typu pamięć-pamięć, takich jakMOVSiCMPS, używa wyłącznie dodatkowego segmentu (patrz poniżej). Tego nie można zastąpić.SPiBPdomyślnie używają segmentu stosu (patrz poniżej).
Rejestry 32-bitowe
Kiedy Intel wyprodukował 80386, zaktualizował z 16-bitowego procesora do 32-bitowego. Przetwarzanie 32-bitowe oznacza dwie rzeczy: oba manipulowane dane były 32-bitowe, a adresy pamięci, do których uzyskiwano dostęp, były 32-bitowe. Aby to zrobić, ale nadal pozostają kompatybilne ze swoimi wcześniejszymi procesorami, wprowadzono zupełnie nowe tryby dla procesora. Był w trybie 16-bitowym lub 32-bitowym - ale można było zmienić ten tryb na zasadzie instrukcja po instrukcji dla danych, adresowania lub obu!
Przede wszystkim musieli zdefiniować rejestry 32-bitowe. Zrobili to, po prostu rozszerzając istniejące osiem z 16 bitów na 32 bity i nadając im „rozszerzone” nazwy z prefiksem E : EAX , EBX , ECX , EDX , ESI , EDI , EBP i ESP . Dolne 16 bitów tych rejestrów było takich samych jak poprzednio, ale górne połowy rejestrów były dostępne dla operacji 32-bitowych, takich jak ADD i CMP . Górne połówki nie były osobno dostępne, tak jak w przypadku rejestrów 8-bitowych.
Procesor musiał mieć osobne tryby 16-bitowe i 32-bitowe, ponieważ Intel używał tych samych kodów operacyjnych dla wielu operacji: CMP AX,DX w trybie 16-bitowym i CMP EAX,EDX w trybie 32-bitowym miały dokładnie te same kody ! Oznaczało to, że ten sam kod NIE może być uruchomiony w żadnym trybie:
Kod operacji „Przenieś natychmiast do
AX” to0xB8, po którym następują dwa bajty wartości bezpośredniej:0xB8 0x12 0x34
Kod operacji „Przenieś natychmiast do
EAX” to0xB8, po którym następują cztery bajty wartości bezpośredniej:0xB8 0x12 0x34 0x56 0x78
Tak więc asember musi wiedzieć, w jakim trybie jest procesor podczas wykonywania kodu, aby mógł wyemitować prawidłową liczbę bajtów.
Rejestry 8-bitowe
Pierwsze cztery rejestry 16-bitowe mogą mieć dostęp do swojej górnej i dolnej połowy bajtów bezpośrednio jako własne rejestry:
-
AHiALsą górnymi i dolnymi połówkami rejestruAX. -
BHiBLsą górną i dolnąBXrejestruBX. -
CHiCLto górne i dolne połowy rejestruCX. -
DHiDLsą górnymi i dolnymi połówkami rejestruDX.
Pamiętaj, że oznacza to, że zmiana AH lub AL natychmiast zmieni również AX ! Zauważ też, że jakakolwiek operacja na 8-bitowym rejestrze nie może wpłynąć na jego „partnera” - zwiększenie AL tak, że przepełnienie z 0xFF do 0x00 nie zmieni AH .
Rejestry 64-bitowe mają również wersje 8-bitowe reprezentujące ich niższe bajty:
-
SILdlaRSI -
DILdlaRDI -
BPLdlaRBP -
SPLdlaRSP
To samo odnosi się do rejestrów R8 przez R15 : ich odpowiednie części niższy bajt są nazwane R8B - R15B .
Rejestry segmentów
Segmentacja
Kiedy Intel projektował oryginalny model 8086, istniało już kilka 8-bitowych procesorów, które miały 16-bitowe możliwości - ale chcieli stworzyć prawdziwy 16-bitowy procesor. Chcieli także stworzyć coś lepszego i bardziej wydajnego niż to, co już tam było, więc chcieli mieć dostęp do więcej niż 65 656 bajtów pamięci sugerowanych przez 16-bitowe rejestry adresujące.
Oryginalne rejestry segmentów
Dlatego wdrożyli ideę „Segmentów” - 64-kilobajtowego bloku pamięci indeksowanego przez 16-bitowe rejestry adresowe - który może być ponownie oparty na różnych obszarach całej pamięci. Aby przechowywać te bazy segmentów, uwzględniono rejestry segmentów:
-
CSRejestr segmentu kodu.
Zawiera on aktualnie wykonywany segment kodu, indeksowany przez niejawny rejestrIP(wskaźnik instrukcji). -
DSRejestr segmentu danych.
Przechowuje domyślny segment danych przetwarzanych przez program. -
ESRejestr Extra Segment.
Zawiera drugi segment danych, dla jednoczesnych operacji danych w całej pamięci. -
SSRejestr segmentu stosu.
Przechowuje segment pamięci, który przechowuje aktualny stos.
Rozmiar segmentu?
Rejestry segmentowe mogą mieć dowolny rozmiar, ale ich szerokość 16 bitów ułatwia współpracę z innymi rejestrami. Następne pytanie brzmiało: czy segmenty powinny się pokrywać, a jeśli tak, to w jakim stopniu? Odpowiedź na to pytanie określałaby całkowity rozmiar pamięci, do którego można uzyskać dostęp.
Gdyby w ogóle nie zachodziło na siebie, przestrzeń adresowa wynosiłaby 32 bity - 4 gigabajty - wówczas zupełnie niespotykany rozmiar! Bardziej „naturalne” nakładanie się 8 bitów zapewni 24-bitową przestrzeń adresową lub 16 megabajtów. Ostatecznie Intel postanowił zapisać cztery dodatkowe piny adresowe na procesorze, czyniąc przestrzeń adresową 1 megabajtową z 12-bitowym nakładaniem się - uważali to za wystarczająco duże jak na razie!
Więcej rejestrów segmentów!
Kiedy Intel projektował 80386, zdali sobie sprawę, że istniejący pakiet 4 rejestrów segmentowych nie wystarcza do złożoności programów, które chcieli, aby mógł on obsługiwać. Dodali więc jeszcze dwa:
-
FSRejestr dalekiego segmentu -
GSRejestr segmentu globalnego
Te nowe rejestry segmentów nie miały zastosowania wymuszonego przez procesor: były dostępne tylko dla wszystkiego, czego chciał programista.
Niektórzy twierdzą, że nazwy zostały wybrane, aby po prostu kontynuować motyw
C,D,Eistniejącego zestawu ...
Rejestry 64-bitowe
AMD jest producentem procesorów, który uzyskał licencję na projekt 80386 od Intela, aby produkować kompatybilne - ale konkurencyjne - wersje. Wprowadzili wewnętrzne zmiany w projekcie, aby poprawić przepustowość lub inne ulepszenia w projekcie, wciąż będąc w stanie wykonywać te same programy.
Dla pojedynczego Intela wymyślili 64-bitowe rozszerzenia do 32-bitowej konstrukcji Intela i stworzyli pierwszy 64-bitowy układ, który nadal może uruchamiać 32-bitowy kod x86. Intel skończył zgodnie z projektem AMD w swoich wersjach architektury 64-bitowej.
Wersja 64-bitowa wprowadziła szereg zmian w zestawie rejestrów, jednocześnie zachowując zgodność z poprzednimi wersjami:
- Istniejące rejestry ogólnego przeznaczenia zostały rozszerzone do 64 bitów i nazwane prefiksem
R:RAX,RBX,RCX,RDX,RSI,RDI,RBPiRSP.Ponownie, dolne połówki tych rejestrów były tymi samymi rejestrami z prefiksem
Ejak poprzednio, a górne połówki nie były dostępne niezależnie. - Dodano jeszcze 8 rejestrów 64-bitowych, które nie zostały nazwane, lecz jedynie ponumerowane:
R8,R9,R10,R11,R12,R13,R14iR15.- 32-bitowa niska połowa tych rejestrów to
R8DdoR15D(D dla DWORD jak zwykle). - Dostęp do najniższych 16 bitów tych rejestrów można uzyskać, dodając
Wdo nazwy rejestru: odR8WdoR15W.
- 32-bitowa niska połowa tych rejestrów to
- Można teraz uzyskać dostęp do najniższych 8 bitów ze wszystkich 16 rejestrów:
- Tradycyjne
AL,BL,CLiDL; - Niskie bajty (tradycyjnie) rejestrów wskaźników:
SIL,DIL,BPLiSPL; - Oraz niski bajtach 8 nowych rejestrów:
R8BprzezR15B. - Jednak
AH,BH,CHiDHsą niedostępne w instrukcjach, które używają prefiksu REX (dla 64-bitowego rozmiaru argumentu lub dostępu do R8-R15 lub dostępu doSIL,DIL,BPLlubSPL). W przypadku prefiksu REX wzorzec bitów kodu maszynowego, który kiedyś oznaczałAHoznacza zamiast tegoSPLi tak dalej. Patrz Tabela 3-1 instrukcji obsługi instrukcji Intela (tom 2).
- Tradycyjne
Zapis do rejestru 32-bitowego zawsze zeruje górne 32 bity rejestru o pełnej szerokości, w przeciwieństwie do zapisu do rejestru 8 lub 16-bitowego (który łączy się ze starą wartością, co stanowi dodatkową zależność przy wykonywaniu poza kolejnością ).
Rejestr flag
Gdy jednostka arytmetyczna logiczna x86 (ALU) wykonuje operacje takie jak NOT i ADD , oznacza wyniki tych operacji („stała się zero”, „przepełniona”, „stała się ujemna”) w specjalnym 16-bitowym rejestrze FLAGS . 32-bitowe procesory zaktualizowały to do 32 bitów i nazwały to EFLAGS , podczas gdy 64-bitowe procesory zaktualizowały to do 64 bitów i nazwały to RFLAGS .
Kody warunków
Ale bez względu na nazwę, rejestr nie jest bezpośrednio dostępny (z wyjątkiem kilku instrukcji - patrz poniżej). Zamiast tego poszczególne flagi są SETcc w niektórych instrukcjach, takich jak Skok warunkowy lub Zestaw warunkowy, znany jako Jcc i SETcc gdzie cc oznacza „kod warunku” i odwołuje się do poniższej tabeli:
| Kod stanu | Nazwa | Definicja |
|---|---|---|
E , Z | Równa, zero | ZF == 1 |
NE , NZ | Nie równe, nie zero | ZF == 0 |
O | Przelewowy | OF == 1 |
NO | Bez przepełnienia | OF == 0 |
S | Podpisany | SF == 1 |
NS | Niepodpisany | SF == 0 |
P | Parytet | PF == 1 |
NP | Bez parzystości | PF == 0 |
| -------------- | ---- | ---------- |
C , B , NAE | Noś, poniżej, nie powyżej lub równy | CF == 1 |
NC , NB , AE | No Carry, Not Below, Above or Equal | CF == 0 |
A , NBE | Powyżej, nie poniżej lub równa | CF == 0 i ZF == 0 |
NA , BE | Not Above, Below lub Equal | CF == 1 lub ZF == 1 |
| --------------- | ---- | ---------- |
GE , NL | Większy lub równy, nie mniej | SF == OF |
NGE , L | Nie większy lub równy, mniej | SF ! = OF |
G , NLE | Większy, nie mniejszy lub równy | ZF == 0 i SF == OF |
NG , LE | Nie większy, mniejszy lub równy | ZF == 1 lub SF ! = OF |
W przypadku 16 bitów odjęcie 1 od 0 wynosi 65,535 lub -1 zależności od tego, czy użyta jest arytmetyka niepodpisana czy podpisana - ale miejsce docelowe zawiera 0xFFFF obu przypadkach. Znaczenie jest jasne tylko poprzez interpretację kodów warunków. Jeszcze bardziej wymowne jest to, czy 1 jest odejmowane od 0x8000 : w arytmetyki bez znaku, co zmienia jedynie 32,768 w 32,768 32,767 ; natomiast w podpisanej arytmetyki zmienia -32,768 do 32,767 - znacznie bardziej godne uwagi przepełnienie!
Kody warunków są pogrupowane w trzy bloki w tabeli: nieistotne dla znaku, niepodpisane i podpisane. Nazwy wewnątrz dwóch ostatnich bloków używają „Above” i „Below” dla niepodpisanych oraz „Greater” lub „Less” dla podpisanych. Zatem JB byłby „Jump if Below” (niepodpisany), podczas gdy JL byłby „Jump if Less” (podpisany).
Bezpośredni dostęp do FLAGS
Powyższe kody warunków są przydatne do interpretowania predefiniowanych pojęć, ale rzeczywiste bity flagi są również dostępne bezpośrednio z następującymi dwiema instrukcjami:
-
LAHFZaładuj rejestrAHz flagami -
SAHFStoreAHw Flags
Tylko niektóre flagi są kopiowane wraz z tymi instrukcjami. Cały EFLAGS FLAGS / EFLAGS / RFLAGS można zapisać lub przywrócić na stosie:
-
PUSHF/POPFWciśnij / pop 16-bitoweFLAGSna / ze stosu -
PUSHFD/POPFDPush / pop 32-bitoweEFLAGSna / ze stosu -
PUSHFQ/POPFQWciśnij / pop 64-bitoweRFLAGSna / ze stosu
Należy pamiętać, że przerwania automatycznie zapisują i przywracają bieżący rejestr [R/E]FLAGS .
Inne flagi
Oprócz flag ALU opisanych powyżej rejestr FLAGS definiuje inne flagi stanu systemu:
-
IFFlaga Przerwania.
Jest to ustawiane za pomocą instrukcjiSTIaby globalnie włączać przerwania, i usuwane za pomocą instrukcjiCLIaby globalnie wyłączać przerwania. -
DFFlaga kierunku.
Operacje pamięć-pamięć, takie jakCMPSiMOVS(w celu porównania i przemieszczania się między lokalizacjami pamięci) automatycznie zwiększają lub zmniejszają rejestry indeksu jako część instrukcji. FlagaDFokreśla, co się stanie: jeśli zostanie wyczyszczona instrukcjąCLD, są one zwiększane; jeśli ustawione za pomocą instrukcjiSTD, są zmniejszane. -
TFFlaga pułapki. To jest flaga debugowania. Ustawienie go spowoduje przejście procesora w tryb „jednoetapowy”: po wykonaniu każdej instrukcji wywoła „Single Step Interrupt Handler”, który powinien być obsługiwany przez debugger. Nie ma instrukcji, aby ustawić lub usunąć tę flagę: musisz manipulować bitem, gdy jest on w pamięci.
80286 Flagi
Aby wesprzeć nowe funkcje wielozadaniowości w 80286, Intel dodał dodatkowe flagi do rejestru FLAGS :
-
IOPLPoziom uprawnień we / wy.
Aby chronić kod wielozadaniowy, niektóre zadania wymagały uprawnień dostępu do portów we / wy, podczas gdy inne musiały być powstrzymywane przed dostępem do nich. Intel wprowadził czteropoziomową skalę przywilejów, przy czym002 jest najbardziej uprzywilejowany, a112 jest najmniejszy. JeśliIOPLbył niższy niż bieżący poziom uprawnień, każda próba dostępu do portów we / wy lub włączenia lub wyłączenia przerwań spowodowałaby ogólny błąd ochrony. -
NTZagnieżdżona flaga zadania.
Ta flaga została ustawiona jeśli jedno zadanieCALLed innego zadania, co spowodowało przełączenie kontekstu. Flaga set powiedziała procesorowi, aby wykonał zmianę kontekstu z powrotem, gdy wykonanoRET.
80386 Flagi
386 potrzebował dodatkowych flag do obsługi dodatkowych funkcji zaprojektowanych w procesorze.
-
RFFlaga wznowienia.
W `386 dodano rejestry debugowania, które mogą wywoływać debuger na różnych dostępach sprzętowych, takich jak czytanie, zapisywanie lub wykonywanie określonej lokalizacji pamięci. Jednak gdy program obsługi debugowania powróci w celu wykonania instrukcji, dostęp natychmiast ponownie uruchomi procedurę obsługi debugowania! A przynajmniej tak by było, gdyby nie flaga wznowienia, która jest automatycznie ustawiana przy wejściu do modułu obsługi debugowania i automatycznie usuwana po każdej instrukcji. Jeśli ustawiona jest flaga wznowienia, moduł obsługi debugowania nie jest wywoływany. -
VMFlaga Virtual 8086.
W celu obsługi starszego kodu 16-bitowego, a także nowszego kodu 32-bitowego, 80386 może uruchamiać 16-bitowe zadania w trybie „Virtual 8086” z pomocą programu wykonawczego Virtual 8086. FlagaVMwskazuje, że to zadanie było wirtualne 8086.
80486 Flagi
Wraz z poprawą architektury Intel, stała się szybsza dzięki takim technologiom, jak pamięci podręczne i wykonywanie super-skalarne. To musiało zoptymalizować dostęp do systemu, przyjmując założenia. Aby kontrolować te założenia, potrzebnych było więcej flag:
- Flaga kontroli wyrównania
ACArchitektura x86 zawsze mogła uzyskać dostęp do wielobajtowych wartości pamięci na dowolnej granicy bajtów, w przeciwieństwie do niektórych architektur, które wymagały wyrównania wielkości (wartości 4-bajtowe musiały znajdować się na granicach 4-bajtowych). Było to jednak mniej wydajne, ponieważ do uzyskania dostępu do niezrównanych danych potrzebnych było wiele dostępów do pamięci. Jeśli ustawiono flagęAC, niezaangażowany dostęp zgłosiłby wyjątek, zamiast wykonać kod. W ten sposób kod można ulepszyć podczas programowania przy użyciu zestawuAC, ale wyłączyć kod produkcyjny.
Flagi Pentium
Pentium dodało więcej obsługi wirtualizacji oraz wsparcie dla instrukcji CPUID :
-
VIFFlaga wirtualnego przerwania.
To jest wirtualna kopiaIFtego Zadania - niezależnie od tego, czy to Zadanie chce wyłączyć przerwania, bez faktycznego wpływu na Przerwania Globalne. -
VIPFlaga wirtualnego przerwania.
Oznacza to, że przerwanie zostało wirtualnie zablokowane przezVIF, więc gdy Zadanie wykonujeSTImożna dla niego wywołać przerwanie wirtualne. -
IDFlaga dozwolona przezCPUID.
Określa, czy zezwolić temu zadaniu na wykonanie instrukcjiCPUID. Monitor wirtualny może go zabronić i „okłamać” żądające Zadanie, jeśli wykona instrukcję.