Poznaliśmy już rejestry, omówiliśmy pamięć. Pora zacząć na nich operować.
Zanim jednak zaczniemy,
proszę Was o to, abyście tej listy też NIE uczyli się na pamięć.
Instrukcji jest dużo, a próba zrozumienia ich wszystkich na raz może spowodować niezły chaos. Co najwyżej
przejrzyjcie tę listę kilka razy, aby wiedzieć mniej-więcej, co każda instrukcja robi.
Instrukcje procesora można podzielić na kilka grup:
Zacznijmy je po kolei omawiać (nie omówię wszystkich).
Tutaj zaliczymy już wielokrotnie używane MOV oraz kilka innych:
XCHG , PUSH i POP.
add do_czego,co - dodajsub od_czego,co - odejmijinc coś / dec coś - zwiększ/zmniejsz coś o 1cmp co, z_czym - porównaj. Wykonuje działanie odejmowania co minus z_czym, ale nie zachowuje wyniku, tylko ustawia flagi.
Wynikiem może być ustawienie lub wyzerowanie jednej lub więcej flag - zaznaczenie wystąpienia jednego z warunków. Główne warunki to:
ponad(dla liczb traktowanych jako liczby bez znaku):
co > z_czym
cmp al,bl ja al_wieksze_od_bl ; ja - jump if above
poniżej(bez znaku): co < z_czym
więcej niż(ze znakiem): co > z_czym
mniej niż(ze znakiem): co < z_czym
add al,bl jc blad_przepelnienia ; jc - jump if carry
cmp ax,cx je ax_rowne_cx ... sub bx,dx jz bx_rowne_dx
nie ponad- mniejsze lub równe (ale dla liczb bez znaku)
nie poniżej- większe lub równe (dla liczb bez znaku)
nie więcej- mniejsze lub równe (ale dla liczb ze znakiem)
nie mniej- większe lub równe (dla liczb ze znakiem)
ponad lub równe), below or equal (
poniżej lub równe)
NEG - zmienia znak.MUL, IMUL - mnożenie, mnożenie ze znakiem (które uwzględnia liczby ujemne)
mul cl ; AX = AL*CL mul bx ; DX:AX = AX*BX mul esi ; EDX:EAX = EAX*ESI mul rdi ; RDX:RAX = RAX*RDI 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
Zapis rej1 : rej2
oznacza, że starsza część wyniku znajdzie się w pierwszym rejestrze
podanej pary (DX, EDX, RDX), a młodsza - w drugim (AX, EAX, RAX), gdyż wynik mnożenia dwóch
liczb o długości n bitów każda wymaga 2n bitów.
DIV, IDIV - dzielenie,
dzielenie ze znakiem (i jednoczesne obliczanie reszty z dzielenia).
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) div rsi ; RAX = (RDX:RAX div RSI), ; RDX = (RDX:RAX mod RSI)
Zapis rej1 : rej2
oznacza, że starsza część dzielnej jest oczekiwana w pierwszym
rejestrze podanej pary (DX, EDX, RDX), a młodsza - w drugim (AX, EAX, RAX). Jeśli liczba
mieści się w rejestrze dla młodszej części, rejestr starszy należy wyzerować. Słowo "div"
w powyższych zapisach oznacza iloraz, a mod - resztę z dzielenia (modulo).
ANDORXORNOTTESTInstrukcja TEST działa tak samo jak AND z tym,
że nie zachowuje nigdzie wyniku, tylko ustawia flagi. Pokrótce wytłumaczę te instrukcje:
0 AND 0 = 0 0 OR 0 = 0 0 XOR 0 = 0 0 AND 1 = 0 0 OR 1 = 1 0 XOR 1 = 1 1 AND 0 = 0 1 OR 0 = 1 1 XOR 0 = 1 1 AND 1 = 1 1 OR 1 = 1 1 XOR 1 = 0 NOT 0 = 1 NOT 1 = 0
and ax,1 ; wyzeruje wszystkie bity z ; wyjątkiem bitu numer 0. or ebx,1111b ; ustawia (włącza) 4 dolne bity. ; Reszta bez zmian. xor cx,cx ; CX = 0 not dh ; DH ma 0 tam, gdzie miał 1 ; i na odwrót
SAL, SHL - shift left - przesunięcie w lewoSHR - shift logical right - przesunięcie logiczne w prawoSAR - shift arithmetic right - przesunięcie arytmetyczne (z zachowaniem znaku) w prawoROL - rotate left - obrót w lewoRCL - rotate through carry left - obrót przez flagę CF (flagę przepełnienia) w lewoROR - rotate right - obrót w prawoRCR - rotate through carry right - obrót przez flagę CF w prawoOczywiście, te instrukcje mogą działać na wartościach większych niż bajt - bit7 jako najstarszy jest tutaj tylko dla ilustracji.
Przy pomocy SHL można przeprowadzać szybkie mnożenie, a dzięki SHR
- szybkie dzielenie. Na przykład, SHL AX,1 jest równoważne przemnożeniu AX przez 2,
SHL AX,5 - przez 2^5, czyli 32. SHR BX,4 dzieli BX przez 16.
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 równy 1), JNS,
JP=JPE (jump if parity equal =
liczba bitów równych jeden jest parzysta), JNP=JPO.JMP, JMP SHORT, JMP FARCALL [NEAR/FAR] RET, RETF.
INT, INTO (wywołuje przerwanie INT4 w razie przepełnienia),
BOUND (int 5)LOOP. Składnia:
LOOP gdzieś.
Jeśli CX jest różny od 0, to skacz gdzieś.
LODS[B/W/D/Q] - Load Byte/Word/Dword/Qword - pobierz bajt/słowo/podwójne słowo/poczwórne słowoADD, gdy flaga kierunku DF = 0,
SUB gdy DF = 1STOS[B/W/D/Q] - Store Byte/Word/Dword/Qword - zapisz bajt/słowo/podwójne słowo/poczwórne słowoADD/SUB jak wyżejMOVS[B/W/D/Q] - Move Byte/Word/Dword/Qword - przesuń (skopiuj) bajt/słowo/podwójne słowo/poczwórne słowoADD/SUB jak wyżejCMPS[B/W/D/Q] - Compare Byte/Word/Dword/Qword - porównaj bajt/słowo/podwójne słowo/poczwórne słowoADD/SUB jak wyżejSCAS[B/W/D/Q] - Scan Byte/Word/Dword/Qword - szukaj bajtu/słowa/podwójnego słowa/poczwórnego słowaDo każdej z powyższych instrukcji można z przodu dodać przedrostek REP
(repeat), co spowoduje, że będzie ona wykonywana, aż CX stanie się zerem,
albo REPE/REPZ albo REPNE/REPNZ co spowoduje,
że będzie ona wykonywana, dopóty CX nie jest zerem i jednocześnie flaga ZF (flaga zera) będzie równa
odpowiednio 1 lub 0.
ININ AL/AX/EAX, port/DXPobierz z portu 1/2/4 bajty i włóż do AL/AX/EAX (od najmłodszego). Jeśli numer portu jest mniejszy lub równy 255, można go podać bezpośrednio. Jeśli większy - trzeba użyć DX.
OUTOUT port/DX, AL/AX/EAXIN.STC/CLC - set carry / clear carry.
Do flagi przepełnienia CF wstaw 1 lub 0, odpowiednio.STD/CLD. Ustaw flagę kierunku DF na 1 lub 0, odpowiednio.STI/CLI. Interrupt Flag (flaga włączenia przerwań) IF = 1 lub IF = 0, odpowiednio.
Gdy IF=0, przerwania sprzętowe są blokowane.PUSHF / PUSHFD
/ PUSHFQ
- umieść flagi na stosie (16, 32 i 64 bity flag, odpowiednio)POPF / POPFD / POPFQ - zdejmij flagi ze stosu
(16/32/64 bity flag)SAHF / LAHF - zapisz AH w pierwszych 8 bitach flag / zapisz
pierwsze 8 bitów flag w AH.LEA - Load Effective Address - załaduj wyliczony adres.lea rej, [pamięć]jest równoważne:
mov rej, pamięć ; NASM/FASMPo co więc osobna instrukcja? Otóż,
LEA
przydaje sie w wielu sytuacjach do obliczania złożonych adresów. Kilka przykładów:
lea eax, [ebp-12]
lea ecx, [ebx + 11*8] oraz lea edx,[ebx+edi*8]
lea esi, [eax + eax*8]
Pominąłem mniej ważne instrukcje operujące na rejestrach segmentowych i klika innych instrukcji.
Te, które tu podałem, wystarczają absolutnie na napisanie większości programów, które można
zrobić.
Wszystkie informacje przedstawione w tej części pochodzą z tego samego źródła:
Intel
i AMD
Byle głupiec potrafi napisać kod, który zrozumie komputer. Dobry programista pisze taki kod, który zrozumie człowiek.