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).
AND
OR
XOR
NOT
TEST
Instrukcja 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 FAR
CALL [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.
IN
IN AL/AX/EAX, port/DX
Pobierz 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.
OUT
OUT port/DX, AL/AX/EAX
IN
.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.