ROZDZIAŁ DZIESIĄTY STRUKTURY STERUJĄCE, INFORMATYKA, „THE ART OF ASSEMBLY LANGUAGE” [PL]

[ Pobierz całość w formacie PDF ]
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
WYŁĄCZNOŚĆ DO PUBLIKOWANIA TEGO TŁUMACZENIA
POSIADA
RAG
WWW.R-AG.PRV.PL
„THE ART OF ASSEMBLY LANGUAGE”
tłumaczone by KREMIK
konsultacja naukowa: NEKRO
wankenob@priv5.onet.pl
nekro@pf.pl
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
ROZDZIAŁ DZIESIĄTY:
STRUKTURY STERUJĄCE
Rozdział ten omawia dwa podstawowe typy struktur sterujących : decyzje i powtórzenia (iteracje).Omawia
jak skonwertować instrukcje języka wysokiego poziomu takie jak if...then..else, case (switch), while, for itp do
odpowiedników sekwencji języka asemblera. rozdział ten również omawia techniki jakie możemy zastosować do
poprawienia osiągów tych struktur sterujących. Sekcje poniżej, które mają przedrostek „•” są niezbędne .Te sekcje, z
„⊗” omawiają zaawansowane tematy, które może odłożymy na później.
• Wprowadzenie do Decyzji
• Sekwencje IF..THEN..ELSE
• Instrukcje CASE
⊗ Stany maszynowe i skoki pośrednie
• Kod spaghetti
• Pętle
• Pętle WHILE
• Pętle REPEAT..UNTIL
• LOOP..ENDLOOP
• Pętle FOR
• Wykorzystanie rejestru a pętle
⊗ Poprawianie wydajności
⊗ Przenoszenie warunku zakończenia na koniec pętli
⊗ Wykonywanie pętli wstecznych
⊗ Pętla niezmienników
⊗ Pętle rozwijane
⊗ Indukcja zmiennych
10.1 WPROWADZENIE DO DECYZJI
W swoje podstawowej formie, decyzja jest rodzajem krótkiego skoku wewnątrz kodu ,który przełącza
pomiędzy dwoma możliwymi wykonaniami ścieżkami wykonania opartymi na jakimś warunku. Normalnie,(chociaż
nie zawsze),sekwencje instrukcji warunkowych są implementowane z instrukcjami skoków warunkowych. Instrukcje
warunkowe odpowiadają instrukcjom w Pascalu;
IF (warunek jest prawdziwy) THEN instr1 else instr2;
Język asemblera, jak zwykle, oferuje dużo większą elastyczność, kiedy zajmujemy się instrukcjami warunkowymi.
Rozważmy poniższą instrukcję pascalowską:
IF ((X<Y) and (Z>T)) or (A <>B) THEN instr1;
Podchodząc do konwertowania tej instrukcji na asembler metodą „brute force” możemy stworzyć:
 Jak możemy zobaczyć ,w przetwarzaniu tego powyższego wyrażenia bierze udział znaczna liczba instrukcji
warunkowych. Pobieżnie odpowiada to (odpowiednikowi) Pascalowych instrukcji:
cl := true;
IF (X>=Y) then cl := fałsz;
IF (Z<=T) then cl := fałsz;
IF (A<>B) then cl := true;
IF (CL = true) then stmt1;
Teraz porównajmy to z poniższym „poprawionym” kodem:
mov
ax, A
cmp
ax, B
jne
DoStmt
mov
ax, X
cmp
ax, Y
jnl
SkipStmt
mov
ax, Z
cmp
ax, T
jng
SkipStmt
DoStmt:
<tu umieszczamy kod dla Stmt1>
SkipStmt:
Dwie rzeczy powinny być oczywiste z powyższej sekwencji kodu: po pierwsze, pojedyncza instrukcja
warunkowa w Pascalu może wymagać kilku skoków warunkowych w asemblerze; po drugie, organizacja złożonego
wyrażenia w sekwencji warunkowej może wpływać na wydajność kodu. Dlatego też ,powinniśmy ostrożnie ćwiczyć
kiedy zajmujemy się sekwencjami warunkowymi w asemblerze.
Instrukcje warunkowe mogą być podzielone na trzy podstawowe kategorie: instrukcje if..then..else
,instrukcje case i skoki pośrednie. Poniższa sekcja opisze te struktury programu ,jak je zastosować i jak napisać je w
języku asemblera.
10.2 SEKWENCJE IF..THEN..ELSE
Najpowszechniejszym zastosowaniem instrukcji warunkowych jest instrukcja if..then lub if..then..else. Te
dwie instrukcje przybierają formę jak pokazano na rysunku 10.1
Instrukcja if..then jest specjalnym przypadkiem instrukcji if..then..else ( z pustym blokiem ELSE).Dlatego
też, będziemy rozpatrywać bardziej ogólną postać if..then..else. Podstawowa implementacja instrukcji if..then..else w
języku asemblera 80x86 wygląda podobnie jak to:
Rysunek 10.1 Instrukcje IF..THEN i IF..THEN..ELSE
{sekwencja instrukcji testujących jakiś warunek}
jcc JakiśKod
{sekwencja instrukcji odpowiadających blokowi THEN}
jmp
EndOfIf
ElseCode:
{sekwencja instrukcji odpowiadających blokowi ELSE}
EndOfIf:
Notka: Jcc przedstawia jakąś instrukcję skoku warunkowego.
Na przykład do konwersji instrukcji pascalowskie:
IF (a=b) then c:=d else b:= b+1;
Na język asemblera, możemy zastosować poniższy kod 80x86:
mov
ax, a
cmp
ax, b
jne
ElseBlk
mov
ax, d
mov
c, ax
jmp
EndOfIf
ElseBlk:
inc
b
EndOf If:
Dla prostego wyrażenia takiego jak (A=B) generowanie właściwego kodu dla instrukcji if..then..else jest
prawie trywialne. Kiedy wyrażenie staje się bardziej złożone, również wzrasta złożoność powiązanego kodu
asemblerowego. Rozważmy poniższą instrukcję if prezentowaną wcześniej:
IF ((X > Y) and (Z <T)) or (A<>B) THEN C :=D;
Kiedy przetwarzamy złożone instrukcje if takie jak to, zadanie konwersji stanie się łatwiejsze jeśli
podzielimy tą instrukcję if na sekwencję trzech różnych instrukcji if jak następuje:
IF (A<>B) THEN C :=D
IF (X >Y) THEN IF (Z< T) THEN C := D;
Konwersja ta pochodzi z Pascalowskich odpowiedników:
IF (wyraż1 AND wyarż2) THEN instr;
Jest odpowiednikiem
IF (wyraż1) THEN IF (wyraż2) THEN instr;
a
IF (wyraż1 OR wyraż2) THEN instr;
jest odpowiednikiem
IF (wyraż1) THEN instr;
IF (wyraż2) THEN instr;
W języku asemblera, dawna instrukcja if staje się :
mov
ax, A
cmp
ax, B
jne
DOIf
mov
ax, X
cmp
ax, Y
jng
EndOfIf
mov
ax, Z
cmp
ax, T
jnl
RndOfIf
DoIf:
mov
ax, D
mov
C, ax
EndOfIf:
Jak już prawdopodobnie mówiliśmy, kod konieczny do sprawdzenia warunku może łatwo stać się bardziej
złożony niż instrukcje pojawiające się w blokach else i then. Chociaż wydaje się to nieco paradoksalne, że można
włożyć większy wysiłek w testowanie warunku niż działanie na wyniku tego warunku, zdarza się to cały czas
.Dlatego też powinniśmy być przygotowani na taką sytuację.
Prawdopodobnie największym problem z implementacją złożonych instrukcji warunkowych w asemblerze
jest próbowanie obliczenia co zrobimy po napisaniu kodu. Największą zaletą oferowaną przez język wysokiego
poziomu nad asemblerem jest to że wyrażenia są dużo łatwiejsze do odczytu i pojęcia w języku wysokiego poziomu.
Wersja HLL’a jest samodokumentująca podczas gdy język asemblera ma tendencje do ukrywania prawdziwej
natury kodu. Dlatego też dobrze napisane komentarze są niezbędnym składnikiem implementacji przez asembler
instrukcji if..then..else. Elegancka implementacja powyższego przykładu:
;IF ((X >Y) AND (Z < T)) OR (A<> B) THEN C:=D;
;Implementujemy jako:
;IF (A<>B) THEN GOTO DoIf;
mov ax, A
cmp ax, B
jne DoIf
;IF NOT (X>Y) THEN GOTO EndOfIf;
mov ax, X
cmp ax, Y
jng EndOf If
;IF NOT (Z < T) THEN GOTO EndOfIf;
mov
ax, Z
cmp
ax,T
jnl
EndOfIf
; Blok THEN:
mov
ax, D
mov
C, ax
;Koniec instrukcji IF
EndOfIf:
Trzeba przyznać, że takie przedstawianie jest popadaniem w przesadę dla tak prostego przykładu poniższe
byłoby prawdopodobnie wystarczające:
;IF ((X > Y) AND (Z < T) OR (A<>B) THEN C:=D;
;test wyrażenia boolowskiego:
mov
ax, A
cmp
ax, B
jne
DoIF
mov
ax, X
cmp
ax, Y
jng
EndOfIf
mov
ax, Z
cmp
ax, T
jnl
EndOfIf
;Blok THEN:
mov
ax, D
mov
C, ax
;Koniec instrukcji IF
EndOfIf:
Jednakże jeśli nasze instrukcje if stają się złożone, gęstość (i jakość) naszych komentarzy staje się coraz bardziej
ważna.
10.3 INSTRUKCJE CASE
Pascalowa instrukcja case przybiera poniższą formę:
CASE zmienna OF
stała
1
: instr
1
;
stała
2
:instr
2
;
-
-
-
stała
n
:instr
n
END;
Kiedy wykonuje się ta instrukcja, sprawdza wartość stałej const
1
..const
n
.Jeśli została znaleziona, wtedy
wykonuje się odpowiednia instrukcja. standardowy Pascal umieszcza kilka ograniczeń na instrukcję case. Po
pierwsze, wartość zmiennej nie jest na liście stałych, wynik instrukcji case jest niezdefiniowany. Po drugie,
wszystkie stałe pojawiające się po etykiecie CASE muszą być unikalne. Powód tych ograniczeń stanie się jasny za
chwilę.
Większość wstępnych tekstów o programowaniu wprowadza instrukcję case poprzez wyjaśnienie jej jako
sekwencji instrukcji if..then..else. Można twierdzić że poniższe dwa kawałki kodu pascalowego są sobie
odpowiednie:
CASE I OF
0: Writeln(‘I=0’);
1:Writeln(‘I=1’);
2:Writeln(‘I=2’);
END;
IF I = 0 THEN writeln (‘I=0’)
ELSE IF I = 1 THEN Writeln (‘I= 1’)
ELSE IF I= 2 THEN Writeln (‘I=2’);
Podczas gdy semantycznie te dwie części kodu mogą być takie same, ich implementacja jest zwykle różna.
Podczas gdy łańcuch if..then..else wykonuje porównanie dla każdej instrukcji warunkowej w sekwencji, instrukcja
case normalnie używa skoku pośredniego dla sterowania przesyłaniem danych do jednej z kilku instrukcji
pojedynczego obliczenia. Rozważmy dwa przedstawione powyżej przykłady ,które mogą być napisane w asemblerze
w poniższym kodzie:
[ Pobierz całość w formacie PDF ]

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • tejsza.htw.pl
  •