Łączna liczba wyświetleń

wtorek, 23 lutego 2016

2. Kurs Asembler x86: Architektura procesorów x86

Autor Nauka Programowania  |  w x86  03:49


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





(Źródło: Wikipedia Lambtron CC BY-SA 4.0)

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.

  1. Umieszczenie adresu na magistrali adresowej
  2. Ustawienie procesora w tryb odczytu pamięci
  3. Odczekanie cyklu zegara w oczekiwaniu na odpowiedź pamięci
  4. 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


3 komentarze:

  1. 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ń
  2. Super wpis. Pozdrawiam i czekam na więcej.

    OdpowiedzUsuń
  3. Bardzo fajny artykuł. Jestem pod wrażeniem.

    OdpowiedzUsuń

Proudly Powered by Blogger.