10. diel - Assembler - Kombinácia skokov a príznaky
V minulej lekcii, Assembler - Podmienené a nepodmienené skoky , sme si povedali niečo o nepodmienených a podmienených skokoch, pomocou ktorých môžeme vytvoriť podmienky a cykly známe z vyšších jazykov.
V dnešnom ASM tutoriálu sa naučíme kombinovať podmienené a nepodmienené skoky, zistíme, ako skokové inštrukcie získajú výsledok z CMP a ako porovnávať signed čísla.
Príklad - Podmienené a nepodmienené skoky dohromady
Hovorili sme si, že môžeme podmienené a nepodmienené skoky ľahko kombinovať. Ukážme si teda na príklade, ako sa používajú dohromady:
zacatek: mov cx, 5 .znovu: mov si, message call print_string dec cx cmp cx, 0 jz .return jmp .znovu .return: mov si, konec call print_string ret print_string: lodsb cmp al, 0 jz .return mov ah, 0eh mov bx, 7h int 10h jmp print_string .return: ret message db 'CX != 0', 13, 10, 0 konec db 'CX == 0', 0
Z kódy by ste už mali vyčítať, že vypisuje text 5x, teda dokiaľ nie je
CX
rovné 0
. Vyskúšali sme si tak aj inštrukciu
DEC
k zníženiu hodnoty a vlastne sme si napísali inštrukciu
loop
.
Všimnite si použitie funkcie print_string
, ktorú
som už používali, ako príkladu. A tiež. že ak dáme pred návesťou
.
, Stane sa z neho "pod-návesťou" a nemusíme tak používať
očíslovanie pod. (Platí pre NASM).
Príznaky
Už vieme, že CMP
vykoná operáciu A - B
a na jej
výsledok potom pomocou ďalších inštrukcií reagujeme. Ako ale tieto
inštrukcie vedia, aký výsledok bol? CMP
totiž podľa výsledku
porovnania nastaví tzv. Flagy (príznakmi) a nasledujúce skákacie inštrukcie
reagujú na hodnoty uložené v týchto príznakoch.
Ak poznáte princípy počítačov, viete, že odčítanie sa vnútorne vykonáva ako pripočítanie dvojkového doplnku druhého čísla.
Flagy nastavuje okrem CMP
aj niekoľko ďalších
inštrukcií a nemusí nastaviť všetky, ale len niektoré z nich. Nie sú teda
len záležitosť porovnávanie, ale aj niekoľkých ďalších inštrukcií,
napr. I tých aritmetických.
Flagy môžu byť vždy buď 1
alebo 0
. V registri
EFLAGS
je veľké množstvo flagov, ale v podmienených skokoch sa
používajú len tieto flagy:
ZF
- Zero flag - Nastaví sa, ak je výsledok0
.SF
- Sign flag - Nastaví sa, ak je najvyšší bit výsledku operácie1
(MSB ako Most Significant Bit, obvykle ten najviac vľavo). Názov pochádza od toho, že ak je číslo uložené ako signed, tak tento bit v čísle označuje, či je číslo záporné alebo nie.CF
- Carry flag - Nastaví sa, ak pri operácii došlo k pretečeniu (napr. Pripočítame1
k255
v premennej s veľkosťou1
bajt). Výsledok bude teda0
, ale zapne sa flag Carry. Ak máme signed číslo, tak tam sa o pretečeniu dozvieme z Flag overflow nižšie.OF
- Overflow flag - Nastaví sa, ak dôjde k pretečeniu hodnoty signed čísla (pre tento typ čísel nemožno na overenie pretečeniu použiť Carry flag).PF
- Parity flag - Flag parity sa nastaví, pokiaľ je v najnižšom bajtu výsledku párny počet jednotkových bitov.
Tabuľka skokov vrátane príznakov a porovnávanie signed čísel
Keďže už poznáme flagy, môžeme si uviesť ďalšie, kompletnejšie
tabuľku skokov a uviesť do nej na aký flag nastavený
pomocou CMP
daná skoková inštrukcia reaguje.
Tiež si pridáme inštrukcie pre prácu so signed číslami.
Takých tabuliek nás čaká ešte veľa, ASM je veľa o tabuľkách
inštrukcií:)
inštrukcie | Porovnanie | popis | typ čísel | flagy |
---|---|---|---|---|
JO (Jump if Overflow) | Skočí, ak došlo k pretečeniu | OF == 1 | ||
JNO (Jump if Not Overflow) | Skočí, ak nedošlo k pretečeniu | OF == 0 | ||
JS (Jump if Sign) | Skočí, ak bol nastavený sign bit | SF == 1 | ||
JNS (Jump if Not Sign) | Skočí, pokiaľ nebol nastavený sign bit | SF == 0 | ||
JE (Jump if Equal) JZ (Jump if Zero) |
A == B | Skočí, ak hodnoty rovné Skočí, ak bol rozdiel hodnôt 0 |
ZF == 1 | |
JNE (Jump if Not Equal) JNZ (Jump if Not Zero) |
A! = B | Skočí, ak hodnoty rovné Skočí, pokiaľ nebol rozdiel hodnôt 0 |
ZF == 0 | |
JB (Jump if Below) JNAE (Jump if Not Above or Equal) JC (Jump if Carry) |
A <B | Skočí, ak bol rozdiel hodnôt záporný Skočí, ak bola hodnota menšia Skočí, ak bol nastavený flag carry |
unsigned | CF == 1 |
JNB (Jump if Not Below) JAE (Jump if Above or Equal) JNC (Jump if Not Carry) |
A> = B | Skočí, pokiaľ nebola hodnota menšia Skočí, pokiaľ nebol rozdiel hodnôt väčší alebo rovný 0 Skočí, pokiaľ nebol nastavený flag carry |
unsigned | CF == 0 |
JBE (Jump if Below or Equal) JNA (Jump if Not Above) |
A <= B | Skočí, ak bola hodnota menšia alebo rovná Skočí, ak bol rozdiel hodnôt menší alebo rovný 0 |
unsigned | CF == 1 alebo ZF == 1 |
JA (Jump if Above) JNBE (Jump if Not Below or Equal) |
A> B | Skočí, ak bola hodnota väčšia Skočí, ak bol rozdiel hodnôt väčší alebo rovný 0 |
unsigned | CF == 0 a ZF == 0 |
JL (Jump if Less) JNGE (Jump if Not Greater or Equal) |
A <B | Skočí, ak bola hodnota menšia Skočí, ak hodnota nebola väčšia alebo rovná |
signed | SF! = OF |
JGE (Jump if Greater or Equal) JNL (Jump if Not Less) |
A> = B | Skočí, ak bola hodnota väčšia alebo rovná Skočí, ak hodnota nebola menšia |
signed | SF == OF |
JLE (Jump if Less or Equal) JNG (Jump if Not Greater) |
A <= B | Skočí, ak bola hodnota menšia alebo rovná Skočí, ak hodnota nebola väčšia |
signed | ZF == 1 alebo SF! = OF |
JG (Jump if Greater) JNLE (Jump if Not Less or Equal) |
A> B | Skočí, ak bola hodnota väčšia Skočí, ak hodnota nebola menšia alebo rovná |
signed | ZF == 0 a SF == OF |
JP (Jump if Parity) JPE (Jump if Parity Even) |
Skočí, ak bol nastavený parity bit Skočí, ak bola párna parita |
PF == 1 | ||
JNP (Jump if Not Parity) JPO (Jump if Parity Odd) |
Skočí, pokiaľ nebol nastavený parity bit Skočí, ak bola nepárna parita |
PF == 0 |
Niektoré uvedené skoky podľa príznakov sa nepoužívajú tak často. My ich budeme používať napr. K tomu, aby sme vedeli, či sa nejaká operácia podarila, alebo nie.
V budúcej lekcii, Assembler - Registre procesora , si ukážeme skoro všetky registre procesorov x86 a x64.