Bölüm 7: Akış Kontrolü
Giriş
Öğrenme Çıktıları
JMP ve etiketlerle programın akışını yönlendirmek; IP'nin nasıl değiştiğini ve bağıl konumun (offset) nasıl hesaplandığını açıklamak.
Her koşullu atlamanın hangi bayrağa (ZF, CF, SF, OF, PF) baktığını söylemek ve zıt komutunu bulmak.
CMP sonrasında işaretsiz sayılar için JA/JB, işaretli sayılar için JG/JL ailesini doğru seçmek.
LOOP, LOOPE/LOOPZ, LOOPNE/LOOPNZ ve JCXZ ile sayaçlı döngüler yazmak; örnek programları adım adım izlemek.
Giriş
Program Akış Kontrolü
- İşlemci normalde komutları bellekteki sırasıyla yürütür: her komuttan sonra IP (Instruction Pointer) komutun uzunluğu kadar artar.
- Akış kontrol komutları IP'ye yeni bir değer yükleyerek yürütmeyi başka bir noktaya taşır.
- Böylece karar yapıları (if/else) ve döngüler (for/while) makine düzeyinde gerçekleştirilir.
JMP etiket: her zaman atlar.LOOP, LOOPE/LOOPZ, LOOPNE/LOOPNZ, JCXZ.Koşulsuz Atlama
JMP: Koşulsuz Atlama
JMP etiketkontrolü programın başka bir noktasına her koşulda aktarır; bayrakları değiştirmez.- Hem ileri hem geri atlayabilir.
- Yakın (near) atlama, mevcut kod kesimi içinde (64 KB = 65.536 bayt, offset 0000h–FFFFh) her yere ulaşır; yalnızca IP değişir.
- Uzak (far) atlama CS ve IP'yi birlikte değiştirerek başka bir kesime geçer.
- Assembler, hedef yakınsa otomatik olarak 2 baytlık kısa (short) biçimi seçebilir.
| Biçim | Kod | Bayt | Menzil |
|---|---|---|---|
JMP SHORT | EB rel8 | 2 | −128…+127 |
JMP NEAR | E9 rel16 | 3 | kesim içi |
JMP FAR | EA ofs seg | 5 | CS:IP |
JMP reg/mem | FF /4 | 2–4 | dolaylı |
Koşulsuz Atlama
Etiketler
- Etiket tanımlamak için adı yazılır ve sonuna
:eklenir:dongu: - Harf, rakam ve
_gibi karakterlerden oluşabilir, ancak rakamla başlayamaz. - Ayrı bir satırda ya da bir komutun önünde tanımlanabilir:
back: jmp stop - Etiket bellekte yer kaplamaz; assembler onu bir adrese (offset) dönüştürür.
- Komut adları ve yazmaç adları (
mov,ax…) etiket olarak kullanılamaz; her etiket bir kez tanımlanır.
Geçerli
dongu:next_char:k1:calc:
Geçersiz
1basla:rakamla başlıyormov:komut adıiki kelime:boşluk içeriyor
Koşulsuz Atlama · Kodu adım adım çalıştır
Kod İzleme: JMP ile İleri ve Geri
Program 0100h adresinden başlar (org 100h, .COM programı). IP = 0100h.
mov ax, 5 (3 bayt) yürütüldü: AX = 0005h, IP = 0103h.
mov bx, 2: BX = 0002h. Sıradaki komut 0106h adresindeki jmp calc.
jmp calc: IP ← calc = 010Ah. Arada kalan back: satırı atlanır.
add ax, bx: AX = 5 + 2 = 0007h.
jmp back: geriye atlama, IP ← 0108h.
back: jmp stop: tekrar ileri atlanır, IP ← 010Eh.
ret: program sonlanır. Sonuç AX = 0007h. Akış: 1 → 2 → 3 → calc → back → stop.
org 100h mov ax, 5 ; ax = 5 mov bx, 2 ; bx = 2 jmp calc ; 'calc' etiketine git back: jmp stop ; 'stop' etiketine git calc: add ax, bx ; ax = ax + bx jmp back ; 'back' etiketine dön stop: ret ; işletim sistemine dön
Koşulsuz Atlama
Bağıl Konum Hesabı
İleri atlama: uzaklık, atlama komutundan sonraki adrese göre hesaplanır → +2.
İşlemci yürütürken IP ← sonraki IP + rel8 = 010Ah + 4 = 010Eh.
Geri atlama: uzaklık negatiftir ve ikiye tümleyenle saklanır: −6 → FAh. 010Eh + FFFAh = 0108h (taşan bit atılır).
Koşullu Atlamalar
Koşullu Atlama Fikri
Jcc etiket: koşul (cc) doğruysa IP ← etiket, değilse bir sonraki komut yürütülür.- Koşul, önceki bir komutun (çoğunlukla
CMP,SUB,ADD,TEST,DEC) ayarladığı bayraklara bakılarak değerlendirilir. - Atlama komutlarının kendisi bayrakları değiştirmez.
Koşullu Atlamalar
Tek Bir Bayrağı Test Eden Atlamalar
| Komut | Anlamı | Koşul | Zıt komut |
|---|---|---|---|
| JZ, JE | Jump if Zero (Equal): sıfırsa / eşitse | ZF = 1 | JNZ, JNE |
| JC, JB, JNAE | Jump if Carry (Below, Not Above or Equal): elde varsa | CF = 1 | JNC, JNB, JAE |
| JS | Jump if Sign: sonuç negatifse | SF = 1 | JNS |
| JO | Jump if Overflow: işaretli taşma varsa | OF = 1 | JNO |
| JPE, JP | Jump if Parity Even: eşlik çiftse | PF = 1 | JPO, JNP |
| JNZ, JNE | Jump if Not Zero (Not Equal) | ZF = 0 | JZ, JE |
| JNC, JNB, JAE | Jump if Not Carry (Not Below, Above or Equal) | CF = 0 | JC, JB, JNAE |
| JNS | Jump if Not Sign: negatif değilse | SF = 0 | JS |
| JNO | Jump if Not Overflow | OF = 0 | JO |
| JPO, JNP | Jump if Parity Odd (No Parity) | PF = 0 | JPE, JP |
JC/JB adındaki "C" elde (carry) bayrağıdır; "taşma" (overflow) ise OF ile ilgilidir: ikisi farklı kavramlardır.
Koşullu Atlamalar
Kodlama ve Eş Anlamlılar
- 8086'da koşullu atlamalar sabit uzunluktadır: 2 bayt = işlem kodu + 1 baytlık bağıl konum (rel8).
- rel8 her zaman işaretli sayıdır: sonraki komuta göre −128 bayt geriye veya +127 bayt ileriye atlanabilir.
- Aynı koşulun farklı adları (eş anlamlılar) aynı makine koduna derlenir: JE = JZ, JNE = JNZ, JC = JB = JNAE, JNC = JNB = JAE.
- Not: 16 bitlik uzaklıklı koşullu atlamalar (0F 8x) ancak 80386 ile gelmiştir; 8086'da yoktur.
Hepsi 2 bayttır: işlem kodu + rel8. Kısa JMP'nin kodu EBh'dir.
Koşullu Atlamalar · Kodu adım adım çalıştır
Kod İzleme: JNC = JNB = JAE
Üç komut da aynı koşulu (CF = 0) sınar ve aynı işlem kodunu (73h) üretir; yalnızca rel8 farklıdır, çünkü her biri farklı adreste.
CF = 0 olduğundan jnc a atlar: IP ← 0102h + 07h = 0109h. Aradaki jnb, jae ve mov ax, 4 yürütülmez.
a: mov ax, 5 → AX = 0005h.
ret. CF = 1 olsaydı üç atlama da gerçekleşmez, AX önce 4 sonra 5 olurdu.
org 100h jnc a ; 0100h: 73 07 jnb a ; 0102h: 73 05 jae a ; 0104h: 73 03 mov ax, 4 ; 0106h: B8 04 00 a: mov ax, 5 ; 0109h: B8 05 00 ret ; 010Ch: C3
Koşullu Atlamalar
Atlama Kodu Hesaplayıcı
Atlama komutunun adresini ve hedef adresi (onaltılık) girin: rel8 / rel16 değeri ve makine kodu hesaplanır.
uzaklık = hedef − (adres + komut uzunluğu). Kısa biçimde sonuç −128…+127 aralığında olmalıdır; değilse assembler "relative jump out of range" hatası verir.Karşılaştırma
CMP Komutu
- Sayısal değerleri karşılaştırmak için
CMP hedef, kaynakkullanılır. - CMP, SUB (çıkarma) işlemini yapar:
hedef − kaynak. Ancak sonucu hiçbir yere yazmaz; yalnızca bayrakları (CF, ZF, SF, OF, PF, AF) ayarlar. - Ardından gelen koşullu atlama bu bayraklara bakarak karar verir.
- İşlenenler: yazmaç–yazmaç, yazmaç–bellek, bellek–yazmaç, yazmaç/bellek–sabit. İki bellek işleneni olamaz.
JE/JZ atlar.Karşılaştırma
CMP AL, BL Bayrakları Nasıl Ayarlar?
Pozitif fark: hiçbir bayrak kalkmaz (PF = 1 çünkü 03h = 0000 0011 iki adet 1 içerir).
Eşit sayılar: sonuç 0 → ZF = 1. Hem işaretli hem işaretsiz bakışta eşitlik.
Küçükten büyük çıkarılınca ödünç alınır → CF = 1; sonuç FEh = −2 → SF = 1, taşma yok.
127 − (−128) = 255 işaretli 8 bite sığmaz → OF = 1. İşaretsiz bakışta 127 < 128 (CF = 1), işaretli bakışta 127 > −128 (SF = OF).
FBh işaretsiz 251, işaretli −5. İşaretsiz: 251 > 3 (CF = 0); işaretli: −5 < 3 (SF ≠ OF). Aynı bitler, farklı karar!
Karşılaştırma
Karşılaştırma Hesaplayıcı
İki baytı girin (ondalık −128…255 ya da 7Fh gibi onaltılık). CMP A, B sonucu, bayraklar ve hangi atlamaların gerçekleşeceği gösterilir.
Karşılaştırma
İşaretli Sayılar İçin Atlamalar
| Komut | Anlamı | Koşul | Zıt komut |
|---|---|---|---|
| JE, JZ | Jump if Equal (=) · Jump if Zero | ZF = 1 | JNE, JNZ |
| JNE, JNZ | Jump if Not Equal (<>) · Jump if Not Zero | ZF = 0 | JE, JZ |
| JG, JNLE | Jump if Greater (>) · Not Less or Equal | ZF = 0 ve SF = OF | JNG, JLE |
| JL, JNGE | Jump if Less (<) · Not Greater or Equal | SF ≠ OF | JNL, JGE |
| JGE, JNL | Jump if Greater or Equal (>=) · Not Less | SF = OF | JNGE, JL |
| JLE, JNG | Jump if Less or Equal (<=) · Not Greater | ZF = 1 veya SF ≠ OF | JNLE, JG |
<> işareti "eşit değil" anlamına gelir. Greater / Less sözcükleri, sayıların ikiye tümleyen gösterimde işaretli olduğu varsayımıyla kullanılır.Karşılaştırma
Neden SF = OF?
- CMP A, B → A − B hesaplanır. Taşma yoksa sonucun işareti doğrudur: SF = 1 ⇔ A < B.
- Taşma varsa (OF = 1) sonuç 8/16 bite sığmamış, işaret biti ters çıkmıştır.
- Bu yüzden gerçek işaret = SF XOR OF: SF ≠ OF ⇔ A < B, SF = OF ⇔ A ≥ B.
| A | B | A − B (8 bit) | SF | OF | Sonuç |
|---|---|---|---|---|---|
| 5 | 7 | FEh (−2) | 1 | 0 | SF ≠ OF → 5 < 7 |
| 127 (7Fh) | −128 (80h) | FFh (−1) ✗ gerçek: +255 | 1 | 1 | SF = OF → 127 > −128 |
| −128 (80h) | 1 | 7Fh (+127) ✗ gerçek: −129 | 0 | 1 | SF ≠ OF → −128 < 1 |
| −5 (FBh) | 3 | F8h (−8) | 1 | 0 | SF ≠ OF → −5 < 3 |
Taşmalı satırlarda SF tek başına yanlış cevap verirdi; OF ile birlikte değerlendirilince karar doğru olur.
Karşılaştırma
İşaretsiz Sayılar İçin Atlamalar
| Komut | Anlamı | Koşul | Zıt komut |
|---|---|---|---|
| JE, JZ | Jump if Equal (=) · Jump if Zero | ZF = 1 | JNE, JNZ |
| JNE, JNZ | Jump if Not Equal (<>) · Jump if Not Zero | ZF = 0 | JE, JZ |
| JA, JNBE | Jump if Above (>) · Not Below or Equal | CF = 0 ve ZF = 0 | JNA, JBE |
| JB, JNAE, JC | Jump if Below (<) · Not Above or Equal · Carry | CF = 1 | JNB, JAE, JNC |
| JAE, JNB, JNC | Jump if Above or Equal (>=) · Not Below · Not Carry | CF = 0 | JNAE, JB, JC |
| JBE, JNA | Jump if Below or Equal (<=) · Not Above | CF = 1 veya ZF = 1 | JNBE, JA |
Karşılaştırma
Above/Below mı, Greater/Less mi?
| Karşılaştırma | İşaretsiz (A/B) | İşaretli (G/L) |
|---|---|---|
| A = B | JE / JZ | JE / JZ |
| A ≠ B | JNE / JNZ | JNE / JNZ |
| A > B | JA / JNBE | JG / JNLE |
| A ≥ B | JAE / JNB | JGE / JNL |
| A < B | JB / JNAE | JL / JNGE |
| A ≤ B | JBE / JNA | JLE / JNG |
JA atlar (251 > 3) ama JG atlamaz (−5 < 3). Verinin türüne göre doğru aile seçilmelidir.Karşılaştırma · Kodu adım adım çalıştır
Kod İzleme: CMP + JE
AX = 0005h.
BX = 0005h.
cmp ax, bx: 5 − 5 = 0 → ZF = 1. AX değişmez.
ZF = 1 olduğundan je atlar.
equal_message: eşitlik durumundaki işlemler burada yapılır.
jmp end_program: not_equal_message bloğu atlanır. Bu JMP olmasaydı her iki blok da yürütülürdü.
Program sonu. Eşit olmasaydı: je atlamaz, 5. satırdaki jmp ile 8. satıra gidilirdi.
mov ax, 5 mov bx, 5 cmp ax, bx je equal_message jmp not_equal_message equal_message: ; eşitse jmp end_program not_equal_message: ; eşit değilse end_program:
Karşılaştırma · Kodu adım adım çalıştır
Kod İzleme: CMP + JA
AX = 0005h.
BX = 0007h.
cmp ax, bx: 5 − 7 = FFFEh (−2). Ödünç alındı → CF = 1, ZF = 0.
ja için CF = 0 ve ZF = 0 gerekir. CF = 1 → atlamaz.
jmp not_jump_above ile "küçük veya eşit" bloğuna gidilir.
not_jump_above: AX ≤ BX durumundaki işlemler.
Program sonu. Aynı kodda ja yerine jg kullanılsaydı da (SF ≠ OF) atlanmazdı; değerler pozitif olduğu için iki aile aynı sonucu verir.
mov ax, 5 mov bx, 7 cmp ax, bx ja jump_above jmp not_jump_above jump_above: ; ax büyükse yapılacaklar jmp end_program not_jump_above: ; ax küçük veya eşitse end_program:
Karşılaştırma · Kodu adım adım çalıştır
Kod İzleme: Karşılaştır ve Yaz
emu8086.inc kütüphanesi putc makrosunu sağlar (AL'deki karakteri ekrana yazar).
AL = 25 = 19h.
BL = 10 = 0Ah.
cmp al, bl: 25 − 10 = 15 (0Fh) → ZF = 0.
ZF = 0 → je atlamaz.
putc 'n': ekrana n yazılır.
jmp stop: 'y' yazan blok atlanır.
Programın sonunda ret bulunmalıdır; kaynaktaki örnekte eksikti, yoksa işlemci stop'tan sonraki rastgele baytları komut sanıp yürütürdü.
include "emu8086.inc" org 100h mov al, 25 ; al = 25 mov bl, 10 ; bl = 10 cmp al, bl ; al - bl karşılaştır je equal ; al = bl ise (zf = 1) atla putc 'n' ; buraya gelindiyse al <> bl: jmp stop ; 'n' yaz ve stop'a atla equal: ; buraya gelindiyse putc 'y' ; al = bl, 'y' yaz stop: ret ; (eklendi) DOS'a dön
Karşılaştırma
if / else Kalıbı
Yüksek düzey
if (ax == bx) {
; A bloğu
} else {
; B bloğu
}
while (cx > 0) { ; işaretsiz
; gövde
}Assembly
cmp ax, bx
jne degil ; koşulun TERSİ
; A bloğu
jmp son
degil:
; B bloğu
son:
bas: cmp cx, 0
jbe bitti ; cx <= 0 → çık
; gövde
jmp bas
bitti:jmp son unutulursa B bloğu da çalışır.Karşılaştırma
Menzil Dışı Koşullu Atlama
- 8086'da koşullu atlama yalnızca −128…+127 bayt uzağa gidebilir.
- Hedef daha uzaktaysa assembler hata verir. Çözüm: koşulu ters çevirip kısa atlama ile hemen sonraki komutu atlamak, uzak hedefe ise JMP (near, ±32 KB) ile gitmek.
Hatalı (hedef çok uzak)
cmp al, 0 je cok_uzak ; out of range! ; ... 200 baytlık kod ... cok_uzak:
Doğru
cmp al, 0 jne devam ; ters koşul, kısa jmp cok_uzak ; near JMP (E9) devam: ; ... 200 baytlık kod ... cok_uzak:
Döngüler
Döngü Komutları
| Komut | İşlem ve atlama koşulu |
|---|---|
| LOOP | CX'i 1 azalt; CX ≠ 0 ise etikete atla. |
| LOOPE | CX'i 1 azalt; CX ≠ 0 ve eşitse (ZF = 1) atla. |
| LOOPZ | LOOPE ile aynı: CX ≠ 0 ve ZF = 1 ise atla. |
| LOOPNE | CX'i 1 azalt; CX ≠ 0 ve eşit değilse (ZF = 0) atla. |
| LOOPNZ | LOOPNE ile aynı: CX ≠ 0 ve ZF = 0 ise atla. |
| JCXZ | CX = 0 ise etikete atla (CX azaltılmaz). |
Döngüler
LOOP Nasıl Çalışır?
- Döngüler, bir kod bloğunun bir koşula bağlı olarak tekrarlanmasını sağlar.
LOOP etiket: önce CX azaltılır, CX sıfır değilse etikete atlanır.DEC CX+JNZile aynı etki, ama bayraklar korunur.LOOPE / LOOPZ: CX ≠ 0 ve ZF = 1 olduğu sürece;LOOPNE / LOOPNZ: CX ≠ 0 ve ZF = 0 olduğu sürece atlar.JCXZ: CX sıfır olduğunda etikete atlar.- Dikkat: CX = 0 iken döngüye girilirse ilk azaltma CX'i FFFFh yapar → gövde 65.536 kez çalışır.
Döngüler · Kodu adım adım çalıştır
Kod İzleme: LOOP
CX = 0005h: gövde 5 kez çalışacak.
1. tur: döngü içeriği yürütülür.
loop: CX = 0004h ≠ 0 → dongu'ya geri atla.
2. tur: döngü içeriği yürütülür.
loop: CX = 0003h ≠ 0 → dongu'ya geri atla.
3. tur: döngü içeriği yürütülür.
loop: CX = 0002h ≠ 0 → dongu'ya geri atla.
4. tur: döngü içeriği yürütülür.
loop: CX = 0001h ≠ 0 → dongu'ya geri atla.
5. tur: döngü içeriği yürütülür.
loop: CX = 0000h → atlama yok, döngüden çıkılır.
jmp dur: dur zaten sonraki satır olduğundan bu atlama gereksizdir ama zararsızdır.
ret: gövde toplam 5 kez çalıştı.
include "emu8086.inc" org 100h mov cx, 5 ; CX = tekrar sayısı (5) dongu: ; döngü içeriği loop dongu ; CX ≠ 0 ise dongu'ye atla jmp dur ; döngü bitince dur'a atla dur: ret
Döngüler · Kodu adım adım çalıştır
Kod İzleme: İç İçe LOOP
BX toplam adım sayacı: 0. .COM programında SP = FFFEh.
Dış döngü 5 kez dönecek: CX = 0005h.
Dış tur 1: BX = 1.
AL = '1' (31h), AH = 0Eh → INT 10h teletype ile 1 yazılır. (0Eh işlevi BH'yi sayfa no. olarak kullanır; BX < 256 olduğundan BH = 0.)
push cx: iç döngü de CX kullanacağı için dış sayaç (5) yığına saklanır; SP = FFFCh.
İç döngü sayacı: CX = 5.
İç tur 1: BX = 2, 2 yazılır.
loop k2: CX = 4 → k2'ye dön.
4 iç tur daha: toplam 5 adet 2 yazıldı, BX = 6, CX = 0 → iç döngü biter.
pop cx: dış sayaç geri gelir: CX = 5, SP = FFFEh.
loop k1: CX = 4 → k1'e dön (dış tur 2).
Dış tur 2 bitti: BX = 12, CX = 3.
Dış tur 3 bitti: BX = 18, CX = 2.
Dış tur 4 bitti: BX = 24, CX = 1.
Dış tur 5 bitti: CX = 0 → dış döngüden çıkılır. BX = 30 = 001Eh (5 + 5×5 adım).
ret. Ekranda 5 kez "122222" vardır. push/pop dengesi sayesinde ret doğru adrese (0000h) döner.
org 100h mov bx, 0 ; toplam adım mov cx, 5 ; dış döngü sayacı k1: add bx, 1 mov al, '1' mov ah, 0eh int 10h ; '1' yaz push cx ; dış sayacı sakla mov cx, 5 ; iç döngü sayacı k2: add bx, 1 mov al, '2' mov ah, 0eh int 10h ; '2' yaz loop k2 ; iç döngü pop cx ; dış sayacı geri al loop k1 ; dış döngü ret
Döngüler · Kodu adım adım çalıştır
Kod İzleme: LOOPNE ile Dizide Arama
En fazla 5 eleman incelenecek.
SI = −1 (FFFFh); döngüdeki ilk inc onu 0 yapar.
SI = 0.
dizi[0] = 7; 7 − 3 → ZF = 0.
loopne: CX = 4 ≠ 0 ve ZF = 0 → aramaya devam.
SI = 1.
dizi[1] = 1; 1 − 3 → ZF = 0.
loopne: CX = 3 ≠ 0 ve ZF = 0 → aramaya devam.
SI = 2.
dizi[2] = 3; 3 − 3 → ZF = 1.
loopne: CX = 2 ama ZF = 1 → döngüden çıkılır. LOOPNE bayrakları değiştirmediği için ZF = 1 korunur.
ZF = 1 → jne yok atlamaz: değer bulundu.
AL = 1 (bulundu), SI = 2 konumu gösterir. Döngü 5 yerine 3 turda bitti.
org 100h mov cx, 5 ; eleman sayısı mov si, -1 ; ilk inc ile 0 olur ara: inc si ; sonraki eleman cmp dizi[si], 3 ; aranan değer 3 mü? loopne ara ; CX≠0 ve ZF=0 ise sürdür jne yok ; ZF=0 → bulunamadı mov al, 1 ; bulundu, konum SI'da ret yok: mov al, 0 ; bulunamadı ret dizi db 7, 1, 3, 9, 4
Döngüler
JCXZ ve LOOP / DEC–JNZ
Sıfır turlu döngüye karşı koruma
mov cx, n ; n çalışma anında jcxz atla ; CX = 0 ise girme tekrar: ; gövde loop tekrar atla:
JCXZ olmadan CX = 0 iken LOOP önce CX'i FFFFh yapar ve gövde 65.536 kez çalışır.
LOOP mu, DEC + JNZ mi?
| LOOP | DEC CX + JNZ | |
|---|---|---|
| Boyut | 2 bayt | 1 + 2 = 3 bayt |
| Bayraklar | değişmez | ZF, SF, OF, PF, AF değişir (CF korunur) |
| Sayaç | yalnız CX | herhangi bir yazmaç |
| Ek koşul | LOOPE / LOOPNE | farklı Jcc seçilebilir |
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Dizi Elemanları Toplamı
CX = 5 eleman, toplam AL = 0, indis BX = 0.
add al, vector[0]: AL = 0 + 5 = 5 (05h).
BX = 1, CX = 4 → next'e dön.
add al, vector[1]: AL = 5 + 4 = 9 (09h).
BX = 2, CX = 3 → next'e dön.
add al, vector[2]: AL = 9 + 5 = 14 (0Eh).
BX = 3, CX = 2 → next'e dön.
add al, vector[3]: AL = 14 + 2 = 16 (10h).
BX = 4, CX = 1 → next'e dön.
add al, vector[4]: AL = 16 + 1 = 17 (11h).
BX = 5, CX = 0 → döngü biter.
mov m, al: m = 11h = 17 = 5 + 4 + 5 + 2 + 1.
ret. Veriler ret'ten sonra tanımlandığı için komut olarak yürütülmez.
org 100h mov cx, 5 ; eleman sayısı mov al, 0 ; toplam (AL) = 0 mov bx, 0 ; BX = indis next: add al, vector[bx] ; elemanı topla inc bx ; sonraki eleman loop next ; CX = 0 olana kadar dön mov m, al ; sonucu m'ye yaz ret vector db 5, 4, 5, 2, 1 m db 0
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Ekrana Hello Yazdırma
jmp start: veri (msg) kodun arasında olduğu için üzerinden atlanır; yoksa 'H' (48h) gibi baytlar komut sanılırdı.
SI = 0: ilk karakter.
AL = msg[0] = 'H' = 48h.
48h − 0 ≠ 0 → ZF = 0, je atlamaz.
AH = 0Eh, INT 10h → H yazılır.
SI = 1, jmp next_char ile başa dönülür.
Aynı tur: AL = 'e' (65h), ZF = 0 → e yazılır, SI = 2.
Aynı tur: AL = 'l' (6Ch), ZF = 0 → l yazılır, SI = 3.
Aynı tur: AL = 'l' (6Ch), ZF = 0 → l yazılır, SI = 4.
Aynı tur: AL = 'o' (6Fh), ZF = 0 → o yazılır, SI = 5.
AL = msg[5] = 0: dizgenin sonu (null sonlandırıcı).
0 − 0 = 0 → ZF = 1, je stop atlar.
ret: ekranda Hello. (Kaynakta eksik olan org 100h ve ret eklendi.)
org 100h jmp start msg db 'Hello', 0 start: mov si, 0 ; kaynak indisi = 0 next_char: mov al, msg[si] ; karakteri al cmp al, 0 ; 0 ile karşılaştır je stop ; 0 ise yazmayı durdur mov ah, 0eh ; teletype işlevi int 10h ; AL'deki karakteri yaz inc si ; sonraki karakter jmp next_char ; başa dön stop: ret
Örnek Programlar
LED Ekran Aygıtı
- emu8086, sanal aygıtlarla G/Ç (giriş/çıkış) denemeyi sağlar.
#start=led_display.exe#yönergesi program çalışınca LED ekran penceresini açar. #make_bin#: DOS'a bağlı olmayan düz ikili (.bin) dosya üretilir.- LED ekran 199 numaralı porta bağlıdır ve 2 bayt (bir word) okur. Değeri işaretli ondalık olarak 5 basamakla gösterir.
OUT port, AX: AX'teki 16 bitlik değeri porta yazar. Port numarası 0–255 ise doğrudan yazılabilir; daha büyükse DX ile verilir (OUT DX, AX).
04D2hE9D2h (ikiye tümleyen)Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: LED Ekran Testi
AX = 1234 = 04D2h.
out 199, ax: LED ekranda 01234.
AX = −5678 = E9D2h (65536 − 5678 = 59858).
Ekran değeri işaretli yorumlar: −05678.
Sayaç: AX = 0.
Ekranda 00000.
inc ax → 0001h, jmp x1 ile başa.
Ekranda 00001.
inc ax → 0002h, jmp x1 ile başa.
Ekranda 00002.
inc ax → 0003h, jmp x1 ile başa.
Döngü koşulsuz olduğundan sonsuza dek sayar (32767'den sonra −32768'e geçer). hlt satırına hiç ulaşılmaz.
#start=led_display.exe# #make_bin# mov ax, 1234 out 199, ax ; LED'e 1234 gönder mov ax, -5678 out 199, ax ; LED'e -5678 gönder mov ax, 0 x1: out 199, ax ; sayacı göster inc ax jmp x1 ; sonsuz döngü hlt ; buraya hiç ulaşılmaz
Örnek Programlar
Palindrom Kontrolü: Fikir
- Palindrom: baştan ve sondan okunuşu aynı olan dizi (
123321,kayak). - DI dizinin başını, SI sonunu gösterir; karakterler karşılaştırılır, DI ileri, SI geri gider.
- Uzunluğun yarısı kadar karşılaştırma yeterlidir (
shr cx, 1→ CX / 2). Tek uzunlukta ortadaki karakter karşılaştırılmaz. str_size = $ - msg:$o anki adrestir;msgilestraynı adreste olduğundan sonuç dizinin uzunluğu olan 6 sabitidir (bellekte yer kaplamaz).- INT 21h / AH = 09h: DS:DX adresindeki dizgeyi
'$'karakterine kadar yazar; 0Dh, 0Ah satır başı ve yeni satırdır.
Adresler org 100h ve 2 baytlık kısa jmp start (0100h) varsayımıyla verilmiştir: str 0102h'den başlar.
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Palindrom (1/2) Hazırlık
jmp start: veri bölümünün üzerinden atlanır.
AH = 09h: DOS dizge yazdırma işlevi.
DX = offset str = 0102h.
INT 21h: 123321 ve satır sonu yazılır ('$' yazılmaz).
lea di, str: DI = 0102h (ilk karakter).
SI = DI = 0102h.
SI = 0102h + 6 = 0108h: dizinin bir sonrası (0Dh).
dec si: SI = 0107h, son karakter '1'.
CX = str_size = 6.
6 − 1 ≠ 0 → ZF = 0, je atlamaz.
shr cx, 1: 0110b → 0011b, CX = 3. Dışarı kayan bit 0 → CF = 0.
org 100h jmp start msg: str db '123321' str_size = $ - msg ; = 6 db 0Dh,0Ah,'$' start: mov ah, 9 ; '$'e kadar yaz mov dx, offset str int 21h lea di, str ; DI = str adresi mov si, di add si, str_size ; SI = son + 1 dec si ; SI = son karakter mov cx, str_size cmp cx, 1 ; tek karakter mi? je is_palindrome ; tek karakter palindromdur shr cx, 1 ; CX = uzunluk / 2
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Palindrom (2/2) Karşılaştırma
Döngü başı: DI = 0102h, SI = 0107h, CX = 3.
AL = [DI] = '1', BL = [SI] = '1'.
Eşit → ZF = 1, jne atlamaz.
DI = 0103h, SI = 0106h, CX = 2 → next_char.
AL = [DI] = '2', BL = [SI] = '2'.
Eşit → ZF = 1, jne atlamaz.
DI = 0104h, SI = 0105h, CX = 1 → next_char.
AL = [DI] = '3', BL = [SI] = '3'.
Eşit → ZF = 1, jne atlamaz.
CX = 0 → döngü biter: tüm çiftler eşleşti.
AH = 09h, DX = offset msg1.
INT 21h: palindrome! yazılır. (DOS bu işlevden AL = 24h, yani '$' ile döner.)
jmp stop: "not palindrome!" bloğu atlanır.
ret. Kaynakta stop: doğrudan verilerin önündeydi; ret olmadan işlemci "palindrome!$" baytlarını komut sanıp yürütürdü.
next_char: mov al, [di] ; baştaki karakter mov bl, [si] ; sondaki karakter cmp al, bl jne not_palindrome ; farklıysa değil inc di ; baştan bir ileri dec si ; sondan bir geri loop next_char is_palindrome: mov ah, 9 ; "palindrome!" yaz mov dx, offset msg1 int 21h jmp stop not_palindrome: mov ah, 9 ; "not palindrome!" yaz mov dx, offset msg2 int 21h stop: ret ; (eklendi) msg1 db "palindrome!$" msg2 db "not palindrome!$"
Örnek Programlar
Palindrom: Farklı Girişler
| str | Uzunluk | CX (shr sonrası) | Karşılaştırmalar | Çıktı |
|---|---|---|---|---|
'123321' | 6 | 3 | 1=1, 2=2, 3=3 | palindrome! |
'123421' | 6 | 3 | 1=1, 2=2, 3≠4 → jne | not palindrome! |
'12321' | 5 | 2 | 1=1, 2=2 (ortadaki 3 atlanır) | palindrome! |
'7' | 1 | — | cmp cx,1 → je is_palindrome | palindrome! |
'ab' | 2 | 1 | a≠b → jne | not palindrome! |
cmp cx, 1? Uzunluk 1 iken shr cx, 1 CX'i 0 yapar; LOOP'lu döngüye CX = 0 ile girilirse karşılaştırma 65.536 kez çalışırdı. Uzunluk 0 da aynı tehlikeyi taşır: jcxz ile korunabilir.Özet
Özet
Özet
Alıştırmalar
- 0120h adresindeki
JNEkomutu 0100h adresine atlamak istiyor. Makine kodu nedir? mov al, 80h/cmp al, 1sonrasındaJAveJGatlar mı?mov cx, 0/d: loop dkaç kez döner? Nasıl önlenir?- AX'teki işaretsiz sayı 100'den büyükse BX = 1, değilse BX = 0 yapan kodu yazın.
- Dizi toplamı örneğinde dizinin elemanları 200, 100 olsaydı AL ve CF ne olurdu? Çözüm önerin.
- Hello örneğinde
jmp startsatırı silinirse ne olur?
İpuçları / cevaplar
- Sonraki IP = 0122h; 0100h − 0122h = −22h = DEh →
75 DE. - 80h − 01h = 7Fh: CF = 0, ZF = 0 → JA atlar (128 > 1). SF = 0, OF = 1 → SF ≠ OF → JG atlamaz (−128 < 1).
- 65.536 kez; öncesine
jcxzkonmalı. mov bx, 0/cmp ax, 100/jbe son/mov bx, 1/son:- 200 + 100 = 300 = 12Ch → AL = 2Ch, CF = 1 (taşma). Toplamı AX'te tutup
adc ah, 0ya da 16 bit toplama kullanılmalı. - 'H','e','l','l','o',0 baytları (48h 65h 6Ch …) komut olarak yürütülür; program öngörülemez davranır.
Özet
Kaynaklar
- emu8086 belgeleri: 8086 Assembler Tutorial for Beginners (Part 7: Program Flow Control).
- Intel, The 8086 Family User's Manual, 1979: komut kümesi ve kodlama tabloları.
- Barry B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009: Bölüm 6 "Program Control Instructions".
- Kip R. Irvine, Assembly Language for x86 Processors, 7. baskı, Pearson, 2014: koşullu işlem ve döngüler.