Programowanie niskopoziomowe / Moduł 5: Techniki programowania asemblerowego: Różnice pomiędzy wersjami
Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Nie podano opisu zmian |
Nie podano opisu zmian |
||
(Nie pokazano 1 pośredniej wersji utworzonej przez tego samego użytkownika) | |||
Linia 28: | Linia 28: | ||
|valign="top" width="500px"|[[Grafika:PNP_M5_S05.png]] | |valign="top" width="500px"|[[Grafika:PNP_M5_S05.png]] | ||
|valign="top"| | |valign="top"| | ||
Przykład | Przykład przedstawia trzy procedury, służące do wypisywania na konsoli danych 4-, 8- i 16-bitowych w postaci szesnastkowej. | ||
Procedura dla słowa 8-bitowego korzysta z procedury wypisywania tetrady, a procedura dla słowa 16-bitowego – z procedury dla bajtu. Argument wywołania jest przekazywany w rejestrze AX lub jego mniej znaczącej części - AL. | Procedura dla słowa 8-bitowego korzysta z procedury wypisywania tetrady, a procedura dla słowa 16-bitowego – z procedury dla bajtu. Argument wywołania jest przekazywany w rejestrze AX lub jego mniej znaczącej części - AL. | ||
Linia 44: | Linia 44: | ||
W pierwszej wersji procedury używamy licznika pętli w jako indeksu danej. Wadami takiego rozwiązania są: konieczność użycia dodatkowej zmiennej jako licznika pętli i użycie złożonego trybu adresowania; zaletą – potrzeba inkrementacji tylko jednej zmiennej. | W pierwszej wersji procedury używamy licznika pętli w jako indeksu danej. Wadami takiego rozwiązania są: konieczność użycia dodatkowej zmiennej jako licznika pętli i użycie złożonego trybu adresowania; zaletą – potrzeba inkrementacji tylko jednej zmiennej. | ||
W drugiej wersji pętla jest odliczana w dół. W porównaniu z wersją pierwszą mamy tu jeden | W drugiej wersji pętla jest odliczana w dół. W porównaniu z wersją pierwszą mamy tu jeden rejestr użyty do zliczania iteracji i konieczność modyfikacji dwóch rejestrów w każdym obiegu pętli. | ||
|} | |} | ||
<hr width="100%"> | <hr width="100%"> | ||
Linia 52: | Linia 52: | ||
Wersja trzecia używa wskaźnika danych do określenia warunku wyjścia z pętli. W tym celu przed pętlą jest wyliczana wartość wskaźnika dla stanu po ostatniej iteracji. | Wersja trzecia używa wskaźnika danych do określenia warunku wyjścia z pętli. W tym celu przed pętlą jest wyliczana wartość wskaźnika dla stanu po ostatniej iteracji. | ||
Wersja czwarta korzysta z instrukcji iteracyjnych x86. Instrukcja LODSB ładuje bajt | Wersja czwarta korzysta z instrukcji iteracyjnych x86. Instrukcja LODSB ładuje bajt spod adresu zawartego w rejestrze ESI do AL i inkrementuje ESI. Instrukcja LOOP dekrementuje ECX i wykonuje skok, jeśli nie osiągnięto wartości 0. Procedura jest krótka w zapisie, ale współczesne procesory x86 wykonują instrukcje iteracyjne na ogół wolniej, niż odpowiadające im sekwencje instrukcji prostych. | ||
|} | |} | ||
<hr width="100%"> | <hr width="100%"> | ||
Linia 80: | Linia 80: | ||
|valign="top" width="500px"|[[Grafika:PNP_M5_S12.png]] | |valign="top" width="500px"|[[Grafika:PNP_M5_S12.png]] | ||
|valign="top"| | |valign="top"| | ||
... | Przesunięcie o jeden bit danej wielokrotnej precyzji można uzyskać poprzez przesunięcie pierwszego elementu, w wyniku czego bit „wysuwany” trafi do znacznika przeniesienia, a następnie użycie instrukcji rotacji przez przeniesienie. Podczas kolejnych rotacji bit z poprzedniej fazy jest wsuwany do słowa poddawanego rotacji, a bit wysuwany ze słowa jest zapamiętywany w znaczniku przeniesienia. | ||
W postaci ogólnej, dla danej o dowolnej długości, do przesuwania używamy wyłącznie instrukcji rotacji przez przeniesienie, a przed rozpoczęciem przesuwania ustawiamy znacznik przeniesienia w stan zero. Można to zrobić przy użyciu dedykowanej instrukcji zerowania przeniesienia lub poprzez wykonanie dowolnej instrukcji logicznej (np. OR AL, AL). | |||
W procesorach rodziny x86 od modelu 386 w górę istnieją specjalne instrukcje przesunięć 64-bitowych z zapisem 32 bitów wyniku – SHLD i SHRD. Można ich użyć do syntezy przesunięć wielokrotnej precyzji o dowolną liczbę bitów (<32). | |||
|} | |} | ||
<hr width="100%"> | <hr width="100%"> | ||
Linia 92: | Linia 96: | ||
|valign="top" width="500px"|[[Grafika:PNP_M5_S14.png]] | |valign="top" width="500px"|[[Grafika:PNP_M5_S14.png]] | ||
|valign="top"| | |valign="top"| | ||
. | Przykład ilustruje usunięcie skoku poprzez dość wyrafinowane zastosowanie instrukcji korekcji dziesiętnej. Sekwencja czterech pierwszych instrukcji procedury hex_digit zamienia wartość mniej znaczącej tetrady rejestru AL na jej reprezentację znakową w postaci cyfry szesnastkowej w kodzie ASCII. | ||
|} | |} | ||
<hr width="100%"> | <hr width="100%"> | ||
Linia 104: | Linia 108: | ||
|valign="top" width="500px"|[[Grafika:PNP_M5_S16.png]] | |valign="top" width="500px"|[[Grafika:PNP_M5_S16.png]] | ||
|valign="top"| | |valign="top"| | ||
... | Kończąca procedurę hex_word sekwencja CALL hex_byte; RET została zastąpiona instrukcją skoku JMP hex_byte. Ponieważ etykieta hex_byte występuje bezpośrednio po tej instrukcji – instrukcja skoku może zostać usunięta. | ||
Analogicznego zabiegu dokonano w procedurze hex_byte. | |||
Procedura hex_digit kończy się skokiem do procedury wyświetlania znaku. | |||
W ten sposób powstaje interesująca konstrukcja programu – procedury wywołującej swoje własne zakończenie. Konstrukcja taka nie ma swojego odpowiednika we współczesnych językach wysokiego poziomu. | |||
|} | |} | ||
<hr width="100%"> | <hr width="100%"> |
Aktualna wersja na dzień 14:24, 18 paź 2006
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |
![]() |
... |