Programowanie niskopoziomowe / Moduł 5: Techniki programowania asemblerowego

From Studia Informatyczne


Grafika:PNP_M5_S01.png

...


Grafika:PNP_M5_S02.png

...


Grafika:PNP_M5_S03.png

...


Grafika:PNP_M5_S04.png

...


Grafika:PNP_M5_S05.png

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.


Grafika:PNP_M5_S06.png

...


Grafika:PNP_M5_S07.png

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 rejestr użyty do zliczania iteracji i konieczność modyfikacji dwóch rejestrów w każdym obiegu pętli.


Grafika:PNP_M5_S08.png

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 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.


Grafika:PNP_M5_S09.png

...


Grafika:PNP_M5_S10.png

...


Grafika:PNP_M5_S11.png

Dodawanie 64-bitowe jest realizowane poprzez dodawanie mniej znaczących słów 32-bitowych, a następnie dodawanie bardziej znaczących słów z uwzględnieniem przeniesienia wchodzącego (instrukcja ADC), wygenerowanego w pierwszym dodawaniu.

W analogiczny sposób można zrealizować odejmowanie, zastępując instrukcję ADD instrukcją SUB,a instrukcję ADC - instrukcją SBB (odejmowania z uwzględnieniem pożyczki wchodzącej).

Przy uogólnieniu dla liczb o dowolnej długości, sumowanie poszczególnych fragmentów danej jest realizowane w pętli przy użyciu instrukcji ADC, a przed pętlą znacznik przeniesienia jest zerowany. Należy zadbać, by żadna inna instrukcja w pętli nie modyfikowała znacznika przeniesienia W tym celu do inkrementacji adresów o 4 użyto instrukcji LEA.


Grafika:PNP_M5_S12.png

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).


Grafika:PNP_M5_S13.png

...


Grafika:PNP_M5_S14.png

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.


Grafika:PNP_M5_S15.png

...


Grafika:PNP_M5_S16.png

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.


Grafika:PNP_M5_S17.png

...


Grafika:PNP_M5_S18.png

...