Inštrukcie CMP a TEST
Porovnanie dvoch operandov vykonávajú inštrukcie CMP a TEST. Ako operandy môžeme použiť registre alebo operand uložený v pamäti v známych veľkostiach 8, 16 a 32 bitov.
Názov inštrukcie CMP je odvodený z anglického slova compare (porovnaj). Inštrukcia je implementovaná podobne ako inštrukcia SUB. Operand o2 sa odpočíta od operanda ol. Výsledok sa nikam neuloží, zmenia sa len príznaky v registri príznakov. Inštrukciu CMP môžeme použiť na porovnanie celých čísel bez znamienka aj so znamienkom.
Inštrukcia TEST pracuje podobne, miesto rozdielu operandov sa vykoná ich bitový súčin (AND). Výsledkom sú novo nastavené príznaky v registri príznakov. Inštrukciu TEST používame pre testovanie hodnôt jednotlivých bitov v bitovom poli.
Ukážme si niekoľko príkladov:
cmp ax, 4 ; porovná register AX s hodnotou 4
cmp dl, ah ; porovná register DL s registrom AH
cmp [prumerl], ax ; porovná obsah "premennej" prumer s registrom AX
cmp ax, [prumerl] ; porovná register AX s obsahom "premennej" prumer
cmp eax, ecx ; porovná registre EAX a ECX
test ax, 00000100b ; testujeme bit 2 (tretia) bit, ak je nastavený
Inštrukcie nepodmieného skoku JMP
Prvým spôsobom, ako zmeniť sekvenčné vykonávanie inštrukcií v programe, je použitie inštrukcie nepodmienečného skoku. Inštrukcia prinúti procesor spracovávať inštrukcie z iného miesta v pamäti (prepíše hodnoty ukazovateľa na ďalšiu inštrukciu, register IP alebo i CS).
Syntax: JMP typ_skoku operand
Nepodmienený skok známy z vyšších programovacích jazykov pod názvom GOTO v Assembleru predstavuje inštrukcia JMP. Názov vznikol z anglického slova jump (skoč). Inštrukcia vyžaduje jediný priamy operand, ktorým je adresa miesta v pamäti, kam sa má skočiť (ako operand možno použiť aj univerzálny register naplnený adresou skoku, čo by som začiatočníkom neodporúčal). V Assembleri sú rovnako ako vo vyšších programovacích jazykoch adresy skokov reprezentované návestiami (label).
Podľa “vzdialenosti” skoku v programe rozlišujeme tri druhy skokov: short, near a far. (Krátky, blízky a vzdialený).
Maximálna “dĺžka” skoku (maximálny absolútny rozdiel adries, ktorý možeme skokom zmeniť) typu short je obmedzená. V druhom byte inštrukcie je uložená len 8-bitová hodnota sa znamienkom, preto adresa cieľa skoku smie ležať iba v rozmedzí -128 až 127 byte. Skok sa vykoná tak, že sa 8-bitová hodnota znamienkovo rozšíri a pripočíta sa k súčasnej hodnote registra (E)IP.
Inštrukcia skoku typu near už obsahuje vo svojej strojovej reprezentácii novú hodnotu registra (E)IP, dĺžka skoku je obmedzená iba módom procesora. V reálnom režime procesora meníme inštrukciou jmp near register IP, preto sa smieme pohybovať len v rozmedzí jedného segmentu (64 KB), v chránenom režime používame register EIP a tak cieľ skoku môže ležať kdekoľvek v 4 GB adresového priestoru.
Skok far mení aj hodnotu segmentového registra CS, ktorý sa podieľa na výpočte adresy inštrukcie v pamäti. Súčasťou adresy skoku musí byť aj nová hodnota pre register CS.
Ak nie je typ skoku uvedený, predpokladá sa typ near.
Teraz trochu vo výklade “preskočíme” a povieme si, ako vyzerá návestie v Assembleri. Ide v podstate o identifikátor zakončený dvojbodkou, ktorému bola pri preklade pridelená adresa podľa miesta výskytu v programe. Ukážme si časť programu, kde je použité návestie:
mov ax, 4 ; do AX vlož hodnotu 4
novy_cyklus: ; návestie novy_cyklus
mov bx, ax ; do BX okopírujte AX
Ak chceme vykonať nepodmienený skok na návestie novy_cyklus, napíšeme inštrukciu:
jmp novy_cyklus; skok na novy_cyklus
Po jej prevedení sa program začne vykonávať od návestia novy_cyklus.
Nič nám nebráni najprv vykonať skok a neskôr v programe uviesť návestie. Prekladač pracuje “na viacerých priechodoch”, a preto aj také skoky dopredu vie spracovať. Časť programu používajúca dopredné skoky by mohla vyzerať nasledovne:
jmp start; skok na štart
ciel: ; návestie ciel
...
... ; ďalšie inštrukcie
start: ; návestie štart
jmp ciel ; skok na ciel
Vráťme sa ešte krátko k typom skokov, ktoré budeme síce ako začiatočníci využívať veľmi zriedka. Skok typu short použijeme všade tam, kde návestie “leží” do 128 B. Tak ušetríme 1B programového kódu, pretože preložená inštrukcia jmp short zaberá len dva byte (inštrukcia JMP alebo JMP near 3 alebo 5 byte). Možno vás desí predstava, ako odhadnúť vzdialenosť návestí v nepreloženom programe. Nemusíte sa báť, jednoducho to vyskúšajte, prekladač v prípade neúspechu zahlási chybu.
blizke_navestie: ; návestie blizke_navestie
.... ; Nejaké dalšie inštrukcie
jmp short blizke_navestie ; urobíme skok na blizke_navestie
Inštrukcie podmienených skokov Jx
Syntax: Jx návestie_ciela_skoku
Ďalším spôsobom, ako zmeniť sekvenčné vykonávanie inštrukcií v programe, je použitie inštrukcie podmieneného skoku.
Inšturkcií podmieneného skoku existuje celá rada. Navzájom sa odlišujú rozhodovaciu podmienkou, ktorá riadi vykonanie skoku. V závislosti od vyhodnotenia podmienky sa vykonávanie programu buď presunie na iné miesto, alebo program pokračuje na nasledujúcu adresu za inštrukciou skoku. Rozhodovaciou podmienkou sú stavy príznakov (niekoľkých alebo len jedného) príznakového registra procesora.
Ukážme si najpoužívanejšie inštrukcie, ktoré skočia na návestie splnené, ak bude podmienka splnená.
jz splnene ; skočí, ak je príznak ZF (zero flag, príznak nuly) nastavený na 1
jc splnene ; skočí, ak je príznak CF (carry flag, príznak prenosu) nastavený na 1
js splnene ; skočí, ak je nastavený príznak znamienka SF (signum flag)
jo splnene ; skočí, ak je nastavený príznak pretečenia
Všetky podmienky môžeme obrátiť (negovať).
jnz splnene; skočí, ak nie je príznak ZF (zero flag, príznak nuly) nastavený (je nula)
Podobne aj ostatné JNC, JNS a JNO.
Teraz môžeme s našimi znalosťami príslušných inštrukcií Assembleru podmienku IF naprogramovať. Ukážme si jednoduchý príklad, v ktorom budeme chcieť odovzdať riadenie programu (skočiť) na návestie je_tri, ak je hodnota v registri AX rovná trom.
V prvom kroku porovnáme hodnotu v registri AX s číslom 3, čo urobíme inštrukciou CMP.
cmp ax, 3; register AX porovnaj s hodnotou 3
Pri porovnaní na rovnosť použijeme inštrukciu JZ.
jz je_tri; skočí na návestie je_tri, ak bude hodnota AX = 3
Všimnime si, že pri porovnávaní rovnosti čísiel nezáleží na tom, či práve číslo chápeme ako číslo so znamienkom alebo bez.
Inštrukcia JZ vykoná skok na návestie je_tri, ak bude hodnota v registri AX rovná trom, inak bude program pokračovať inštrukciou nasledujúcou po JZ.
V ďalšom príklade budeme chcieť porovnať bez znamienka hodnoty v registri CL a AI .. Do registra BL zapísať jedničku, keď sú si hodnoty rovnaké, dvojku, ak je AL väčší ako CL, a trojku, ak je v registri AL menšie ako v CL
Porovnáme registre AL a CL, výsledok porovnania sa uloží do príznakového registra procesora a použitím rôznych inštrukcií skoku zabezpečíme výber správnej alternatívy a tým aj riešenie problému.
cmp al, cl ; porovnaj hodnoty uložené v AL a CL
jz zapis_l ; skoč na návestie zapis_l, ak AL = CL
cmp al, cl ; porovnaj hodnoty uložené v AL a CL
ja zapis_2 ; skoč na návestie zapis_2, ak AL> CL
mov bl, 3 ; do BL zapíš 3
koniec_if: ; tu je koniec nášho programu
zapis_1: ; návestie zapis_1
mov bl, 1 ; do BL zapíš 1
jmp koniec_if; skok na koniec nášho programu
zapis_2: ; návestie zapis_2
mov bl, 2 ; do BL zapíš 2
jmp koniec_if; skok na koniec nášho programu
Museli sme dokonca použiť nepodmienený skok, aby sme vrátili riadenie programu na pôvodné miesto. Riešenie možno ešte výrazne vylepšiť:
mov bl, 1 ; do BL zapíš 1
cmp al, cl ; porovnaj AL a CL
je koniec_if ; skoč na koniec programu, ak AL = CL
mov bl, 2 ; do BL zapíš 2
cmp al, cl ; porovnaj AL a CL
ja koniec_if ; skoč na koniec programu, ak AL > CL
mov bl, 3 ; do BL zapíš 3
koniec_if: ; koniec programu
VN:F [1.9.3_1094]
Rating: 9.0/10 (1 vote cast)