Programowanie niskopoziomowe / Moduł 5: Techniki programowania asemblerowego

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

PNP M5 S01.png

...


PNP M5 S02.png

...


PNP M5 S03.png

...


PNP M5 S04.png

...


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.


PNP M5 S06.png

...


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.


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.


PNP M5 S09.png

...


PNP M5 S10.png

...


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.


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


PNP M5 S13.png

...


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.


PNP M5 S15.png

...


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.


PNP M5 S17.png

...


PNP M5 S18.png

...