Sztuka Grzebiąc Registers Intel


Original: http://www.swansontec.com/sregisters.html

Napisałem ten artykuł dla magazynu online o nazwie Zine Scene. Zine Scene zaspokaja Scena demo, która jest wspólnotą cyfrowa sztuka poświęcona przesuwanie granic komputerów poprzez połączenie muzyki, sztuki i programowania komputerowego. Szczególna kategoria demosceny produkcjach, intra 4K, skupić się na produkcji końcowej w surowej rozmiaru pliku. Celem jest ułożenie jak najwięcej wysokiej jakości muzykę, grafikę i animacje, jak to możliwe do tylko 4096 bajtów. Rozwiązanie to wymaga wysoko wyspecjalizowanych technik optymalizacji wielkości, od 4096 bajtów jest mniej miejsca niż dwie strony tekst maszynowy lub true-color Windows XP ikony. W tym artykule omówiono niektóre z tych technik.

Niektórzy pisali, że chcą, aby zobaczyć więcej artykułów programowych ekspertem w Zine sceny. Aby zaradzić tej sytuacji, ten artykuł jest dla wszystkich programistów asemblerowych tam. Omawia sztukę skubanie który rejestruje użyć w kodzie. Informacja ta powinna uprościć kodowania i pomóc zapisanie mniejszych procedur.

Kiedy inżynierowie Intel zaprojektował oryginalny 8086 procesor, mieli specjalny cel w umyśle każdego rejestru. Ponieważ zaprojektował zestaw instrukcji, stworzyli wiele optymalizacje i specjalne instrukcje w zależności od funkcji spodziewali każdy rejestr wykonać. Korzystanie z rejestrów według pierwotnego planu Intela pozwala kod do pełnego wykorzystania tych optymalizacje. Niestety, wydaje się, że stracił sztuki. Kilka koderzy mają świadomość ogólnej konstrukcji Intela, a większość kompilatory są zbyt uproszczone, albo koncentruje się na szybkości wykonania użyć rejestrów poprawnie. Zrozumienie, jak rejestry i zestaw instrukcji do siebie pasują, jednak jest to ważny krok na drodze do wysiłku rozmiar kodowania.

Używanie rejestrów konsekwentnie ma inne zalety oprócz optymalizacji wielkości. Jak za pomocą dobrych nazw zmiennych, przy wykorzystaniu spójnych rejestrów czyni kod bardziej czytelnym. Gdy są używane prawidłowo, rejestry mają znaczenie niemal tak jasne jak licznik pętli, i, w językach wyższego poziomu. W rzeczywistości, od czasu do czasu nazywać zmienne w C po rejestrów x86, ponieważ nazwy rejestrów są tak opisowe. Przy prawidłowym użytkowaniu rejestru, assembler x86 może być prawie tak samo-dokumentowanie jako język wysokiego poziomu.

Inną korzyścią, że konsekwentne stosowanie przynosi rejestr jest lepsza kompresja. W produkcjach wykorzystujących sprężarki spakować ostatecznej kompilacji, takich jak 4K intro, tworzenie bardziej nadmiarowy kod prowadzi do mniejszych opakowaniach rozmiarach. Kiedy kod używa konsekwentnie rejestruje te same sekwencje instrukcji zaczynają pojawiać się w kółko. To, z kolei, zwiększa współczynnik kompresji.

Jako przegląd, wszystkie x86-rodzina procesorów ma 8 rejestrów ogólnego przeznaczenia. Rejestry mają 32 bitów, choć 16-bitowe wersje są również dostępne ze specjalnym jeden bajt przedrostka instrukcji. W 16-bitowym trybie, sytuacja jest odwrotna. Niższe 16 bitów są dostępne domyślnie i pełne rejestry są dostępne tylko w bajcie prefiksu.

Każda nazwa rejestru jest naprawdę akronim. Dzieje się tak nawet na „alfabetycznie“ rejestry EAX, EBX, ECX i EDX. Poniższa lista przedstawia nazwy rejestru i ich znaczenie:

EAX – Accumulator Zarejestruj
EBX – rejestr bazowy
ECX – Counter Rejestracja
EDX – Dane Zarejestruj
ESI – Index Źródło
EDI – Destination Index
EBP – wskaźnik bazowy
ESP – wskaźnik stosu

Oprócz pełnowymiarowa ogólnych rejestrów x86 procesor ma również osiem bajt wielkości rejestrów. Ponieważ te rejestry map bezpośrednio do EAX, EBX, ECX, EDX i większość ludzi postrzega je jako części większych rejestrów. Z punktu widzenia rozkazów, jednak 8-bitowe rejestry są odrębnymi podmiotami. Na przykład, CL i CH rejestruje żadnej akcji właściwości przydatnych w rejestrze ECX. Wyjątkiem AL i AH, żaden z 8-bitowych rejestrów mają żadnego specjalnego znaczenia w zestaw instrukcji, więc ten artykuł nie wspomina o nich.
EAX: Akumulator

Istnieją trzy główne procesory o architekturze: Zarejestruj się, stos, i akumulator. W architekturze katastralnym, operacje takie jak dodawanie lub odejmowanie, może wystąpić pomiędzy dwoma rejestrami arbitralnych. W stosie architektury, operacje występują między szczycie stosu i innych elementów znajdujących się na stosie. W architekturze akumulatora, procesor posiada jedno obliczenie zarejestrować nazywa akumulator. Wszystkie obliczenia występują w akumulatorze, a inne działają rejestrów miejsc przechowywania danych prostych.

Oczywiście procesor x86 nie ma architekturę akumulatora. To jednak, masz akumulator-jak się zarejestrować: EAX / AL. Chociaż większość obliczeń może wystąpić pomiędzy dwoma rejestrami, zestaw instrukcji daje akumulator szczególną preferencję jako rejestru obliczeniowego. Na przykład, wszystkie dziewięć podstawowych operacji (ADD, ADC i, CMP, OR, SBB, SUB, test i XOR) mają specjalne jednobajtowe rozkazy do operacji pomiędzy akumulatorem i stałą. Specjalistyczne operacje, takie jak mnożenie, dzielenie, rozbudowy migowego i korektą BCD może nastąpić tylko w akumulatorze.

Ponieważ większość obliczeń występują w akumulatorze, architektura x86 zawiera wiele zoptymalizowanych instrukcje przenoszenia danych do iz tego rejestru. Aby rozpocząć, procesor ma szesnaście bajt wielkości rozkazy xchg dla wymiany danych pomiędzy akumulatorem i wszelkie innego rejestru. To nie są strasznie przydatne, ale pokazują jak silnie Intel inżynierowie preferowane akumulator nad innymi rejestrami. Dla nich to było lepiej, aby zamienić dane w akumulatorze do niż z nim pracować, gdzie to było. Inne instrukcje przenoszenia danych do iz akumulatora są LODS, STOS, IN, OUT, INS, out, Komitetu wysoko i XLAT. Wreszcie, instrukcja MOV ma specjalny jednobajtowych opcode do przenoszenia danych do akumulatora z pamięci stałej lokalizacji.

W kodzie, spróbuj wykonać tyle pracy w akumulatorze, jak to możliwe. Jak widać, pozostałe siedem uniwersalne rejestry istnieją przede wszystkim na wsparcie obliczeń występujące w akumulatorze.
EDX: Dane Zarejestruj

Z siedmiu pozostałych rejestrów ogólnego przeznaczenia, rejestr danych, EDX, jest najściślej związany z akumulatora. Instrukcje, które dotyczą ponad wielkości przesyłanych danych, takich jak mnożenie, dzielenie, CWD i CDQ przechowywać najbardziej znaczących bitów w danych rejestru i najmniej znaczących bitów w akumulatorze. W pewnym sensie, rejestr danych 64-bitowego rozszerzenie akumulatora. Rejestr danych odgrywa również rolę w instrukcji IO. W tym przypadku, akumulator przechowuje dane do odczytu lub zapisu z portu, i rejestr danych posiada portu adres.

W kodzie, rejestr danych jest najbardziej przydatna do przechowywania danych dotyczących obliczania akumulatora jest. Z mojego doświadczenia, większość obliczeń trzeba tylko te dwa rejestry do przechowywania, jeżeli są napisane poprawnie.
ECX: Hrabia Rejestracja

Ilość rejestr, ECX, jest x86 odpowiednik wszechobecnego zmiennej i. Każdy liczenia związane instrukcja w x86 używa ECX. Najbardziej oczywiste instrukcje liczenia są LOOP, loopz i LOOPNZ. Kolejny licznik bazie instrukcji jest JCXZ, które, jak sama nazwa wskazuje, skacze, gdy licznik jest 0. Ilość rejestr pojawia się również w niektórych bit przesunięcia operacji, gdy posiada liczbę zmian do wykonania. Wreszcie Ilość rejestr steruje instrukcji łańcuchów poprzez REP, REPE i REPNE prefiksów. W tym przypadku, liczba rejestr określa maksymalną liczbę powtarzających się operacji.

Szczególnie w demo większość obliczenia występują w pętli. W takich sytuacjach, ECX jest logicznym wyborem dla licznika pętli, ponieważ żaden inny rejestr ma tak wiele rozgałęzień operacji zbudowanych wokół niego. Jedynym problemem jest to, że ten rejestr liczy się w dół, a nie jak w językach wysokiego poziomu. Projektowanie dół liczenia nie jest trudne, jednak, więc jest to tylko drobne trudności.
EDI: Destination Index

Każda pętla generuje dane należy zapisać wynik w pamięci, a ten sposób wymaga ruchomy wskaźnik. Indeks przeznaczenia, EDI, jest to, że wskaźnik. Indeks przeznaczenia posiada dorozumianą adres zapisu wszystkich operacji łańcuchowych. Najbardziej przydatne wskazówki string, zadziwiająco mało, jest rzadko używane STOS. STOS kopiuje dane z akumulatora do pamięci i zwiększa indeks przeznaczenia. Ten jeden bajt instrukcji jest doskonały, ponieważ efekt końcowy obliczeniach powinna w każdym razie akumulatora i przechowywania wyników w poruszającym adres pamięci wspólnej zadaniem.

Wielu programistów traktują indeks docelowy nie więcej niż dodatkowe miejsca. To jest błąd. Wszystkie procedury muszą przechowywać dane, a niektóre Rejestr musi służyć jako wskaźnik pamięci. Ponieważ indeks docelowy jest przeznaczony dla tej pracy, używając go dla dodatkowego składowania jest odpadem. Używanie stosu lub inny rejestr do przechowywania i wykorzystania EDI jako globalnego wskaźnika zapisu.
ESI: Index Źródło

Indeks źródłem ESI, ma takie same właściwości jak w indeksie docelowego. Jedyną różnicą jest to, że wskaźnik jest do odczytu źródło zamiast pisać. Mimo, że wszystkie procedury przetwarzania danych, pisać, nie wszystko czytać, więc indeks źródło nie jest tak powszechnie użyteczne. Gdy nadejdzie czas używać jednak wskaźnik źródłem jest tak silne jak w indeksie docelowego i ten sam typ instrukcji.

W sytuacjach, w których nie jest kod odczytu jakichkolwiek danych, oczywiście za pomocą indeksu źródłowego dogodnym miejsca jest dopuszczalne.
ESP i EBP: wskaźnik stosu i wskaźnik bazowy

Z ośmiu rejestrów ogólnego przeznaczenia, tylko wskaźnik stosu, ESP, a wskaźnik bazowy, EBP, są szeroko stosowane w ich pierwotnym przeznaczeniem. Te dwa rejestry są sercem x86 Funkcja dyżurów mechanizmu. Kiedy blok kodu wywołuje funkcję, to wypycha parametry i adres zwrotny na stosie. Raz wewnątrz, funkcja ustawia wskaźnik bazowy równy wskaźnika stosu, a następnie umieszcza swoje wewnętrzne zmienne na stosie. Od tego momentu, funkcja odnosi się do jego parametrów i zmiennych w stosunku do wskaźnika bazowego, a nie wskaźnik stosu. Dlaczego wskaźnik stosu? Z jakiegoś powodu, wskaźnik stosu kiepskie tryby adresowania. W 16-bitowego, to nie może być kwadratowy przesunięcie wspornika pamięci ogóle. W trybie 32-bitowym, to może pojawić się w nawiasach kwadratowych, dodając tylko drogie bajt SIB dla kodu maszynowego.

W kodzie, nigdy nie powód, aby używać stosu wskaźnik do czegokolwiek innego niż stosu. Wskaźnik podstawy, jednak jest do wzięcia. Jeśli procedury przekazywania parametrów przez zarejestrować zamiast przez stos (powinny), nie ma powodu, aby skopiować stos wskaźnik do wskaźnika bazowego. Wskaźnik podstawy staje się wolny rejestr czegokolwiek potrzebujesz.
EBX: rejestr bazowy

W trybie 16-bitowym, baza rejestr, EBX, działa jako wskaźnik ogólnego przeznaczenia. Oprócz specjalistycznego ESI, EDI, EBP i rejestrów, nie jest tylko rejestr ogólnego przeznaczenia, które mogą pojawić się w kwadratowym uchwytem dostępu do pamięci (np. MOV [BX], AX). W świecie 32-bitowym, jednakże każdy rejestr może służyć jako pamięci przesunięcia, więc rejestr bazowy nie jest wyjątkowa.

Rejestr bazowy dostaje swoją nazwę od XLAT instrukcji. XLAT wyszukuje wartość w tabeli za pomocą AL indeksu i EBX jako podstawy. XLAT odpowiada MOV AL, [BX + AL], co jest czasami przydatne, jeśli trzeba zastąpić jeden 8-bitową wartość z inną z tabeli (Pomyśl o kolorze look-up).

Więc wszystkich rejestrów ogólnego przeznaczenia, EBX jest tylko rejestr bez ważnego celu dedykowany. Jest to dobre miejsce do przechowywania dodatkowych wskaźnik lub krok obliczeń, ale nie wiele więcej.
Konkluzja

Osiem rejestrów ogólnego przeznaczenia w rodzinie procesorów x86 każda posiada niepowtarzalny cel. Każdy rejestr ma specjalne instrukcje i rozkazy, które sprawiają, spełnienie tego celu bardziej wygodne i efektywne. Rejestry i ich zastosowania są przedstawione pokrótce poniżej:

EAX – Wszystkie główne obliczenia odbywają się w EAX, co czyni go podobnym do dedykowanego akumulatora rejestru.
EDX – rejestr danych jest rozszerzenie do akumulatora. Jest to najbardziej przydatne do przechowywania danych związanych z bieżącym obliczaniu akumulatora jest.
ECX – Like zmiennej I w językach wysokiego poziomu, liczba rejestr uniwersalny licznik pętli.
EDI – Każda pętla musi przechowywać swój wynik gdzieś, a punkty indeksowe przeznaczenia do tego miejsca. Z jednobajtowych instrukcji STOS do zapisu danych z akumulatora, rejestr ten czyni operacje danych znacznie rozmiar efektywny.
ESI – W pętli, które przetwarzają dane, indeks źródło posiada lokalizację strumienia danych wejściowych. Podobnie jak indeks przeznaczenia, EDI miał dogodną jeden bajt instrukcji ładowania danych z pamięci do akumulatora.
ESP – ESP jest święte wskaźnik stosu. Z ważnym PUSH, POP, CALL i RET instrukcje wymagające jego wartości, nigdy nie jest dobry powód, aby użyć wskaźnik stosu na nic innego.
EBP – W funkcjach, które przechowują lub zmienne parametry na stosie, wskaźnik podstawy posiada lokalizację bieżącej ramki stosu. W innych sytuacjach, jednakże, EBP to darmowe przechowywanie danych rejestru.
EBX – w trybie 16-bitowym, rejestr bazowy był użyteczny jako wskaźnik. Teraz jest całkowicie bezpłatna dla dodatkowego miejsca.

Jako przykład, jak te rejestry do siebie pasują, tu jest szkic typowego rutyny:

esi mov, source_address
edi mov, destination_address
mov ecx, loop_count
my_loop: lodsd

; Czy jakieś obliczenia z eax tutaj.

stosd
pętla my_loop

W tym przykładzie, jest ECX licznika pętli, punkty ESI do danych wejściowych, a do EDI punktów danych wyjściowych. Niektóre obliczenia, takie jak rozmycie, filtr, a może kolor look-up występuje w pętli przy użyciu EAX jako zmienną. Ten przykład jest nieco uproszczone, ale miejmy nadzieję, że pokazuje ogólną ideę. Realne rutynowych prawdopodobnie do czynienia z dużo bardziej skomplikowanych danych niż DWORD i prawdopodobnie obejmować kilka zmiennoprzecinkowych, jak również.

Podsumowując, przy użyciu rejestrów przeznaczony Intel ma kilka zalet. W przypadku pięści, umożliwia kod, aby skorzystać z wielu optymalizacji i specjalnych poleceń. To również sprawia, że ​​kod jest bardziej czytelny, ponieważ rejestry wykonać przewidywalne funkcji. Ponadto na podstawie rejestrów konsekwentnie prowadzi do lepszej kompresji poprzez promowanie bardziej powtarzalne sekwencje instrukcji.

Comments are closed.