Koşullu Jump Komutları

07:20 , ,
Jump komutları sembolik makine dillerinin mutlaka bilinmesi gereken komutlarındandır. Bazı işlemci ailelerinde bu komutlara branch (dallanma) komutları denilmektedir. Jump komutları olmadan yüksek seviyeli dillerdeki if, switch, while for gibi deyimler gerçekleştirilemez. Jump komutları 
  • koşulsuz (unconditional
  • koşullu (conditional) olmak üzere ikiye ayrılmaktadır. 
Koşulsuz jump komutları C’deki goto deyimi gibidir. Koşulsuz olarak EIP yazmacını belli bir değere çeker. Koşulsuz jump komutlarının doğrudan (direct) ve dolaylı (indirect) biçimleri de vardır. Koşulsuz jump komutları pek çok işlemcide olduğu gibi göreli uzaklık değerini operand olarak alır. Doğrudan koşulsuz jump komutlarının son byte’larından sonraki ilk byte göreli uzaklık için sıfır orijini belirtir. Negatif uzaklık "yukarıya", pozitif uzaklık "aşağıya" jump yapılacağı anlamına gelmektedir.

Koşullu Jump Komutları

Koşullu jump komutları bayraklara bakarak jump işlemi yapmaktadır. Intel’deki bütün koşullu jump komutları doğrudandır ve "göreli uzunluk" değerini operand olarak alırlar. Bayrakların uygun karşılaştırma sonuçlarını içermesi SUB ya da CMP komutlarıyla sağlanmaktadır. Bu nedenle önce bayrakların karşılaştırma için set ya da reset edilmesi gerekir. Yani koşullu jump komutları tipik olarak SUB ya da CMP komutlarından sonra uygulanmaktadır. Zaten onların isimlendirmeleri de SUB ya da CMP komutlarından sonra kullanılacağı fikriyle yapılmıştır. Intel’de çok fazla koşullu jump komutu varmış gibi görülse de aslında bazı komutlar diğerleriyle aynı işlemi yaparlar. Yani bu komutlar aynı makine kodunun farklı isimleridirler. Örneğin JA ile JNBE aslında aynı komutlardır. Bunlar tek bir komutun iki farklı isimleridir desek yanlış olmaz. Koşullu jump komutlarının isimlendirilmeleri SUB ya da CMP komutlarının birinci operandına göre yapılmıştır. Örneğin:

cmp eax, ebx
jb REPEAT

Burada jb (jump below) eax’teki değer ebx’teki değerden küçükse anlamına gelmektedir. İsimlendirmede A (Above) ve B (Below) işaretsiz tamsayılar için G (Greater) ve L (Less) de işaretli sayılar için kullanılmaktadır. Eşitlik E (Equal) ya da Z (Zero flag set) ile ifade edilebilmektedir. Koşullu jump komutlarında eğer koşul sağlanmışsa jump işlemi yapılır. Eğer koşul sağlanmamışsa sonraki komuttan devam edilir. Aşağıda tüm jump komutlarının listesi verilmiştir:





Sembolik makine dilinde döngüler ve if deyimleri koşullu ve koşulsuz jump komutlarının kullanılmasıyla gerçekleştirilir. Örneğin aşağıdaki gibi bir C kodunun sembolik makine dili karşılığını yazmak isteyelim:

int g_x = 0;
/* ... */
while (g_x < 10) {
printf(“AhmetUlucay\n”);
++g_x;
}

Böyle bir while döngüsü aşağıdaki gibi oluşturulabilir:


Döngüdeki en önemli nokta şurasıdır:

cmp dword [g_x], 10
jge EXIT

Burada g_x ile 10 değeri karşılaştırılmıştır. Eğer g_x 10'dan büyükse ya da 10'a eşitse while koşulu sağlanmadığı için döngüden çıkılmıştır. Eğer bu koşul sağlanmıyorsa akış aşağıdan devam eder. Orada da mesaj ekrana yazdırılmıştır. Dönünün devamının sağlanması için yukarıya jump yapıldığına dikkat ediniz:

; ...
inc dword [g_x]
jmp REPEAT

Şimdi de aşağıdaki while döngüsünü sembolik makine dilinde yazmaya çalışalım:

unsigned g_x = 10;
while (g_x != 0) {
/* ... */
--g_x;
}

Kodun eşdeğer assembly karşılığı şöyle olabilir:

REPEAT:
cmp dword [g_x], 0
je EXIT
;  ...
dec dword [g_x]
jmp REPEAT
EXIT:
; ...

Tabii bu döngüyü şöyle de oluşturabilirdik:

cmp dword [g_x], 0
je EXIT
REPEAT:
; ...
dec dword [g_x]
jnz REPEAT
EXIT:
; ...

Burada dec komutuyla g_x değeri sıfıra düştüğünde ZF bayrağı set edileceğine dikkat ediniz. do-while döngüleri de benzer biçimde yapılabilir. Örneğin:

unsigned g_x = 10;
do {
/* ... */
--g_x;
} while (g_x != 0);

İşlemi sembolik makine dilinde şöyle yapılabilir:

REPEAT:
; ...
dec dword [g_x]
jnz REPEAT

for döngüleri de benzer biçimde sembolik makine dilinde oluşturulabilir. (Örneklerimizde stack görmediğimiz için hep global değişkenleri kullanıyoruz). Örneğin:

int g_i;
/* ... */
for (g_i = 0; g_i < 10; ++g_i) {
/* ... */
}

Bu işlemin sembolik makine dili karşılığı şöyle oluşturulabilir:

MOV dword [g_i], 0
@2:
cmp dword [g_i], 10
jge @1
; ...
inc dword[g_i]
jmp @2
@1:
; ...

Notlar: jmp işlemlerinde etiket kullanırken isim uydurmak zordur. Sembolik makine dilinde @ karakteri geçerli bir isimlendirme karakteridir. Pek çok C derleyicisi programın sembolik makine dili karşılığını oluştururken bu biçimdeki fabrikasyon etiketleri kullanmaktadır.

if deyimleri de yine koşullu ve koşulsuz jump komutlarıyla gerçekleştirilir. Örneğin yalnızca doğruysa kısmı olan bir if deyimi düşünelim:

if (g_i > 100) {
/* ... */
}
/* ... */

Bu işlem aşağıdaki gibi sembolik sembolik makine dilinde ifade edilebilir:

cmp dword [g_i], 100
jle @1
; doğruysa kısmı
@1:
; if deyimin dışı

Şimdi de else kısmı olan bir if deyimini sembolik makine dili ile ifade etmeye çalışalım:

if (g_i > 10) {
/* ... */
}
else {
/* ... */
}

Bu işlemin eşdeğer sembolik makine dili karşılığı şöyle olabilir:

cmp dword [g_i], 10
jle @1
; if’in doğruysa kısmı
jmp @2
@1:
; if’in yanlışsa kısmı
@2:

Şimdi de else-if örneği üzerinde duralım:

int g_a;
if (g_a > 0) {
/* .... */
}
else if (g_a < 0) {
/* ... */
}
else {
/* ... */
}

Bu işlemin sembolik makine dili karşılığı şöyle oluşturulabilir:

cmp dword [g_a], 0
jle @1
; g_a > büyükse sıfır
jmp @3
@1:
cmp dword [g_a], 0
jge @2
; g_a < 0
jmp @3
@2:
; g_a == 0
@3: