Jak pisac programy w jezyku assembler?
Autor: Bogdan Drozdowski, bogdandr (at) op.pl
Czesc 3 - Podstawowe instrukcje, czyli poznajemy dialekt procesora.
---------------------------------------------------------------------------
Poznalismy juz rejestry, omowilismy pamiec. Pora zaczac na nich operowac.
Zanim zaczniemy, prosze Was o to, abyscie tej listy tez NIE uczyli sie na
pamiec. Instrukcji jest duzo, a proba zrozumienia ich wszyskich na raz moze
spowodowac niezly chaos. Co najwyzej przejrzyjcie ta liste kilka razy, aby
wiedziec mniej-wiecej, co kazda instrukcja robi.
---------------------------------------------------------------------------
Instrukcje procesora mozna podzielic na kilka grup:
instrukcje przemieszczania danych
instrukcje arytmetyki binarnej
instrukcje arytmetyki dziesietnej
instrukcje logiczne
operacje na bitach (shift i rotate) i bajtach (np. bt, setcc)
instrukcje przekazujace kontrole innej czesci programu (sterujace
wykonywaniem programu)
instrukcje operujace na lancuchach znakow
instrukcje kontroli flag
instrukcje rejestrow segmentowych
inne
Zacznijmy je po kolei omawiac (nie omowie wszystkich).
---------------------------------------------------------------------------
1. instrukcje przemieszczania danych.
Tutaj zaliczymy juz wielokrotnie uzywane "mov" oraz kilka innych. Sa to:
"xchg", "push" i "pop".
---------------------------------------------------------------------------
2. arytmetyka binarna.
- add do_czego,co - dodaj
- sub od_czego,co - odejmij
- inc cos / dec cos - zwieksz/zmniejsz cos o 1
- cmp co, z_czym - porownaj. Wykonuje dzialanie odejmowania "co - z_czym",
ale nie zachowuje wyniku, tylko ustawia flagi.
Wynikiem moze byc ustawienie 1 lub wiecej flag - zaznaczenie wystapienia
jednego z warunkow. Glowne warunki to:
A - above. (bez znaku)co > z_czym
cmp al,bl
ja al_wieksze_od_bl ; ja - jump if above
B - below. (bez znaku)co < z_czym
G - greater. (ze znakiem) co > z_czym
L - lower. (ze znakiem) co < z_czym
O - overflow. przepelnienie ostatniej operacji. niekoniecznie uzywane
przy cmp.
C - carry. przepelnienie bez znaku
add al,bl
jc blad_przepelnienia ; jc - jump if carry
E lub Z - equal (rowny) lub zero.
cmp ax,cx
je ax_rowne_cx
...
sub bx,dx
jz bx_rowne_dx
NE/NZ - przeciwienstwo poprzedniego. Not equal/not zero.
NA - not above
NB - not below
NC - no carry
AE/BE - above or equal, below or equal
NO - no overflow
3. arytmetyka dziesietna
- NEG - zmienia znak.
- MUL, IMUL - mnozenie, mnozenie ze znakiem (tj. uwzglednia liczby ujemne)
mul cl ; AX := AL*CL
mul bx ; DX:AX := AX*BX
mul esi ; EDX:EAX := EAX*ESI
imul eax ; EDX:EAX := EAX*EAX
imul ebx,ecx,2 ; EBX := ECX*2
imul ebx,ecx ; EBX := EBX*ECX
imul si,5 ; SI := SI*5
- DIV, IDIV - dzielenie, dzielenie ze znakiem.
div cl ; AL := (AX div CL), AH := (AX mod CL)
div bx ; AX := (DX:AX div BX), DX := (DX:AX mod BX)
div edi ; EAX := (EDX:EAX div EDI), EDX := (EDX:EAX mod EDI)
4. Instrukcje logiczne. AND, OR, XOR, NOT, TEST. TEST dziala tak samo jak
AND z tym, ze nie zachowuje nigdzie wyniku, tylko ustawia flagi. Po krotce
wytlumacze te instrukcje:
0 AND 0 = 0 0 OR 0 = 0 0 XOR 0 = 0 NOT 0 = 1
0 AND 1 = 0 0 OR 1 = 1 0 XOR 1 = 1 NOT 1 = 0
1 AND 0 = 0 1 OR 0 = 1 1 XOR 0 = 1
1 AND 1 = 1 1 OR 1 = 1 1 XOR 1 = 0
Przyklady zastosowania:
and ax,1 ; wyzeruje wszystkie bity z wyjatkiem bitu nr 0.
or ebx,1111b ; ustawia (=wlacza) 4 dolne bity. Reszta bez zmian.
xor cx,cx ; CX = 0
not dh ; DH ma 0 tam, gdzie mial 1 i na odwrot
5. Instrukcje przesuniecia bitow.
- SHL - shift left.
bit7 := bit6, bit6 := bit5, ... , bit1 := bit0, bit0 := 0.
- SHR - shift logical right
bit0 := bit1, bit1 := bit2, ... , bit6 := bit7, bit7 := 0
- SAR - shift arithmetic right
bit0 := bit1, bit1 := bit2, ... , bit6 := bit7,
*** bit7 := bit7 *** bit znaku zachowany
(Najstarszy bit w rejestrze nazywa sie czasem bitem znaku)
- ROL - rotate left
bit7 := bit6, ... , bit1 := bit0, bit0 := stary bit7
- RCL - rotate through carry left
carry flag CF := bit7, bit7 := bit6, ... , bit1 := bit0, bit0 := stara CF
- ROR - rotate right
bit0 := bit1, ... , bit6 := bit7, bit7 := stary bit0
- RCR - rotate through carry right
CF := bit0, bit0 := bit1, ... , bit6 := bit7, bit7 := stara CF
Przy uzyciu SHL mozna przeprowadzac szybkie mnozenie, a dzieki SHR - szybkie
dzielenie. Np. "shl ax,1" jest rownowazne przemnozeniu AX przez 2, "shl ax,5"
- przez 2^5 = 32. "shr bx,4" dzieli bx przez 16.
6. Instrukcje sterujace wykonywaniem programu.
- Skoki warunkowe: JA=JNBE, JAE=JNB, JNA=JBE, JNAE=JB , JG=JNLE (jump if
greater - dla liczb ze znakiem) = jump if not lower or equal,
JNG=JLE, JGE=JNL, JNGE=JL, JO, JNO, JC, JNC, JS (jump if sign czyli
bit7 wyniku jest rowny 1), JNS, JP=JPE (jump if parity equal =
liczba bitow rownych jeden jest parzysta), JNP=JPO.
- Skoki bezwarunkowe: JMP, JMP SHORT, JMP FAR
- Uruchomienia procedur: CALL [NEAR/FAR]
- Powrot z procedury: RET/RETF.
- Przerwania: INT, INTO (jesli overflow, to INT4), BOUND (int 5)
- Instrukcje petli: LOOP. Skladnia: "LOOP gdzies". Jesli CX jest rozny od 0,
to skacz "gdzies".
7. Operacje na lancuchach znakow.
- LODS[B/W/D] - Load Byte/Word/Dword
MOV AL/AX/EAX , DS:[SI]
ADD SI,1/2/4 ; ADD, gdy flaga kierunku DF = 0, SUB gdy DF = 1
- STOS[B/W/D] - Store Byte/Word/Dword
MOV ES:[DI], AL/AX/EAX
ADD DI,1/2/4 ; ADD/SUB jw.
- MOVS[B/W/D] - Move Byte/Word/Dword
MOV ES:[DI], DS:[SI] ; to nie jest instrukcja!
ADD DI,1/2/4 ; ADD/SUB jw.
ADD SI,1/2/4
- CMPS[B/W/D] - Compare Byte/Word/Dword
CMP DS:[SI], ES:[DI] ; to nie jest instrukcja!
ADD SI,1/2/4 ; ADD/SUB jw.
ADD DI,1/2/4
- SCAS[B/W/D] - Scan Byte/Word/Dword
skanuje lancuch bajtow/slow/podwojnych slow pod ES:[DI] w
poszukiwaniu, czy jest tam wartosc wskazana przez AL/AX/EAX
Do kazdej z tych instrukcji mozna z przodu dodac predrostek "REP" (repeat),
co spowoduje, ze bedzie ona wykonywana, az CX stanie sie zerem, lub REPE/REPZ
lub REPNE/REPNZ co spowoduje, ze bedzie ona wykonywana, dopoty CX nie jest
zerem i gdy ZF (zero flag) =1 lub =0, odpowiednio.
7. Instrukcje wejscia/wyjscia do portow.
- IN
IN AL, port/DX.
Pobierz z portu bajt i wloz do AL. Jesli numer portu < 255, mozna
podac bezposrednio. Jesli wiekszy - trzeba uzyc DX.
IN AX, port/DX
Jest rownowazne:
IN AL, port/DX
IN AH, port+1/DX+1
IN EAX, port/DX - pobierz 4 bajty - 1 z "port" do AL, 2 z "port+1"
do AH, 3 z "port+2" do bitow 23-16 EAX, 4 z "port+3" do bitow
31-24 EAX.
- OUT
OUT port/DX, AL/AX/EAX.
Uwagi jak przy "IN".
8. Instrukcje flag
- STC/CLC - set carry / clear carry. CF := 1 i CF := 0, odpowiednio.
- STD/CLD. DF := 1, DF := 0, odpowiednio.
- STI/CLI. Interrupt Flag IF := 1, IF := 0, odpowiednio. Gdy IF=0, przerwania
sprzetowe sa blokowane
- Przenoszenie flag
+ "pushf/pushfd" - umiesc flagi na stosie (16 i 32 bity flag, odpowiednio)
+ "popf/popfd" - zdejmij flagi ze stosu (16/32bity flag)
+ "sahf/lahf" - zapisz AH w pierwszych 8 bitach flag / zapisz pierwsze 8
bitow flag w AH.
9. Instrukcja LEA - Load Effective Address.
Wykonanie:
lea rej, [pamiec]
Jest rownowazne:
mov rej, offset pamiec ; TASM
mov rej, pamiec ; NASM
Po co wiec osobna instrukcja? Otoz, LEA przydaje sie w wielu sytuacjach do
obliczania zlozonych adresow. Kilka przykladow:
- Jak w 1 instrukcji sprawic, ze EAX = EBP-12 ?
Tak: lea eax, [ebp-12]
- Niech EBX wskazuje na tablice o 20 elementach o rozmiarze 8 kazdy.
Jak do ECX zapisac adres 11-tego elementu, a do EDX elementu o
numerze EDI?
Tak: lea ecx, [ebx + 11*8 ] oraz lea edx,[ebx+edi*8]
- Jak w 1 instrukcji sprawic, ze ESI = EAX*9?
lea esi, [eax + eax*8 ]
---------------------------------------------------------------------------
Pominalem mniej wazne instrukcje operujace na rejestrach segmentowych i klika
innych instrukcji. Te, ktore tu podalem, wystarczaja absolutnie na napisanie
wiekszosci programow, ktore mozna zrobic.
Wszystkie informacje przedstawione w tej czesci pochodza z tego samego zrodla:
Intel: http://developer.intel.com/design/Pentium4/documentation.htm
AMD nie jest gorsze:
http://www.amd.com/us-en/Processors/DevelopWithAMD/0,,30_2252_739_7044,00.html
"Byle glupiec potrafi napisac kod, ktory zrozumie komputer. Dobry programista
pisze taki kod, ktory zrozumie czlowiek."
-----------------------------------------------------------------------------
Cwiczenia:
1. Zapisz instrukcje: do rejestru AX dodaj 5, o rejestru SI odejmij 178.
2. Nie uzywajac cyfry "1" napisz jedna instrukcje, ktora zmniejszy rejestr
DX o 1.
3. Przemnoz wartosc rejestru EDI przez 2 na przynajmniej dwa rozne sposoby po
1 instrukcji. Postaraj sie nie uzywac instrukcji (I)MUL.
4. W jednej instrukcji podziel wartosc rejestru BP przez 8.
5. Nie uzywajac instrukcji MOV spraw, by DX mial wartosc 0 (na przynajmniej 3
sposoby, kazdy po 1 instrukcji).
6. Nie uzywajac instrukcji przesuwania bitow SH* ani mnozenia *MUL przemnoz
EBX przez 8. Mozesz uzyc wiecej niz 1 instrukcji.
7. W dwoch instrukcjach spraw, by EDI rownal sie 7*ECX. Postaraj sie nie
uzywac instrukcji (I)MUL.
Wyszukiwarka
Podobne podstrony:
FUNFACE DOS OPIScompilar dosdos lid fun der goldener pawe c moll pfte vni vla vc voxCwiczenie 07 Testy penetracyjne ataki DoSdos win to linux howto 6a kurs03dos kompilierenDOS DIOD TUTOkno MS DOSCo to jest so uruchamianie pol dos unixBezpieczeństwo Ataki typu DoS Anatomia zagrożenia i metody obrony 02 2005Brasílio Sallum Jr , B Resenha Labirintos Dos GeneraisLinux DOS Win95 OS2 DYJDRPGZ3XMKL2CW333NX7RVRTMCHO2B2VQXYQIlinux dos win95 plKURS03więcej podobnych podstron