| |Wprowadzenie|
Chyba nikogo nie musze
uswiadamiac jak wazna jest znajomosc assemblera dla badaczy kodu.
Jezyk ten bedacy mnemonika kodu maszynowego procesorow ulega
zatraceniu w dzisiejszych czasach w dobie pakietow typu Visual
Microsoftu, Borlanada i innych. Nowoczesni (czytaj. nowi -:))
programisci nie maja nawet pojecia czym jest assebler i jak go
ugrysc a przeciez kod asemblera jest esencja programowania i dlatego
kazdy badacz kodu musi go poznać. Postanowilem przedstawic wam maly
guide wprowadzajacy do asemblera dla wszystkich poczatkujacych
crackerów i pod ich kierunkiem pisany. Jest to jedynie schematyczny
przeglad podstawowych pojec i instrukcji, który mam nadzieje
rozwine w przyszlosci. W ZADNY WYPADKU NIE JEST TO TUTOR
programowania w asm, jedynie przedstawia zagadnienia na ktore nalezy
zwrocic uwage podczas analizy kodu. No ale mam nadzieje :-) ze kazdy
kto to przeczyta wezmie sie za asm'a porzadnie i bedzie pisal w nim
programy w razie potrzeby.
[ Rejestry ]
Rejestry sa podstawowym miejscem
przechowywania danych. Sa to 16-bitowe komorki procesora. Jest 14
rejestrów i w tym 12 rejestrow danych i adresowych, rejestr
wskaznika instrukcji (IP) i rejestr
znacznikow. Rejestry danych i adresowych mozemy podzielic na kilka
grup i tak:
AX (akumulator) --------+
BX (bazowy) |----- Rejestry ogólnego
przenzaczenia
CX (licznik) |
DX (danych) --------+
SP (wskaznik stosu) --------+
BP (wskaznik bazy) |-----Rejestrywskaznikowe i
indeksowe
SI (index zrodla) |
DI (indeks przeznaczenia) --------+
CS (programu) --------+
DS (danych) |----- Rejstry segmentowe
SS (stosu) |
ES (dodatkowy) --------+
IP (wskaznik instrukcji)
I Rejestr Znacznikow
Jak oczywiscie kazdy sie zorientowal przy pracy w
Win32 rejestry okreslane sa jak EAX, EAX itd, oznacza to ze sa to
odpowiedniki powyzszych rejestrow, tyle, ze 32-bitowe.
Chwila wyjasnienia z tymi bitami. Wezmy rejestr AX,
ktoryjest 16 bitowy i dzieli sie na dwa podrejestry 8 bitowe AH i
AL. Jak wiemy 8 bitow tworzy bajt, ktory przyjumuje wartosc od 0 do
255, czyli
rejestr AH i AL moze miec najwieksza wartosc FFh. Logicznie myslac
-:) rejestr 16 bitowy moze przyjac maksymalna wartosc FFFFh itd. (32
bit EAX mam max FFFFFFFFh ups-:)). Chyba kazdy lapie co daja 32
bitowe rejestry i jak zwiekszaja sie mozliwosci.
Warto zapoznac sie z charakterystykami rejestrow,
gdzyz kazdy ma swoje wlasne konkretne zastowsowanie. Przegladajac
kod programu mozemy zauazyc pewne prawidlowosci, np.
EIP -
debugujac pod SoftIce 32bit widzimy, ze rejestr ten wskazuje na
aktualny kod instrukcji i mozemy go uzyc np do zalozenia pulapki na
danej lini czyli bpx EIP lub dokladniej CS:EIP.
CS -
wskazuje segment kodu, czyli jak mamy jakac linie kodu o adresie np.
14F:04033232 to mozemy ja zapisac jako CS:04033232 poniewaz w
rejestrze CS jest zachowana wartosc 014F.
DS -
podobnie jak powyzej, zawiera adres segmentu dany, jezeli w okienku
danych pod SoftIce mamy jakis adres np. 0145:03055555 to DS wskazuje
segment 0145.
ESI i EDI sa
wskaznikami danych np. do porownan tekstow itp. Wezmy np. instrukcje
porownywania w bibliotekach VB - reps cmpsw dla, ktorych w w ds:esi
i es:edi zawarte sa adresy tekstow (np. numerow
seryjnych) do porwnania. To samo tyczy sie wielu instrukcji
przesylania i porownnywania danych, gdzie przeznaczenie i cel
zawarte sa w rejesteach SI i DI np:
LEA SI, ZRODLo ;Zaladowanie adresu zrodla
LEA DI, ES:PRzesznaczenie ;Zaladowanie adresu przezanczenia
MOV CX,100 ;Zaladowanie licznika elementow
MOVS Przeznaczenie,Zrodlo ;Kopiowanie tekstu z jednego
miejsca w innne.
|Rejestry - specyfikacja
architektury intela|
Rejestry ogolnego przeznaczenia Rejestry segmentowe
AH/AL AX (EAX) Akumulator CS Programu
BH/BL BX (EBX) Bazowy DS Danych
CH/CL CX (ECX) Licznik SS Stosu
DH/DL DX (EDX) Danych ES Dodatkowy
(Exx) znaczy 386+ 32 bit rejestr
Rejestry wskaznikowe Rejestry stosu
SI (ESI) Indeks zrodla SP (ESP) Wskaznik stosu
DI (EDI) Indeks przeznaczenia BP (EBP) Wskaznik bazy
IP Wskaznik instrukcji
FLAGI Rejestr Znacznikow (zobacz FLAGI)
Specjalne rejestry (386+)
CR0 Control Register 0 DR0 Debug Register 0
CR2 Control Register 2 DR1 Debug Register 1
CR3 Control Register 3 DR2 Debug Register 2
DR3 Debug Register 3
TR4 Test Register 4 DR6 Debug Register 6
TR5 Test Register 5 DR7 Debug Register 7
TR6 Test Register 6
TR7 Test Register 7
Rejestry ogolnego przeznaczenia sa
przeznaczzone do przechowywania dowolnych danych i wykonywania
roznych operacji (arytmetycznych, logicznych itp) , pelnia takze
funkcje specjalne odpowiadajace ich
nazwom.
AX (accumulator)
- rejestr ten jest najczesciej uzywany przy operacjach mnozenia i
dzielenia, a takze w operacjach logicznych, arytmetycznych i
odkladania wynikow wielu operacji. 8 dolnych bitow tego rejstru
okresla sie jako rejestr AL, a 8 gornych bitow jako AH
BX (basis) -
rejestr bazowy moze byc uzywany jako dwa 8-bitowe rejestry BH i BL,
a np. jako 16-bit mozemy go uzyc do utworzenia adresu pamieci,
tworzac z rejestrem segmentowym pelny adres -
Segmennt:Offset - DS:BX
CX (count) -
rejestr zliczajacy jest wykorzystywany oprocz zliczania takze do
przesylania danych. Moze byc takze uzywany jako dwa rejestry
8-bitowe CH i CL.
DX (data) -
rejestr danych wykorzystuje sie przy dzieleniu i mnozeniu. Jest
takze jedynym rejestrem, w korym mozna podac adres portu w rozkazach
wejscia-wyjscia.
Rejestry segmentowe sluza do adresowania pamieci
operacyjnej.
CS (code segment)
- rejestr wskazuje poczatek segmentu kodu programu, tworzy pelny
adres wraz z rejestrem IP - CS:IP. Rozkazy programu, skoki, powroty
pobierane sa w odniesieniu do tego
rejestru.
DS (data segment)
- rejestr wskazujacy poczatek segmentu danych
SS (stack segment)
- rejestr stosu wskazuje poczatek segmentu stosu
ES (extra segment)
- rejestr dodatkowu wskazujacy dodatkowy segment danych
Rejestry wskaznikow. Dostep do danych adresowany
jest przez polaczenie adresu z rejestru segmentu z przesunieciem
pobieranym z innego rejestru min. rejestru wskaznikowego.
SI (source index)
- rejestr indeksowy zrodla, najczesciej stosowany przy adresowaniu w
innstrukcjach przetwarzajacych lancuchy znakow, tworzy wowczas pelny
adres DS:SI
DI (destination index)
- rejestr indeksowy przeznaczenia, podobnydo SI uzywany w
adresowaniu danych przy przetwarzaniu lancuchow znakow, tworzy
wowczas pelny adres ES:DI
SP (stack pointer)
- wskaznik stosu tworzy wraz z SS - SS:SP adres danej odeslanej na
stos i jest wykorzystywany przy pobieraniu i zapisywaniu danych na
stos.
BP (base pointer)
- wskaznik bazy uzywany jest podczas operacji niestandardowych np.
przy pobieraniu parametrow przekazywanych na stos.
IP (instruction pointer) -
wskaznik instrukcji wskazuje na aktualnie wykonywana instrukcje i
wraz z rejestrem segmentu kodu tworzy pelny adres - CS:IP. IP
wskazuje offset (przesuniecie) wzgledem poczatku segmentu programu.
| Flagi - rejestr znaczników|
Falgi sa komorkami, ktore moga
przyjmowac wartosc 0 lub 1 i sa zawarte w rejestrze znacznikow.
Odpowiednie ustawienie poszczegolnych flag decyduje o wykonaniu
innych instrukcji a szczegolnie instrukci warunkowych. Najszybciej
zrozumiec flagi mozna na przykladzie :
CMP AX,BX - Porownaj rejestry AX z BX, jezeli
rowne to flaga zerowa Z ustawiona na 1
JZ 0401233 - Jezeli flaga Z ustawiona na 1 to wykonaj skok do adrsu
0401233
Oczywiscie intrukcja CMP ustawia takze inne flagi
z zaleznosci od wyniku porownania i podobnie inne instrukcje
warunkowych skokow moga sprawdzac takze inne flagi. Szczegolowiej
przedstawie to przy omowieniu skokow warunkowych.
Po co nam znajomoasc flag, ano poto aby podzczas
analizy kodu wiedziec jaki wynik dalo porownanie danych i czy np.
skok zostanie wykonany czy nie. Poza tym debugujac program mozem
zmienic dzialanie instrukcji skoku zmieniajac stan znacznikow.
Np. w powyzszym przykladzie AX jest rowne BX i
flaga zerowa Z zostala ustawiona na 1 wiec skok warunkowy zostanie
wykonany. Jezeli jednak mimo rownosci AX i BX nie chcemy wykonac
skoku to podczas sledzenia programu resetujemy flage zerowa. W
SoftIce robimy to : r fl z (czyli resetuj flage zerowa) i skok nie
zostanie wykonany :-)
Ciekawostki :
Bit 6 rejestru znacznikow - znacznik zera, najwazniejsza przy
pierwszych krokach lamania programow. Decyduje o podstawowych
skoksach warunkowych :-)
Bit 8 rejestru znacznikow - flaga pracy krokowej (TF
- trap flag) ustawia procesor w trybie pracy krokowej w celu
uruchomienia programu pod debugerem,
Bit 10 rejestru znacznikow - flaga kierunku (DF -
direction flag) wymusza zwiekszania lub zmniejszanie rejestrow
indeksowych przy wykonywaniu instrukcji operujacych na lancuchach
czyli albo rosnaco albo malejaco (czyli od lewej do prawej albo na
odwrot). Czujecie, przeciez numer seryjny mozna spokojnie przeczytac
od koncz :-)
|Flagi - Rejestr znaczników -
specyfikacja Intel 8086|
Rejestr znacznikow jest 16-bitowym
rejestrem, szesc bitow zawiera informacje o stanach, trzy pozwalaja
sterowac praca procesora z poziomu programu a dwa pozostale zwiazane
sa z trybem wirtualnym.
|11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
| | | | | | | | | | | | | | | | | '--- CF Carry Flag
| | | | | | | | | | | | | | | | '--- 1
| | | | | | | | | | | | | | | '--- PF Parity Flag
| | | | | | | | | | | | | | '--- 0
| | | | | | | | | | | | | '--- AF Auxiliary Flag
| | | | | | | | | | | | '--- 0
| | | | | | | | | | | '--- ZF Zero Flag
| | | | | | | | | | '--- SF Sign Flag
| | | | | | | | | '--- TF Trap Flag (Single Step)
| | | | | | | | '--- IF Interrupt Flag
| | | | | | | '--- DF Direction Flag
| | | | | | '--- OF Overflow flag
| | | | '----- IOPL I/O Privilege Level (286+ only)
| | | '----- NT Nested Task Flag (286+ only)
| | '----- 0
| '----- RF Resume Flag (386+ only)
'------ VM Virtual Mode Flag (386+ only)
Bit 0, (CARRY FALG)
CF - Znacznik przeniesienia, ma wartosc 1
jesli dodawanie powoduje przeniesienie lub odejmowanie powoduje
pozyczenie, w przeciwnym razie ma wartosc 0. CF zawiera takze
wartosc przesuniecia lu przesunietego cyklicznie bitu wychodzacego
poza rejestr lub komorke pamieci, oddaje takze wynik operacji
porownania. CF dziala takze jako wskaznik dla operacji mnozenia.
Bit 2, (PARITY FLAG)
- Znacznik parzystosci - ma wartosc 1 gdy wynik operacji ma parzysta
ilosc bitow o wartosci 1, w przeciwnym wypadku znnacznik przyjmuje
wartosc 0. PF jest glownie uzywany przy przesylaniu danych.
Bit 4, (AUXILIARY CARRY FLAG)
- znacznik przeniesienia pomocniczego - ma podobne znaczenie jak CF,
ale pokazuje przeniesienie lub pozuczke od bitu 3 w gore. AF jest
uzyteczny przy dzialaniach na "spakowanych" liczbach
dziesietnych.
Bit 6, (ZERO FLAG)
- znacznik zera - ma wartosc 1 gdy wynik operacji jest zerem, wynik
rozny od zera ustawia na 0
Bit 7 - (SIGN FLAG)
- znacznik znaku - ma znaczenie tylko podczas operacji na liczbach
ze znakiem, SF przyjmuje wartosc 1 jesli wynikiem operacji
arytmetycznych, logicznych, przesunniec jest wartosc ujemna, w
przeciwnym wypadku przyjmuje wartosc 0. Inaczej mowiac SF pokazuje
najbardziej znaczasy bot (bit znaku) wyniku, niezaleznie czy wynik
jest 8 czy 16-bitowy
Bit 8 - (TRAP FLAG)
- znacznik pracy krokowej - ustawia procesor w trybie pracy
krokowej, w celu uruchomienia programu po debugerem.
Bit 9 - (INTERRUPT FLAG)
- znacznik zezwolenia na przerwanie - zezwala procesorowi rozpoznac
zadanie obslugi przerwan pochodzace od zewnetrznych urzadzen
systemu. Wyzerownie IF powoduje, ze procesor ignoruje przerwania.
Bit 10 - (DIRECTORY FLAG)
- znacznik kierunku - wymusza zmniejszenie (DF=1) lub zwiekszenie (DF=0)
rejestrow indeksowych po wykoniu instrukcji operujacych na
lancuchach. Jesli DF =0 to procesor przetwarza lancuchy w kierunku
rosnaczych adresow (od strony lewej do prawej) a jak 1 to w kierunku
odwrotnym.
Bit 11 - (OVERFLOW FLAG)
- znacznik nadmiaru - jest glownie wskaznikiem bledu podczs operacji
na liczbaczh ze znakiem. OF=1 jesli dodanie dwoch liczb z jednakowym
znakiem lub odjecie dwoch liczb z roznymi znakami daje wynik nie
mieszczacy sie w argumencie wykonanej instrukcji, w przeciwnym
przypadku znacznik jest 0. OF ma takze wartosc 1 gdy najbardzej
znaczacy bit (bit znaku) argumentu zostanie zmieniony przez
przesuniecie podczas operacji arytmetycznej, w przeciwnym przypadku
jest 0. Znacznik OF, razem ze znacznikiem CF, wskazuje takze dlugosc
wyniku mnozenia. Jesli bardziej znaczaca czesc iloczynu jest rozna
od zera to OF i CF sa rowne 1, jezeli jest inaczej to oba znaczniki
sa rowne 0. OF takze przyjmuje wartosc 1 gdy operacja z dzielenia
daje iloraz przekraczajacy rejestr przeznaczenia.
| Stos /Stack/|
Stos jest miejscem przechowywania danych jak
rejestry lub zawartosci komorek pamieci. Mamy dwie instrukcje PUSH,
ktora przesyla dane na szczyt stosu i POP, ktora pobiera dane ze
szczytu stosu. O co biega z tymi szczytami :-), stos jest sterta na
ktorej ukladane sa dane, kazda dana ukladana jest na szczyt a
poprzednia dana schodzi na dalsza pozycje. Czyli istotna jest
kolejnosc kladzenia danych na stos, gdyz w takiej samej( a dokladnie
odwrotnej) kolejnosci musimy pobierac dane ze stosu:
PUSH EAX - kladzie na szczyt stosu EAX
PUSH EBX - kladzie na szczyt stosu EBX a EAX schodzi na dalsza
pozycje
....instrukcje
POP EBX - pobiera ze szczytu dana ktora jest EBX ( a na szczycie
zostaje EAX)
POP EAX - pobiera ze szczytu stosu EAX
Chyba lapiecie o co biega ?:-)
Acha jeszcze jedno, na szczyt stosu wskazuje tzw.
wskaznik stosu SP (Stack Pointer) a instrukcje PUSH i POP zwiekszaja
i zmniejszaja ten wskaznik. Rejestr ten nigdy nie jest ustawiany bo
procesor to robi automatycznie i zawsze wskazuje adres szczytu stosu
(szczytowego slowa).
Paczac ogolnie na pamiec komputera, kazda czesc
programu moze utworzyc swoja dowolna przestrzen stosu. Programista
powinien tak przydzielic pamiec aby stos nie pokrywal sie
przypadkiem z innymi obszarami pamieci :-)
|CALL i RET - wywołanie funkcji i procedur|
CALL adres wywoluje funkcje o podanym adresie i wykonuje ja
az do powrotu (RET).
instrukcje...
CALL 040ABCCC
Mov eax,edx
instrukcje...
Wywollanie CALL wywola funkcje o adrsie 040ABCCC i
po powrocie z niej (RET) program bedzie kontynuowal dalej MOV
eax,edx itd. Jak to sie dzieje, ze program wie gdzie ma wrocic ?.
Ano CALL kladzie adres kodu na stosie, natomiast RET pobiera ten
adres i wraca tam gdzie potrzeba.
Jezeli CALL wywoluje jakies funkcje, to argumenty
takiej funkcji kladziemy na stosie przed wywolanie CALL. Przyklad
takiego dzialania :
MOV EDI,[ESP+00000220] --- Zapisuje uchwyt okienka
dialogowego w EDI
PUSH 00000100 --- Maksymalny rozmiar tekstu na stos
PUSH 00406130 --- Adres bufora dla tekstu na stos
PUSH 00000405 --- Identyfikator na stos
PUSH EDI --- Uchwyt okienka dialogowego na stos
CALL GetWindowText --- Wywolanie funkcji o parametrach zapisanych na
stosie.
Widzimy wiec, ze przy jakis ciekawych wywolania
funkcji warto zagladnac jakie parametry kladzione sa na stosie i
ogolnie warto sie zorientowac jakie parametry dana funkcja wymaga.
|MOV - instrukcja przeniesienia|
To najczesciej spotykana
instrukcja umozliwiajaca przenoszenie danych pomiedzy rejestrem a
komorka lub pomiedzy rejestrami lub kopiowania stalej wartosci do
rejestru lub komorki. Ogolna postac to MOV przeznaczenie, zrodlo i
nie powinno nikomu sprawic klopotu jej zrozumienie.
Przyklady :
MOV EDS, EAX - przeniesienie pomiedzy dwoma rejestrami 32-bitowymi
MOV CL, 39 - przeniesienie stalej do rejestru
MOv ES:[BX],AX - zmiana przypisania segmentu
Kila uwag :
1). Nie mozna bezposrednio przeniesc danych
pomiedzy komorkami pamieci. Musimy dane najpier przeniesc dane do
rejestru ogolnego przeznaczenia a pozniej z rejestru do
przeznaczenia w pamieci. Przyklad, mamy dwie zmienne w pamieci np.
TYLEK i ZADEK i aby przenies wartosc z jednej do drugiej to
MOV AX,TYLEK
MOV ZADEK,AX
2). Nie mozna zaladowac bezposrednio stalej do
rejestru segmentu, musimy ja przenies przez rejestr ogolnego
przeznaczenia.
MOV AX, ADRES_DS
MOV DS, AX
3). Podobnie nie mozemy przenies bezposrednio
zawartosci jednego rejestru segmentu do drugiego, podobnie musimy
przez rejestr ogolnego przeznaczenia.
MOV AX, ES
MOV DS, AX
4). Nie mozna uzyc rejestru CS jaki argumentu
przeznaczenia w instrukcji MOV
Widzicie wiec jakie kombinacje nalezy wykonywac z
danymi i dlaczego az tak duzo instrukcji MOV mamy w kodzie programu.
Przy debugowaniu programu pamietajcie, ze w
rejestrze moze byc szukana przez nas wartosc lub adres wskazujacy na
ta szukana wartosc. A wiec sprawdzajac w SOFTICE dane jezeli uzyjemy
komendy np. d EAX to wyswietli nam w oknie danych zawartosc pamieci
o adresie zawartym w EAX, natomiast jak damy ? EAX to wyswietli nam
dane zawarte w EAX w postaci szesnastkowej i dziesietnej.
|CMP i skoki warunkowe|
Bardzo wazna instrukcja jest CMP (compare),
ktora decyduje o dzialaniu programu, petlach, skokach, wywolaniach
podprogramow itp. Instrukcaja CMP dziala na zasadzie odejmowania
zrodla od przeznaczenia i sprawdzaniu otrzymandego wyniku. Glownym
celem dzialania tej instrukcji jest ustawienie rejestrow w
zaleznosci od otrzymanego wynniku. W przypadku operacji na
argumentach bez znaku ustawiane sa dwie flagi - zerowa ZF i
przeniesienia CF, natomiast przy operacjach na argumentach ze
znakiem dodatkowo jeszcze - nadmiaru OF i znaku SF
Przyklad:
CM AX,BX - jezeli AX = BX to ZF=1 i CF=0 gdy AX > BX to ZF=0 i CF=1
gdy AX < BX to ZF i CF=0
Na podstawie spelnianych warunkow, czyli
ustawieniu poszczegolnych flag moga nastapic skoki warunkowe w
kodzie. Naczesciej spotykany JZ - skok jezeli ustawiona flaga Z
czyli np. w przypadku porownaia czy AX=BX i jezeli tak to skok.
Podobna instrukcja jest TEST, ktora dla odmiany
przeprowadza operacje logiczna na bajtach - AND ale nie zapamietuje
wyniku a jedynie na jego podstawie ustawia odpowiednio flagi.
Przyklad: CALL procedura procedura: MOV AX,1
TEST AX,AX CMP
Wpisany_kod, Dobry_kod
JZ adres2 JE dobrywpis
RET
dobrywpis: XOR
AX,AX
RET
Procedura CALL wywoluje np. procedure sprawdzania
poprawnosci danych rejestracyjnych i w przypadku pomyslnym zapisuje
do AX wartosci logiczna 0 (np. przez XOR AX,AX) a jezeli zle to
zapisuje 1. Teraz instrukcja TEST AX,AX wykonuje operacje logiczna
na AX czyli AX and AX, jezeli bylo (0 to 0) AND 0 da nam 0 i flaga
zerowa Z zostaje ustawiona na 1. Teraz instrukcja skoku warunkowego
sprawdza czy flaga zerow Z=1 i robi skok. Natomiast gdy by bylo (1
AND 1) to flaga Z=0 i skok nie nastapi.
A procedurka to wiadomo, napoczatku wpisujemy
wartosc logiczna 1 do AX (czyli zly kod) a pozniej sprawdzamy jaki
faktycznie jest wpisany kod, jezeli poprawny to skok i operacja (1
XOR 1) co da nam 0 w AX i powrot a jak zly to niech pozostanie 1 i
powrot
Nalezy pamietac, ze instrukcje CMP i TEST wykonuja
operacje na argumentach, ktorych wykonanie ustawia kilka
odpowiednich flag w zaleznosci od wielkosci argumentow, znaku,
przeniesienia itp. Dlatego tez mozemy wykonac odpowiednie skoki nie
tylko przy warunku A=B ale tez w zaleznosci czy mniejsze, wieksze,
ze znakiem itp.
Np. skok JA (skok gdy powyzej) wykonany jest gdy
flagi CF=0 i ZF=0 i wykonuje skok gdy przeznaczenie jest wieksze od
zrodlo (bo to wyniklo z operacji porownania i takiego ustawienia
flag). Od razu zaznaczam, ze analizujac kod pod SoftIce aby zmienic
skok np. musimy nie tylko zmienic flage Z ale i C (czyli np. r fl z;
r fl c). To samo tyczy sie innych skokow warunkowych i zapraszam do
tabeli specyfikacji skokow warunkowych.
|Specyfikacja skoków warunkowych|
Instrukcja Opis Skok jesli.....
JA skok gdy powyzej CF=0 i ZF=0
JAE skok gdy powyzej lub rowny CF=0
JB skok gdy ponizej CF=1
JBE skok gdy ponizej lub rowny CF=1 or ZF=1
JC skok gdy przeniesienie CF=1
JCXZ skok gdy CX=0 CX=0
JE skok gdy jest rowny ZF=1
JG skok gdy wiekszy * ZF=0 and
SF=OF
JGE skok gdy wiekszy lub rowny * SF=OF
JL skok gdy mniejszy SF != OF
JLE skok gdy mniejszy lub rowny * ZF=1 or SF
!= OF
JMP skok bezwarunkowy bez warunku
JNA skok gdy nie powyzej CF=1 or ZF=1
JNAE skok gdy nie powyzej ani rowny CF=1
JNB skok gdy nie ponizej CF=0
JNBE skok gdy nie ponizej ani rowny CF=0 and
ZF=0
JNC skok gdy nie ma przeniesienia CF=0
JNE skok gdy nie rowny ZF=0
JNG skok gdy nie wiekszy ZF=1 or SF
!= OF
JNGE skok gdy nie wiekszy ani rowny * SF != OF
JNL skok gdy nie mniejszy * SF=OF
JNLE skok gdy nie mniejszy ani rowny * ZF=0 and
SF=OF
JNO skok gdy niema przepelnienia * OF=0
JNP skok gdy nie parzystosc PF=0
JNS skok gdy brak znaku * SF=0
JNZ skok gdy rozne od zera ZF=0
JO skok gdy jest przepelnienie * OF=1
JP skok gdy parzystosc PF=1
JPE skok gdy parzystosc parzysta :-) PF=1
JPO skok gdy parzystosc nieparzysta PF=0
JS skok gdy jest znak * SF=1
JZ skok gdy jest zero ZF=1
* - wazne dla arytmetyki liczb ze znakiem (uzupelnienie do dwoch)
|
|TEST EAX,EAX - co to znaczy ?|
Powyzsza linia kodu wydaje sie niezrozumiala. Nalezy jednak
zastanowic sie co robi dokladnie. Instrukcja TEST wykonuje operacje
AND na dwoch argumentach i w oparciu o ten wynik ustawiane sa
odpowiednie flagi.
Nalezalo by wiec przeanalizowac czym jest operacja
mnozenia logicznego AND. Dziala on na argumentach rozmiaru bajt lub
slowo (ale nie na ich zwyklej postaci a postaci binarnej, bo dziala
dokladnie na bitach tych liczb).
Z matematyki wiemy ze 0 AND 0 = 0 ; 0 AND 1 =0 i 1
AND 0 = 0 a 1 AND 1 = 1 a wiec operacja daje wynik jeden wtedy i
tylko wtedy gdy oba bity rowne sa jeden.
Wezmy teraz TEST EAX, EAX. Zalozmy ze EAX=0 czyli
00000000 AND 00000000 = 00000000 czyli na kazdej pozycji bedzie 0 i
wtedy ustawiana jest flaga zerowa Z. Natomiast przy kazdej innej
wartosci np. 00000011 AND 00000011 da nam 00000011 i wtedy jezeli
gdziekolwiek na dowolnej pozycji wystapia w obu argumentach 1 to
flaga Z nie jest ustawiana.
Daje nam to mozliwosc sprawdzenia czy np. EAX jest
0 czy jakas inna wartoscia, gdzy tylko porownanie dwoch TYCH SAMYCH
liczb o wartosci 0 da nam 0 i ustawi flage. Operacja AND na kazdych
dwoch TAKICH SAMYCH roznych od zera nie ustawi flagi zerowej bo
zawsze gdzies bedzie 1 w bitach.
Dlatego tez w programach czesto spotykane
instrukcje TEST EAX,EAX a pozniej JZ adres maja calekiem logiczne
znaczenie bo skok nastapi tylko w przypadku EAX=0. Nie nalezy wiec
sugerowac sie domyslnym znaczeniem instrukcji prownania EAX z EAX
:-) |