Architektura
procesorów x86
Język Assembly x86 jest nierozłącznie
związany z architekturą procesorów, na których jest wykonywany. Poznanie
możliwości i sposób działania procesora pozwala na lepszą naukę programowania i
zrozumienie działania programu.
Budowa komputera
Podstawowymi
jednostkami wchodzącymi w skład procesora są:
- Jednostka kontrolna (CU, control unit) – Jest jednym z elementów procesora (CPU), steruje jego działaniem oraz określa zachowanie na poszczególne instrukcje programu, określa przepływ danych między procesorem a jego podjednostkami. Jednostka kontrolka nie wykonuje poszczególnych instrukcji, a kieruje ich wykonaniem w odpowiednich jednostkach procesora.
- Jednostka arytmetyczna (ALU, arithmetic logic unit) – jest to układ wewnątrz procesora służący do wykonywania operacji arytmetycznych na liczbach całkowitych oraz operacji logicznych. ALU na swoje wejście przyjmuje słowa, na których zostaną wykonane działania, informacje o poprzednim wyniku oraz kod opisujący operację, która ma zostać wykonana na operandach. Zależnie od instrukcji, która jest wykonywana operandy mogą pochodzić z rejestrów procesora, pamięci zewnętrznej lub mogą być wygenerowane przez ALU. Po wykonaniu operacji, słowo wyjściowe pojawia się na wyjściu jednostki arytmetycznej. Wynik może być zapisany w rejestrze, pamięci oraz informacje o nim zapisywane są w specjalnym rejestrze.
- Zegar (clock) – Procesory są urządzeniami synchronicznymi co oznacza, że do swojej pracy potrzebują sygnału synchronizującego. Jest to fala prostokątna o naprzemiennych wartościach 0 i 1. Sygnał synchronizujący generowany jest przez zewnętrzny oscylator. Częstotliwość zegara określa szybkość z jaką procesor wykonuje rozkazy. Warto zaznaczyć, że okres sygnału z zegara musi być dłuższy niż czas potrzebny na propagację sygnałów w procesorze.
Transportem
informacji między elementami procesora zajmują się magistrale. Komputer ma
zazwyczaj cztery rodzaje magistral: danych, wejścia/wyjścia, sterowania,
adresowania. Magistrala danych przenosi instrukcje i dane między procesorem a
pamięcią. Magistrala wejścia/wyjścia między procesorem a urządzeniami
wejściowymi/wyjściowymi. Zadaniem magistrali sterującej jest transport sygnałów
synchronizujących wszystkie urządzenia do niej podpięte takie jak pamięć oraz
urządzenia wejściowe/wyjściowe. Magistrala adresowa przenosi adresy instrukcji
i danych.
Cykl wykonania instrukcji
Jest
to zbiór podstawowych zadań, które pozwalają komputerowi na wykonanie programu.
Podczas tego procesu komputer pobiera instrukcję z pamięci, określa niezbędne
akcje potrzebne do jej wykonania i je przeprowadza. Ten cykl jest powtarzany w
komputerze od momentu jego uruchomienia do momentu zamknięcia. W prostych
procesora cykl ten jest sekwencyjny, każda z instrukcji jest wykonana zanim
rozpocznie się kolejna. W większości nowych procesorów cykl wykonania jest
równoległy, ponieważ możliwe jest współbieżne wykonywania instrukcji dzięki
mechanizmowi potokowości.
Do
przeprowadzenia tego cyklu procesor wykorzystuje następujące jednostki:
Licznik programu (PC) – licznik
przechowujący adres następnej instrukcji.
Rejestr adresu pamięci (MAR) –
przechowuje adres komórki pamięci, z której należy odczytać dane lub do niej
zapisać dane.
Rejestr danych pamięci (MDR) – rejestr
przechowujący dane pobrane z pamięci lub dane czekające na zapisanie do
pamięci. Znany jest również jako rejestr buforu pamięci.
Rejestr instrukcji (IR) – miejsce
tymczasowego przechowania instrukcji, która została pobrana z pamięci.
Jednostka sterująca (CU) – dekoduje
instrukcję zapisaną w IR i kieruję dalszym jej wykonaniem.
Jednostka arytmetyczno logiczna (ALU) –
wykonuje działania arytmetyczne i logiczne.
Cykl
ten można podzielić na następujące fazy:
Pobranie instrukcji: Kolejna instrukcja
jest pobierana z licznika programu (PC) i zapisywana do rejestru instrukcji.
Pod koniec pobierania instrukcji licznik programu wskazuje na następna
instrukcję czekająca na wykonanie.
Dekodowanie instrukcji: Podczas tego
cyklu zakodowana instrukcji w rejestrze instrukcji jest interpretowana przez
dekoder.
Odczytanie adresu efektywnego: w
przypadku instrukcji pamięci (bezwzględna, względna) faza wykonania nastąpi w
następnym cyklu. Jeżeli instrukcja ma adres względny to adres efektywny jest
odczytywany z pamięci wraz ze wszystkimi danymi, na których wykonywana jest
operacja a następnie odczytane dane przenoszone są do rejestru danych. Jeżeli
instrukcja jest bezwzględna nic nie jest wykonywana podczas tego cyklu zegara.
Jeżeli jest to operacja wejścia/wyjścia lub operacja rejestru to jest ona
wykonywana podczas tego cyklu zegara.
Wykonanie instrukcji: Jednostka
sterująca procesora przekazuje zdekodowane dane jako sekwencja sygnałów do
poszczególnych układów funkcjonalnych procesora w celu wykonania. Wynik tego
działania przechowywany jest w pamięci lub wysyłany do urządzenia wyjściowego.
Ze względu na wynik wykonania instrukcji licznik programu może być ustawiony na
inny adres.
Odczyt z pamięci
Komputerom
odczyt z pamięci zajmuje więcej czasu niż odczyt z wewnętrznych rejestrów. W
celu odczytania danych z pamięci, procesor musi podjąć następujące działania.
- Umieszczenie adresu na magistrali adresowej
- Ustawienie procesora w tryb odczytu pamięci
- Odczekanie cyklu zegara w oczekiwaniu na odpowiedź pamięci
- Skopiowanie danych z magistrali do miejsca docelowego
Pamięć
to element, który mocno spowalnia wykonywanie programu. Od szybkości odczytywania
instrukcji zależy czy procesor będzie mógł bez opóźnień je wykonywać. W tym
celu inżynierowie opracowali pamięć cache. W pierwotnych procesorach wyróżnia
się jej dwa rodzaje.
- Level-1 cache – pamięć cache umieszczona bezpośrednio w rdzeniu procesora
- Level-2 cache – pamięć cache współdzielona między wszystkimi rdzeniami
Pamięć
cache jest szybsza od zwykłej pamięci DRAM, wynika to z jej budowy, jest to
pamięć typu static RAM, która w przeciwieństwie do pamięci dynami RAM nie
wymaga odświeżania zawartości komórek.
Wykonanie programu
Żeby
program mógł zostać wykonany to w pierwszej kolejności musi zostać załadowany do
pamięci, odpowiada za to loader – jeden z elementów systemu operacyjnego.
Proces
załadowania programu wygląda w następujący sposób:
- Podczas uruchamiania programu z wiersza poleceń loader wyszukuje nazwę pliku w obecnym folderze, jeżeli go nie znajdzie to szuka programu w ścieżkach zdefiniowanych w zmiennych środowiska, jeżeli go nie znajdzie to zwraca błąd. W przypadku uruchamiania programu z interfejsu graficznego uzyskaniem ścieżki zajmuje się explorer.exe
- Po odnalezieniu programu loader odczytuje rozmiar pliku, uprawnienia i inne atrybuty
- Następuje sprawdzenie czy użytkownik ma uprawnienia do wykonania programu
- Loader wyszukuje wolny adres w pamięci na załadowanie programu, alokuje dla niego miejsce i go kopiuje do pamięci. Uzupełniana jest tablica deskryptorów, na stos kopiowane są argumenty uruchomienia, wskaźnikom wewnątrz programu nadawane są odpowiednie wartości
- Rozpoczyna się wykonywanie pierwszej instrukcji programu, nadawany jest procesowi jego identyfikator.
Tryby pracy procesora
Procesory
z rodziny x86 mogą pracować w różnych trybach, o to ich krótkie opisy:
Tryb
rzeczywisty – w tym trybie, procesor pracuje tak jak Intel 8086. Ten tryb nie
zapewnia ochrony pamięci przed użyciem przez inny proces oraz nie zapewnia
obsługi wielozadaniowości. W tym trybie pracowały programy w systemie DOS. Adres
logiczny w tym trybie składa z dwóch 16-bitowych liczb, numeru segmentu oraz
przemieszczenia względem początku segmentu. Pozwala na zaadresowanie 1088 kB.
Tryb
chroniony – jest to natywny tryb procesora, nie jest on w żaden sposób
ograniczony. Programy dostają własną przestrzeń adresową, a procesor chroni
każdą przestrzeń przed dostępem do niej z obcego procesu. Funkcję tę realizuje
jednostka zarządzania pamięcią (MMU, memory management unit) Pozwala na zaadresowanie
pamięci przekraczającej 1 MB. Procesor
pracujący w trybie chronionym wykorzystuje mechanizm segmentacji. W 16-bitowych
rejestrach segmentu przechowuje selektory wskazujące tablicę deskryptorów i
deskryptor w tej tablicy. Deskryptor Opisuje położenie i właściwości segmentu
pamięci.
Tryb
wirtualny – ten tryb dostępny jest w trybie chronionym, umożliwia uruchamianie programów
przeznaczonych dla trybu rzeczywistego i symuluje pracę procesora Intel 8086.
Ten tryb wykorzystywany jest do uruchamiania programów dla systemu DOS na
nowszych systemach. 64 bitowe systemy Windows nie mają zaimplementowanej
obsługi takiego trybu.
Tryb
zarządzania systemem – to tryb pracy systemu, w którym wykonanie wszystkich
programów zostaje zawieszone, a kontrolę uzyskuje specjalne oprogramowanie.
Przestrzeń adresowa
Standardowo
32-bitowy system operacyjny daje możliwość zaadresowania do 4 GB pamięci.
Częściowo ograniczenie to znosi rozszerzenie Physical Extended Adressing, które
umożliwia zaadresowanie do 64 GB pamięci fizycznej. 32 bitowy adres pamięć
zostaje rozszerzony do 36 bitowego. Pamięć wirtualna dla danego procesu nie
jest zwiększana i nadal wynosi maksymalnie 4 GB.
Rejestry
Rejestry
to elementy procesora służące do przechowywania danych.
Podstawowe
rejestry w 32 bitowym trybie pracy:
32 bitowe rejestry
ogólnego przeznaczenia
|
|||
EAX
|
EBP
|
||
EBX
|
ESP
|
||
ECX
|
ESI
|
||
EDX
|
EDI
|
||
Rejestry specjalne
|
16 bitowe rejestry
segmentu
|
||
EFLAGS
|
CS
|
ES
|
SS
|
EIP
|
FS
|
DS
|
GS
|
Rejestry
ogólnego przeznaczenia są głównie używane przy wykonywaniu działań
matematycznych i przenoszeniu danych. Rejestry te dzielą się na mniejsze
części.
32 bity
|
16 bitów
|
8 bitów (górne)
|
8 bitów (dolne)
|
EAX
|
AX
|
AH
|
AL
|
EBX
|
BX
|
BH
|
BL
|
ECX
|
CX
|
CH
|
CL
|
EDX
|
DX
|
DH
|
DL
|
32 bity
|
16 bitów
|
ESI
|
SI
|
EDI
|
DI
|
EBP
|
BP
|
ESP
|
SP
|
Niektóre
z rejestrów mają z góry określone użycie.
EAX –
automatycznie używany przez instrukcje mnożenia i dzielenia.
ECX –
wykorzystywany jako licznik pętli.
ESP –
przechowuje adresy danych na stosie.
ESI,
EDI – wykorzystywane przez intrukcje transferu danych.
EBP –
wykorzystywany przez języki programowania wysokiego poziom do referencji
parametrów funkcji i zmiennych lokalnych na stosie.
Rejestry
segmentowe w trybie rzeczywistym wskazują adres bazowy segmentu. W trybie
chronionym przechowują wskaźniki na tablice deskryptorów. Niektóre segmenty
przechowują kod wykonywalny, inne zmienne, a segment stosu przechowuje lokalne
zmienne i parametry funkcji.
Wskaźnik
instrukcji EIP przechowuje adres kolejnej instrukcji czekającej na wykonanie.
Rejestr
EFLAGS przechowuje flagi opisujące wynik pracy procesora oraz właściwości
wykonanych przez niego instrukcji.
Flagi
kontrolne decydują o pracy procesora. Pogramy mogą ustawiać poszczególne flagi
w rejestrze EFLAGS by sterować działaniem procesora.
Flagi
statusu opisują wynik operacji arytmetycznych i logicznych wykonanych przez
procesor. Wyróżnia się flagi:
Carry flag (CF), ustawiona jest na
wartość 1 kiedy wynik działania na licznie całkowitej jest zbyt duży, żeby
zmieścić się w miejscu docelowym
Overflow flag (OF), ustawiona jest na
wartość 1 kiedy wynik działania na liczbie naturalnej jest zbyt duży, żeby zmieścić
się w miejscu docelowym
Sign flag (SF), ustawiona jest na
wartość 1 kiedy wynik działania jest ujemny
Zero flag (ZF), ustawiony jest na
wartość jeden kiedy wynik działania wynosi 0
Auxiliary Carry (AC), ustawiony jest na
wartość 1 kiedy działanie spowoduje przeniesienie trzeciego bitu do czwartego w
8 bitowym operandzie
Parity flag (PF) ustawiona jest na 1
kiedy wynik zawiera parzystą liczbę jedynek
Jednostka zmiennoprzecinkowa
Jest
to element procesora wykorzystywany przy działaniach na liczbach zmiennoprzecinkowych. Zawiera własne rejestry.
80 bitów
|
48 bitów
|
ST(0)
|
Wskaźnik instrukcji
FPU
|
ST(1)
|
|
ST(2)
|
Wskaźnik danych FPU
|
ST(3)
|
|
ST(4)
|
16 bitowe rejestry
kontrolne
|
ST(5)
|
Tag register
|
ST(6)
|
Rejestr kontrolny
|
ST(7)
|
Rejestr statusu
|
x86-64
Procesory
64-bitowe wykorzystują zestaw instrukcji x86-64. Cechy 64 bitowych procesorów
tej architektury:
- Zapewniają kompatybilność wsteczną dla instrukcji x86
- Mogą wykorzystywać 64-bitowe adresowanie pamięci.
- Udostępniają 64-bitowe rejestry ogólnego przeznaczenia
- Udostępniają osiem dodatkowych rejestrów ogólnego przeznaczenia
Dostępne
rejestry
Rozmiar
|
Rejestr
|
8 bitów
|
AL, BL, CL, DL, DIL, SIL, BPL, SPL, R8L, R9L,
R10L, R11L, R12L, R13L, R14L, R15L
|
16 bitów
|
AX, BX, CX, DX, DI,
SI, BP, SP, R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W
|
32 bity
|
EAX, EBX, ECX, EDX,
EDI, ESI, EBP, ESP, R8D, R9D, R10D, R11D, R12D, R13D, R14D, R15D
|
64 bity
|
RAX, RBX, RCX, RDX,
RDI, RSI, RBP, RSP, R8, R9 R10, R11, R12, R13, R14, R15
|
Niestety ja się na programowaniu za bardzo nie znam, jednak chętnie wykorzystuję różnego rodzaju aplikacje pomagające mi w prowadzeniu firmy. Na pewno jednym z nich jest system CRM https://www.connecto.pl/system-crm-poprawia-relacje-z-klientem/ który wspomaga mnie w budowaniu relacji z moimi klientami.
OdpowiedzUsuńSuper wpis. Pozdrawiam i czekam na więcej.
OdpowiedzUsuńBardzo fajny artykuł. Jestem pod wrażeniem.
OdpowiedzUsuń