Bu bölümde Intel firmasının 80x86 serisi işlemcilerini programlamak için kullanılan
assembly komutlarından bir kısmını inceleyeceğiz.
• Transfer komutları
MOV
XCHG
LEA
PUSH
PUSHF
POP
POPF
LAHF
SAHF
• Giriş/Çıkış komutları
IN
OUT
• Aritmetiksel Komutlar
ADD
ADC
SUB
SBB
MUL
IMUL
DIV
21
IDIV
INC
DEC
CMP
• Mantıksal Komutlar
AND
OR
XOR
NOT
TEST
• Kaydırma ve Döndürme Komutları
SAL/SHL
SHR
SAR
RCL
ROL
RCR
ROR
• Dallanma Komutları
JMP
JZ/JE
JNZ/JNE
JB/JC/JNAE
JBE/JNA
JNB/JNC/JAE
JG/JNLE
JA/JNBE
JL/JNGE
JLE/JNG
JS ve JNS
JO ve JNO
JCXZ
• Döngü Komutları
LOOP
LOOPZ/LOOPE
LOOPNZ/LOOPNE
3.1 Transfer Komutları
Bu grup içerisindeki komutlar herhangi bir bilgiyi register-register, bellek-register ve registerbellek
bölgeleri arasında transfer etmek için kullanılır.
22
3.1.1 MOV Komutu
MOV komutuna daha önce bellek adresleme bölümünde kısaca değinilmişti. Bu kısımda
komutun kullanımı hakkında daha ayrıntılı bilgi verilecektir. Mov komutunun çeşitli kullanım
biçimleri aşağıdaki gibidir.
Genel Form : mov hedef, kaynak
mov register, register
mov bellek, register
mov register, bellek
mov bellek, sabit değer
mov register, sabit değer
Yukarıda mov komutunun çeşitli kullanım şekilleri gösterilmiştir. Dikkat ederseniz kullanım
şekilleri arasında bellek-bellek arasında transfer yok. Yukarıdaki “register” ifadeleri hem genel
amaçlı register’ları hem de segment register’larını temsil etmektedir. Yalnız, kesinlikle bir sabit
değer doğrudan bir segment register’ına atılamaz. Böyle bir işlem aşağıdaki gibi iki aşamada
gerçekleştirilir.
mov ax, 1234
mov cs, ax
Yukarıdaki örnekte CS içerisine 1234h değeri atanmıştır.
Dikkat edilmesi gereken bir başka önemli nokta da transferi yapılacak değerlerin boylarının
aynı olmasıdır. Yani AH içerisine 16-bit’lik bir değer atamsı yapılamaz. Aynı şekilde 8-bit’lik
bir register’dan 16-bitlik bir resgister’a da transfer yapılamaz.
Herhangi bir bellek bölgesi dolaylı adresleme ile adreslenip içerisine sabit bir değer atanmak
istendiği zaman atanacak değerin uzunluğu belirtilmelidir.
mov [bx], 12 Hata !
mov byte ptr [bx], 12
yada
mov word ptr [bx], 1234
“byte ptr” ve “word ptr” önekleri ile transfer edilecek bilginin boyu hakkında işlemciye bilgi
verilmektedir.
NOT: 32-bit işlemcilerde ( 80386 ve sonrasında ) “dword ptr” öneki ile 32-bit bilgi transferi
yapılabilmektedir.
MOV komutu flag register’lar üzerinde herhangi bir değişiklik yapmamaktadır.
23
3.1.2 XCHG Komutu
XCHG (exchange) komutu iki değeri karşılıklı olarak değiştirmek için kullanılır. Tabi yine
değişiklik yapılacak değerlerin aynı boyda olması gerekmektedir. Genel formu aşağıdaki
gibidir.
xchg register, register
xchg bellek, register
xchg komutunun kullanımında operandların yerleri önemli değildir. Yani “xchg bellek,
register” ile “xchg register, bellek” aynı işi yapmaktadır.
mov ax,1234 AX=1234h
mov bx, 5678 BX=5678h
xchg ax,bx AX=5678h BX=1234h
XCHG komutu flag register’lar üzerinde herhangi bir değişiklik yapmamaktadır.
3.1.3 LEA Komutu
LEA komutunun kullanımı MOV komutu ile benzerlik göstermesine karşın bazı durumlarda
programcıya iki yada üç komut ile yapılacak bir işlemi tek komut ile yapma olanağı
sağlamaktadır. Genel formu aşağıdaki gibidir.
lea register, bellek
Komutun kullanımına birkaç örnek verince programcıya sağladığı kolaylıklar daha basit
anlaşılacaktır.
lea ax, [bx] mov ax, [bx]
lea bx, 3[bx] BX = BX+3
Yukarıdaki kullanımlar “lea” komutu dışında tek bir komut ile icra edilebilecek durumlardır.
(BX = BX+3 ifadesinin assembly dilindeki karşılığı daha anlatılmadığı için normal bir gösterim
kullanılmıştır) Aşağıdaki örnekler incelenirse komutun sağladığı kolaylık açıkça fark
edilecektir.
lea ax, 3[bx] BX = BX+3 mov ax, bx
lea ax, 8[bx+di]
LEA komutunun genel kullanım amacı herhangi bir register’a bir bellek adresi saklamaktır.
Komut kullanımı sırasında flag register’lar üzerinde herhangi bir etki yapmamaktadır.
24
3.1.4 PUSH Komutu
PUSH komutu herhangi bir bilgiyi bilgisayarın stack adı verilen bölümüne kaydetmek için
kullanılır. PUSH komutu ile stack üzerine atılacak bilgi 16-bit uzunluğunda olmalıdır.
Komutun genel formu aşağıdaki gibidir.
PUSH değer
Yukarıda “değer” ile gösterilen kısım daha öncede belirtildiği gibi 16-bit uzunluğunda
olmalıdır. Bunun yanı sıra “değer” ile gösterilen kısım sabit bir değer alamaz. Yani PUSH ile
stack üzerine yazılacak değer ya bir register içerisindeki değer yada bir bellek bölgesindeki
değer olmalıdır.
PUSH komutu ile stack üzerine bilgi yazıldığı için SP’nin değeri değişmektedir. İcra edilen
her PUSH komutu SP’nin değerini 2 azaltacaktır (PUSH ile 2 bayt bilgi aktarıldığı için).
Aşağıda PUSH komutu ile stack üzerine bilgi aktarılmasına bir örnek verilmiştir.
mov ax,1234 AX = 1234h
push ax AX > STACK , SP = SP-2
Stack üzerine bilgi yazma işlemi gerekli değerlerin geçici bir süre saklanması için ve bazı
UNIX sistemlerde kesme kullanımında gerekli parametrelerin aktarılması için işaretçiler ile
birlikte kullanılır.
3.1.5 PUSHF Komutu
PUSHF komutu ile PUSH komutuna benzer olarak stack üzerine bilgi aktarılır. Yalnız burada
tek fark, PUSHF komutu ile aktarılacak bilginin herhangi bir register yada bellek bölgesinden
değil de flag register’dan alınmasıdır. Komutun kullanımı aşağıdaki gibidir.
PUSHF
Görüldüğü gibi komutun kullanımı sırasında hiçbir register yada bellek adresi
kullanılmamıştır. Onun yerine stack üzerine atılacak bilgi doğrudan 16-bit uzunluğundaki flag
resigter içerisindeki değerdir.
Komut herhangi bir işlem sırasında flag register’ın mevcut değerini korumak için kullanılır.
Yine PUSH komutunda olduğu gibi PUSHF komutu da SP’nin değerini 2 azaltacaktır.
3.1.6 POP Komutu
POP komutu ile stack üzerinden bilgi okuması yapılır. Yani PUSH komutu ile stack üzerine
yazılan bilgi POP komutu ile geri okunur. Okunan bilgi 16-bit uzunluğunda olmalıdır.
POP komutu ile alınacak bilgi stack üzerine yazılan son bilgidir. PUSH ve POP komutları ile
bilgi transferi yapılırken yazılan ve okunan bilgilerin sıralaması önemlidir. Programlar
yazılırken stack üzerindeki işlemlerde hesaplama hatası yapılması sık karşılaşılan
durumlardandır. Komutun genel kullanımı aşağıdaki gibidir.
POP alıcı_alan
Yukarıda alıcı alan bir bellek bölgesi veya register olabilir.
25
mov ax,1234 AX = 1234h
push ax AX > STACK , SP = SP-2
mov ah,01 AH = 01 ,AX’in değeri değişti!
pop ax AX = 1234h
Örneğimizde önce AX’e bir değer atanıyor ve daha sonra AH’ın değeri değiştirilmek sureti
ile dolaylı olarak AX’inde değeri değiştiriliyor. Son işlemde de POP komutu ile AX’in önceden
stack üzerine PUSH ile atılan eski değeri geri alınıyor.
3.1.7 POPF Komutu
POP komutu ile PUSH eşleştirilir ise PUSHF komutu ile de POPF komutunu eşleştirmek
yanlış olmaz. POPF komutu ile stack üzerinden 16-bit’lik bilgi flag register’a yazılır. Alınan 16
bitin hepsi işlemci tarafından dikkate alınmaz. Bitlerin word içerisindeki sıralarına göre işlemci
için ifade ettikleri değerler aşağıda verilmiştir.
0. bit Carry biti
2. bit Parity biti
4. bit Auxilary biti
6. bit Zero biti
7. bit Sign biti
8. bit Trap biti
9. bit Interrupt biti
10. bit Direction biti
11. bit Overflow biti
POPF komutu anlaşılacağı üzere flag register’ın değerini tamamen değiştirmektedir. Komut
tıpkı PUSHF komutunda olduğu gibi tek başına kullanılır.
PUSH, PUSHF, POP ve POPF komutlarının stack üzerinde işleyişlerini tam olarak
kavrayabilmek için yazının daha önceki bölümlerinde yer alan “Stack” kısmını tekrar
okumanızı tavsiye ederim.
3.1.8 LAHF Komutu
LAHF (Load AH from Flags) komutu AH register’ına flag register’ın düşük seviyeli baytını
kopyalar. Kopyalanan bitler sign, zero, auxilary, parity ve carry bitleridir. Bunların dışında
kalan overflow, direction, interrupt ve trace bitlerinin komut ile bir ilgisi yoktur. Komutun
kullanımı aşağıdaki gibidir.
lahf
Görüldüğü gibi komut tek başına kullanılmaktadır. Komutun icrası sırasında flag register’da
herhangi bir değişiklik olmaz.
3.1.9 SAHF Komutu
SAHF (Store AH into Flags) komutu da LAHF komutu gibi flag register üzerinde işlem
yapar. AH içerisindeki değer flag register’ın düşük seviyeli baytına kopyalanır. Yine işlemden
26
etkilenen bitler sign, zero, auxilary, parity ve carry bitleridir. Komutun kullanımı LAHF
komutunda olduğu gibi tek başınadır.
3.2 Giriş/Çıkış Komutları
80x86 serisi işlemcilerde giriş ve çıkış birimlerine ulaşmak için “in” ve “out” komutları
kullanılır. Aslında bu komutlar bir bakıma MOV komutu ile benzer şekilde iş yapmaktadır. Tek
fark bu komutların özel olarak bilgisayarın G/Ç birimi için ayrılmış olan bellek bölgesi ile
çalışmalarıdır.
3.2.1 IN Komutu
in ax/al, port
in ax/al, dx
IN komutunun genel kullanımı yukarıda gösterilmiştir. IN komutu ile “port” veya dx ile
belirtilen port adresinden okunan bilgi boyutuna göre AX yada AL içerisine kopyalanır.
Erişilmek istene port 0-255 arasında ise port numarası kullanılır. Aksi taktirde, yani erişilmek
istenen port 256 ve 80x86 işlemcinin maksimum desteklediği port numarası olan 65535
arasında ise istenen port numarası DX içerisine atılır ve daha sonra IN komutu ile erişim
sağlanır. Komutun icrasında flag register herhangi bir değişikliğe uğramaz.
3.2.2 OUT Komutu
out port, ax/al
out dx, ax/al
OUT komutunun kullanımı IN komutu ile benzerlik göstermektedir. Tek fark IN komutunda
port içerisindeki bilgi AX/AL’ye atanırken OUT komutunda AX/AL içerisindeki bilgi porta
gönderilir. Yine IN komutunda olduğu gibi 0-255 arası adreslerde doğrudan port numarası
girilirken 256-65535 arası adreslerde DX ile adresleme yapılır. Komutun icrasında flag register
herhangi bir değişikliğe uğramaz.
mov al, 2e AL = 2Eh
out 70, al 70h. Porta 2E değeri gönderiliyor
in al,71 Gönderilen isteğe karşılık 71h.
porttan geliyor. Gelen değer AL
içerisine alınıyor.
Yukarıda OUT komutu ile 70h CMOS portuna bilgi yollanıyor. CMOS gelen sinyale 71h
portundan cevap veriyor ve biz gelen cevabı IN komutu ile AL içerisine kaydediyoruz.
3.3 Aritmetiksel Komutlar
80x86 programcıya toplama, çıkarma, çarpma, bölme gibi temel aritmetiksel işlemlerin yanı
sıra elde edilen sonuçları değişik biçimlerde saklama olanağı sağlar. Aritmetiksel komutların
icrası sırasında flag register değişikliğe uğramaktadır.
27
3.3.1 ADD Komutu
ADD komutu toplama işlemini gerçekleştirmek için kullanılır. Genel formu aşağıdaki gibidir.
add hedef, kaynak
ADD komutu ile “kaynak” içerisindeki değer “hedef” ile toplanıp “hedef” içerisine
kaydedilir. “hedef” ve “kaynak alanları register-register, bellek-register, register-bellek
çiftlerinden birisi olabilir.
mov ax, 1234 AX = 1234h
mov word ptr [4444], 1000 [4444] = 1000h
add word ptr ax, [4444] AX = AX + [4444]
= 1234h + 1000h
= 2234h
Yukarıdaki örnekte ilk önce AX’e 1234h değeri atanmıştır. Daha sonra 4444h adresli bellek
gözüne word uzunluklu 1000h değeri yazılmıştır (Bu işlem için iki bellek gözü kullanılmıştır).
En son olarak da AX içerisindeki değeri 4444h bellek gözü ile işaret edilen word ile toplanıp
sonuç yine AX içerisine atılmıştır.
3.3.2 ADC Komutu
ADC komutu da tıpkı ADD komutu gibi toplama işlemi için kullanılır. Tek fark ADC
komutunda toplama bir de carry flag’ın değerinin eklenmesidir. Genel formu aşağıdaki gibidir.
adc hedef, kaynak
Yapılan işlemi aritmetiksel olarak göstermek gerekirse aşağıdaki gösterim yanlış
olmayacaktır.
hedef = hedef + kaynak + carry flag’ın değeri
ADC komutu ile peş peşe yapılan toplama işlemlerinde eldelik sayının göz ardı edilmemesi
sağlanmaktadır.
3.3.3 SUB Komutu
SUB komutu çıkarma işlemi için kullanılır. Kullanımı ADD komutunda olduğu gibidir.
sub hedef, kaynak
“kaynak” içerisindeki değer “hedef” içerisinden çıkartılıp sonuç “hedef” içerisinde saklanır.
İşlemin aritmetiksel gösterimi
hedef = hedef – kaynak
28
şeklindedir. Aslında CPU, SUB komutu ile “hedef” ile “-kaynak” değerlerini toplamaktadır.
Gerçekte yapılan işlem yine bir toplama işlemidir.
mov ax, 8da7 AX = 8DA7h
mov bx, 4a43 BX = 4A43h
sub ax, bx AX = AX – BX
= 8DA7h – 4A43h
= 4364h
3.3.4 SBB Komutu
sbb hedef, kaynak
SBB komutu ile SUB arasındaki ilişki, ADD komutu ile ADC arasındaki ilişki ile aynıdır.
SUB komutu ile aynı işe yapılır yalnız burada “hedef” alana atılan değerden carry flag’ın
değeri de çıkartılır. İşlemin aritmetiksel gösterimi
hedef = hedef – kaynak – carry flag’ın değeri
3.3.5 MUL Komutu
MUL komutu çarpma işlemini gerçekleştirmek için kullanılan komuttur. Aritmetiksel olarak
çarpma işlemi iki değer ile gerçekleştirilmesine karşın MUL komutu sadece bir değer alır.
MUL komutu ile kullanılan değer gizli olarak ax/al içerisindeki değer ile çarpma işlemine tabi
tutulur.
mov ax,0045 AX = 0045h
mov bx,11ac BX = 11ACh
mul bx AX = AX * BX
= 0045h * 11Ach
= C35Ch
Yukarıda çarpma işleminin bir elamanı olan 0045h sayısı AX içerisine atılmıştır. Bir sonraki
adımda işleme sokulmak istenen diğer sayı olan 11ACh sayısı BX içerisine atıldıktan sonra
“mul bx” komutu ile BX içerisindeki sayı doğrudan AL (AH=00) ile işleme sokuluyor ve elde
edilen çarpım AX içerisinde saklanıyor.
mov ax, 0005 AX = 0005h
mov word ptr [4000], 1212 [4000] = 12 , [4001] = 12
mul word ptr [4000] AX = AX*[4001][4000]
29
Yukarıda çarpma işlemi için kullanılacak ikinci sayımız bir bellek bölgesinden okunmaktadır.
Dikkat ederseniz işlemlerimde “word ptr” ile atama yaptığım değerin uzunluğu hakkında
işlemciye bilgi veriyorum. MUL komutunu kullanırken işlem yapacağınız sayı bir bellek
bölgesinde ise “word ptr” ve “byte ptr” gibi yardımcı bilgilerle işlemciye üzerinde işlem
yapılacak bilginin uzunluğu hakkında bilgi vermeniz gerekmektedir
Diyelim ki çarpma işlemi sonunda bulduğunuz sonuç 16-bit’lik bir alana sığmıyor. Böyle bir
durumda bulunan sonuç DX:AX ikilisi içerisinde saklanır.
mov ax, 4321 AX = 4321h
mov cx, 4586 CX = 4586h
mul cx AX * CX = 4321h * 4586h
= 123B0846h (32-bit)
= DX = 123Bh , AX = 0846h
3.3.6 IMUL Komutu
IMUL komutu da MUL komutu gibi çarpma işlemi için kullanılır tek fark IMUL komutunun
işaretli sayılar üzerindeki işlemler için kullanılan bir komut olmasıdır. IMUL komutu ile
gerçekleştirilen bir işlem sonucunda AH (sonuç AX içerisine sığıyor ise) veya DX (sonuç AX
içerisine sığmıyor ise) sıfırdan farklı ise çarpma işleminin sonucu negatiftir. Eğer işlem
sonucunda bir taşma olmuş ve AH veya DX içerisinde sonucun işaretine değil de kendisine ait
bir değer varsa carry ve overflow flag’ları set edilmiş olacaktır.
3.3.7 DIV Komutu
Bölme işlemi için kullanılan bir komuttur. DIV komut da MUL komutundan olduğu gibi
sadece bir değer ile işleme girer ve gizli olarak AX register’ını kullanır. Genel formu aşağıdaki
gibidir.
div bölen_değer
Bölme işleminde “bölen_değeri”in uzunluğu, işlem sırasında kullanılacak bölünen değerin
uzunluğunu da belirler. Sözgelimi, “bölen_değeri”in 8-bit’lik bir değer olması halinde bölünen
olarak 16-bit’lik AX register’ı işleme alınacaktır. İşlem sonunda bölüm değeri AL, kalan değeri
de AH içerisine kopyalanır. Aynı şekilde “bölen_değer”i 16-bit’lik bir değer ise bölünün değeri
olarak DX:AX çifti işleme alınır. Yine işlem sonundaki bölüm değeri AX ve kalan değeri de
DX içerisine atılır.
8-bit’lik bir sayıyı yine 8-bit’lik bir sayıya ve 16-bit’lik bir sayıyı yine 16-bit’lik bir sayıya
bölmek için sırasıyla AH ve DX register’larına 0 değeri atanır.
“bölen_değer” olarak bir bellek bölgesi kullanılması halinde işlemciye kullanılan değerin
uzunluğu hakkında bilgi verilmelidir.
mov ax, 4a2c
div byte ptr [2155]
30
DIV komutunu kullanırken dikkat edilmesi gereken bir husus da sıfır ile bölme durumu ile
karşılaşmamak ve bölüm kısmındaki değerin alıcı alana sığıp sığmadığıdır. Mesela aşağıdaki
gibi bir işlem sonunda hata ile karşılaşılacaktır.
mov ax, aaaa
div 4
Yukarıdaki işlemin sonucu ( AAAAh / 4H = 2AAAH 16-bit ) olan 2AAAh sayısı 8-bit bir
register olan AL içerisine sığmayacağı için hatalı olacaktır.
3.3.8 IDIV Komutu
IDIV komutu DIV komutu gibi bölme işlemi için kullanılır. DIV komutundan farkı, IDIV
komutunun işaretli sayılar üzerinde işlem yapmak için kullanılmasıdır. DIV komutu için
yukarıda anlatılanların dışında IDIV komutunun kullanımında dikkat edilmesi gereken bir
nokta AH veya DX değerleri sıfırlanırken sayının işaret bitinin korunmasıdır. Mesela işleme
konulacak bölen değer 8-bit bir negatif sayı ve bölünen de 8-bit bir sayı ise AH’ın bütün
bitlerine AL içerisindeki 8-bit’lik negatif sayının işaret biti olan 1 değeri atanmalıdır.
3.3.9 INC Komutu
INC komutu kendisine verilen register yada bellek bölgesi içerisindeki değeri bir arttırır. C
dilindeki “++” komutu ile aynı işi yapmaktadır. Aşağıda, komutun kullanımını C dilindeki gibi
göstermeye çalıştım.
mov ax, 000f degisken = 15 ;
inc ax degisken++ ;
Flag register üzerinde, carry flag dışında, ADD komutu ile aynı etkiyi yapar.
add ax,1
inc ax
Yukarıdaki iki komut da aynı işi yapmaktadır. Fakat INC komutu ile gerçekleştirilen işlem,
işlemci tarafından daha hızlı bir şekilde gerçekleştirilir ve bellekte kapladığı alan ilkinin üçte
biri kadardır. Bu sebeplerden “add ax,1” gibi kullanımlar yerine “inc ax” komutu
kullanılmaktadır.
inc byte ptr [125a]
inc word ptr [7ad8]
inc byte ptr [bx+di]
31
Bir bellek bölgesindeki değer INC komutu ile işleme alınacaksa, işlemciye üzerinde işlem
yapılacak bilginin uzunluğu belirtilmelidir.
3.3.10 DEC Komutu
DEC komutu kendisine verilen register yada bellek bölgesi içerisindeki değeri bir azaltır.
Yine INC komutundan olduğu gibi C dilinden bir örnek vermek istiyorum.
mov ax, 000f degisken = 15 ;
dec ax degisken-- ;
Yukarıda da görüldüğü gibi DEC komutu C dilindeki “--“ komutuna karşılık gelmektedir.
DEC komutu ile yapılan bir azaltma işlemi “sub ax,1” komutu ile de gerçekleştirilebilirdi fakat
DEC komutu SUB komutuna göre bellekte daha az yer kaplar ve daha hızlı çalışır.
dec word ptr a8[bx+di]
DEC komutu ile azaltılacak değer bir bellek bölgesinde ise değerin uzunluğu “word ptr” yada
“byte ptr” ile işlemciye bildirilmelidir.
3.3.11 CMP Komutu
CMP komutu SUB komutu gibi çalışır.
cmp deger1, deger2
Yukarıda “deger1” ve “deger2” yerine sırasıyla register-register, register-bellek bölgesi,
bellek bölgesi-register ve register-sabit değer değerleri kullanılabilir.
CMP komutu kısaca “deger1”den “deger2”yi çıkarmaktadır. Fakat SUB komutundan farklı
olarak sonuç herhangi bir yere kaydedilmez. Onun yerine, işlem sonucunda değişen flag
register bitlerinin değerine göre programda dallanma yapılır. CMP komutundan sonra sonuca
göre genellikle koşullu dallanma komutları ile programın akışı değiştirilir.
cmp ax, bx
Komut flag register üzerinde kısaca şu gibi etkilerde bulunur :
• AX, BX’e eşit ise işlemin sonucu sıfır olur ve zero flag 1 değerini alır.
• AX’in değeri BX’inkinden küçük ise çıkarma işlemi sonunda carry flag 1 değerini
alır.
• Sonuç negatif ise sign biti 1, pozitif ise 0 değerini alır.
32
3.4 Mantıksal Komutlar
Bu komutlar herhangi bir işlem sırasında mantıksal karşılaştırmalar yapmak için kullanılır.
Bölüm içerisindeki komutlar incelenmeden önce dokümanın “Bitler Üzerinde Mantıksal
İşlemler” kısmının tekrar gözden geçirilmesinde fayda var.
Bu komutlar icra görürken kullanılan register yada bellek bölgesinin içerisindeki değerler
ayrı ayrı bitler halinde işleme sokulur.
3.4.1 AND Komutu
and hedef, kaynak
Komutun kullanımında “hedef” ve “kaynak” alanlarına sırasıyla register-register, bellek
bölgesi-register, register-bellek bölgesi, register-sabit değer ve sabit değer-register çiftlerinden
biri kullanılabilir.
İşlem sırasında “hedef” ve “kaynak” bölgesindeki değerler mantıksak VE işlemine sokulur ve
işlemin sonuncu “hedef” alana kaydedilir.
mov ah, a5 AH = A5h = 1010 0101 (binary)
mov al, c1 AL = C1h = 1100 0001 (binary)
and ah, al AND_________________
1000 0001 (binary) = 81h
Yukarıda AH’a A5h ve AL’ye C1h değerleri atanmış ve daha sonra “and ah, al” komutu ile
iki değer “mantıksal ve” işlemine sokulmuştur. İşlem sonucunda 81h değeri elde edilmiştir.
Elde edilen değer AH registeri içerine atılmıştır.
3.4.2 TEST Komutu
TEST komutu tamamen AND komutu gibi çalışır. Tek fark elde edilen sonucun hedef alana
aktarılmaması onun yerine değişen flag bitlerine göre programın akışının kontrol edilmesidir.
3.4.3 OR Komutu
or hedef, kaynak
OR komutu “mantıksal veya” işlemini gerçekleştirmek için kullanılır. “hedef” ve “kaynak”
alanları yerine kullanılabilecek değerler AND komutu ile aynıdır. İşlem gerçekleştikten sonra
elde edilen sonuç hedef alan içerisine kaydedilir.
3.4.4 XOR Komutu
xor hedef, kaynak
“hedef” ve “kaynak” alanları için kullanılabilecek değerler AND komutu ile aynıdır. İşlem
sonucunda elde edilen değer hedef alan içerisine kaydedilir.
XOR komutu herhangi bir register’ın değerini sıfır yapmak için sıkça kullanılır. “xor ax, ax”
komutu “mov ax, 0” komutundan daha hızlı çalışır ve bellekte daha az yer kaplar.
33
3.4.5 NOT Komutu
not hedef
NOT komutu diğer mantıksal komutlardan ayrı olarak flag register üzerine etki etmeyen tek
komuttur. Kullanım şekli ile de diğer komutlardan farklılık gösterir. “hedef” alan içerisindeki
değerin bitleri ters çevrilip yine aynı alana yazılır.
3.5 Kaydırma ve Döndürme Komutları
Bu bölümde daha önce anlatılan “Shift ( Kaydırma ) ve Rotate ( Döndürme ) İşlemleri”
başlıklı kısımdaki işlemlerin assembly komutları ile gerçekleştirilmesi anlatılacaktır.
3.5.1 SHL/SAL Komutları
SHL (Shift Left) ve SAL (Shift Arithmetic Left) komutları eştir.
shl hedef, sayaç
Her iki komut da “hedef” alan içerisindeki bit pozisyonunu “sayaç” defa sola kaydırır.
Kaydırma işlemi sırasında 0. bit pozisyonuna sıfır yazılır ve 7. veya 15. bit pozisyonundaki
değer de carry flag içerisine yazılır.
3.5.2 SHR Komutu
SHL (Shift Right) komutunun kullanımı aşağıdaki gibidir.
shr hedef, sayaç
SHR komutu ile “hedef” bölgesindeki bayt dizilimi “sayaç” defa sağa kaydırılır. Sağa
kaydırma işleminde boşta kalan 7. yada 15. bit pozisyonuna 0 değeri atanır ve 0. Bit
pozisyonundaki değer de carry flag’a yazılır. Sign biti sonucun her zaman sıfır olan yüksek
seviyeli bit değerini alır.
Aritmetiksel olarak herhangi işaretsiz bir sayıyı “SHR sayı, a” işlemine sokmak, sayıyı 2ª ile
bölmek ile aynı şeydir.
3.5.3 SAR Komutu
sar hedef, sayaç
SAR (Shift Arithmetic Right) komutu SHR komutunda olduğu gibi “hedef” alan içerisindeki
bit dizilimini “sayaç” kere sağa kaydırır. SHR komutundan farkı, sondaki 7. veya 15. bit
pozisyonuna sıfır değil de yine 7. veya 15. bit pozisyonundaki değerin yazılmasıdır. Flag’lar
üzerine etkisi, SHR’den farklı olarak, sign flag içerisine 7. veya 15. bit pozisyonundaki değerin
yazılmasıdır.
34
3.5.4 RCL Komutu
rcl hedef, sayaç
RCL (Rotate through Carry Left) komutu hedef alandaki bit dizilişini sola döndürme
hareketine sokar. İşlem sonrasında carry flag içerisindeki değer 0. bit pozisyonuna yazılır ve
arta kalan bit de carry flag içerisine aktarılır.
3.5.5 ROL Komutu
rol hedef, sayaç
ROL (Rotate Left) komutu da RCL komutu gibi sola döndürme işlemi için kullanılır. Tek
farkı en sonda boş kalan 0. bit pozisyonuna carry flag’ın değerinin değil de en yüksek seviyeli
bitin değerinin yazılmasıdır. Bu işlemde de yine yüksek seviyeli bit değeri carry flag içerisine
kopyalanır.
3.5.6 RCR Komutu
rcr hedef, kaynak
RCR (Rotate through Carry Right) komutu da aynen RCL komutu gibi çalışmaktadır.
Adından da anlaşılacağı gibi tek farkı sadece döndürme işleminin sola değil sağa doğru
yapılmasıdır. Yine düşük seviyeli bit pozisyonundaki değer carry flag içerisine ve carry flag
içerisindeki değer de yüksek seviyeli bit pozisyonuna kopyalanır.
3.5.7 ROR Komutu
ror hedef, kaynak
ROR (Rotate Right) komutunu RCR komutu ile ROL komutunu RCL komutu ile
ilişkilendirdiğimiz şekilde ilişkilendirebiliriz. Yani ROR komutu da RCR komutu gibi
çalışmaktadır. Tek fark ROR komutundan yüksek seviyeli bit pozisyonuna atanan değer carry
flag içerisindeki değil alçak seviyeli bit pozisyonu içindeki değerdir.
NOT: Yukarıda “shift” ve “rotate” işlemlerini gerçekleştirilen komutlarda kullanılan “sayaç”
ifadesi normalde 1 olarak kullanılır. 80286 ve sonrası işlemcilerde herhangi bir sabit değer
kullanımı getirilmiştir. Daha önceki işlemcilerde 1 dışında bir değer kullanmak için aşağıdaki
yol izlenmelidir.
mov cl, sayaç
shr ax, sayaç
Yukarıdaki gibi CL içerisine istenilen değer atanır ve daha sonra hedef alan ile işleme
sokulur.
35
3.6 Dallanma Komutları
Dallanma komutları, programın normalde yukarıdan aşağı doğru giden akışını herhangi bir
koşula bağlı olarak yada koşulsuz olarak başka bir yere yönlendirmek amacı ile kullanılır.
Kullanılan bu dallanma komutları yüksek seviyeli dillerdeki “if” veya “goto” komutları gibi
düşünülebilir.
Assembly dilinde kullanılan dallanma komutları atlama yaptıkları yere göre FAR veya NEAR
özelliği taşır. NEAR özelliği taşıyan komutlar 2-3 bayt yer tutarken FAR özellikli olanlar 5
bayt yer tutmaktadır. Komutlar arasındaki fark, FAR özelliği taşıyanların farklı segment
içerisindeki noktalara dallanma için kullanılmasıdır. Gerekli olmamakla beraber dallanmanın
türü “FAR PTR” yada “NEAR PTR” ile belirtilebilir.
3.6.1 JMP (Koşulsuz Dallanma) Komutu
jmp hedef
JMP komutu belirtilen herhangi bir noktaya koşulsuz olarak dallanma yamak için kullanılır.
DEBUG kullanılarak yazılan programlarda gidilecek noktanın offset adresi “hedef” kısmına
yazılır. Eğer farklı bit segment içerisindeki bir adrese dallanma yapılıyorsa “hedef” kısmında
SEGMENT:OFFSET şeklinde bir adresleme kullanılır.
Eğer aynı segment içerisinde –128 veya +127 bayt’dan daha uzak noktalara dallanma
yapılıyorsa bu dallanma da FAR özelliği taşır. Bellekte kapladığı alan 3 bayt olacaktır.
Aslında JMP komutu ile yapılan sadece IP değerine “gidilecek_adres - bulunulan_adres”
değerini eklemektir. JMP komutunun icrası sırasında IP’ye eklenecek değer JMP komutundan
bir sonraki komutun adresinden itibaren hesaplanır.
Dallanama yapılırken doğrudan gidilecek adres yazılmayıp, bellek adresleme yolu ile de
işlem gerçekleştirilebilir.
mov bx, 0401
mov si, 0002
mov word ptr [bx+si+04], 1a8c
jmp far ptr [bx+si+04]
Yukarıdaki örnek JMP komutu ile gidilecek nokta BX+SI+04 = 0407h değeri değil aynı
segment içerisinde 0407h numaralı offset içerisindeki değerin gösterdiği yerdir. Örneğimizde
bu değer 1A8Ch değeridir.
Benzer şekilde herhangi bir genel amaçlı16-bit register kullanılarak da dallanma işlemi
gerçekleştirilebilir.
mov ax, 1111
jmp ax
Yukarıda “JMP AX” komutundan sonra programın akışı 1111h numaralı offset adresinden
devam edecektir.
36
Başka bir segment içerisine dallanma yapmak için SEGMENT:OFFSET kalıbı kullanılır.
Yani 4C70:0100 adresine dallanma yapmak için “JMP 4C70:0100” komutunu kullanmak
gerekir. Komut bellekte 5 bayt yer kaplayacaktır.
Yukarıda ele alınan JMP komutu dışında assembly dilinde kullanılan koşullu dallanma
komutları da vardır. Bu komutlar herhangi bir işlem sonucunda flag register’ların değerine göre
programın akışını etkilerler. Bu komutlar C’deki “if” ve Pascal’daki “if...then” kalıbı ile
eşleştirilebilir.
Karşılaştırma işlemi herhangi bir aritmetiksel işlem olabileceği gibi bir karşılaştırma (CMP)
yada döndürme olabilir. Fakat koşullu dallanma komutları çoğunlukla CMP komutundan sonra
karşılaştırma amaçlı kullanılır.
3.6.2 JZ/JE Komutları
JZ/JE (Jump if Zero/Jump if Equal) komutları herhangi bir işlem sonrasında zero flag’ın
değerine göre programın akışını düzenler. Komutun icrası sırasında zero flag içerisindeki bit
değeri 1 ise program JZ komutu ile gösterilen yere atlar aksi taktirde işlemci JZ komut yokmuş
gibi programın akışına devam eder.
dec cx
cmp cx,0
jz 010a
jmp 0110
Yukarıdaki örnekte CX içerisindeki değer bir azaltılıyor. Daha sonra elde edilen değer sıfır
ile karşılaştırılıyor ve eğer sonuç sıfır ise 010Ah adresine atlanıyor. Sonuç sıfırdan farklı ise
program normal akışına devam ediyor ve bir sonraki komut olan “JMP 0110” çalıştırılıyor. Bu
sefer koşulsuz olarak 0110h adresine bir dallanma yapılıyor.
Örneğimizdeki yazım şekli DEBUG içerisinde kullanılan yazım şeklidir. Assembly
programlarını bir assembler programı aracılığı ile birleştiren programcılar için yazım şekli biraz
daha farklıdır. Assembler kullanan programcılar offset adresleri yerine programın çeşitli
yerlerine koydukları etiketleri kullanırlar.
.model small
.code
org 0100h
basla:
mov dl,41h
mov ah,02h
int 21h
dongu: inc dl
int 21h
cmp dl,5Ah
jnz dongu
mov ah,4Ch
37
int 21h
end basla
Yukarıda MASM ile yazılmış bir assembly programı görülmektedir. Bu aşamada programı
anlamaya çalışmayın yalnızca program içerisinde kullanılan etikete dikkat edin. “INC DL”
komutunun olduğu satır “dongu” etiketi ile işaretlenmiştir. “JNZ dongu” komutu ile bir offset
adresi belirtilmeyip bir etiket yardımı ile istenilen noktaya atlama yapılmıştır. Yukarıda DL
içerisindeki değer 41h’tan başlayıp 5Ah olana kadar arttırılmaktadır.
Pratikte, DEBUG program yazmak için uygun bir ortam değildir. Yazacağınız assembly
programını herhangi bir assembler yazılımı ile birleştirip kullanırsınız.
Yukarıdaki program COM dosyası olarak derlenirse 19 bayt alan kaplar ve ekrana alfabedeki
büyük harfleri yazar.
3.6.3 JNZ/JNE Komutları
JNZ/JNE (Jump if Not Zero/Jump if Not Equal) komutları JZ ve JE komutlarının zıttı olarak
kullanılır. Herhangi bir işlem sonrasında zero flag içerisindeki değer sıfır değil ise program
komutun gösterdiği yere dallanarak akışına devam eder.
Örnek olarak JZ için verilen MASM programı incelenebilir. “jnz dongu” komutu ile zero flag
içerisindeki değer kontrol ediliyor. Değerin sıfırdan farklı olması halinde “dongu” ile işaretli
yere gidiliyor ve döngü tekrar işletiliyor. En son olarak DL içerisindeki değer 5Ah’a ulaşınca
programın akışı bir sonraki komut olan “mov ah, 4ch” satırına geçiyor.
Yukarıdaki program ile aynı işi yapan C programını aşağıda verdim. Assembly ile yazıla
COM dosyasının boyu 19 bayt iken C ile yazılanınki 8378 bayt!
#include
int main()
{
int ch=65; /* hex 41 */
dongu:
if (ch!=90) /* hex 5A */
{
printf("%c",ch);
ch++;
goto dongu;
}
return 0;
}
38
C örneğinde, ilk programdaki “cmp” ve “jnz” ile gerçekleştirilen işlemler “if” ve “goto”
deyimleri ile gerçekleştirilmiştir.
3.6.4 JB/JC/JNAE Komutları
JB/JC/JNAE (Jump if Below/Jump if Carry/Jump if Not Above or Equal) komutları carry
flag’ın değerine göre dallanma gerçekleştirirler. Herhangi bir işlem sonrasında carry flag
içerisinde 1 değeri varsa programın akışı JB komutu ile gösterilen yere gider. Aksi taktirde JB
komutu dikkate alınmadan programın normal akışına devam edilir.
3.6.5 JBE/JNA Komutları
JBE/JNA (Jump if Below or Equal/Jump if Not Above) komutlarının icrası sırasında carry ve
zero flag’ları kontrol edilir. Bir işlem sonrasında iki flag’dan birinin 1 olması durumunda JBE
komutu ile gösterilen noktaya dallanma yapılır.
3.6.6 JNB/JNC/JAE Komutları
JNB/JNC/JAE (Jump if Not Below/Jump if Not Carry/Jump if Above or Equal)
komutlarından birisi ile karşılaşıldığı zaman CPU carry flag’ın değerini kontrol eder. Carry flag
içerisindeki değerin sıfır olması halinde JNB komutu ile gösterilen noktaya dallanma
gerçekleştirilir.
3.6.7 JG/JNLE Komutları
JG/JNLE (Jump if Greater than/Jump if Not Less than or Equal) komutlarının gerçekleşmesi
için gerekli koşul sign ve overflow flag’larının değerlerinin eşit olması veya zero flag içerisinde
sıfır değerinin bulunmasıdır. Gerekli koşulların sağlanması halinde JG komutu ile gösterilen
noktaya dallanma yapılacak ve programın akışı o noktadan devam edecektir.
3.6.8 JA/JNBE Komutları
JA/JNBE (Jump if Above/Jump if Not Below or Equal) komutlarının icrası sırasında dikkate
alınan flag’lar carry ve zero flag’larıdır. Eğer herhangi bir işlem sonrasında bu iki flag bitinin
de değeri sıfır ise programın akışı JA komutu ile gösterilen yerden devam eder. İki flag bitinden
birisinin sıfır olmaması halinde program normal akışına devam edecektir.
3.6.9 JL/JNGE Komutları
JL/JNGE (Jump if Less than/Jump if Not Greater or Equal) komutlarının gerçekleşmesi için
gerekli koşul carry ve overflow flag bitlerinin birbirinden farklı değerler taşımasıdır. İki bitin
farklı değerler içermesi durumunda programın akışı JL komutu ile gösterilen noktaya
yönlendirilir.
3.6.10 JLE/JNG Komutları
JLE/JNG (Jump if Less than or Equal/Jump if Greater) komutlarının icrası sırasında zero,
sign ve overflow flag’larının değerleri dikkate alınır. Komut ile gösterilen yere dallanmak için
zero flag içerisinde 1 değerinin olması yada sign ve overflow flag’larının değerlerinin farklı
olması gerekmektedir. Gerekli koşul sağlanırsa programın akışı JLE komutu ile gösterilen
noktaya kaydırılacaktır.
3.6.11 JS ve JNS Komutları
JS (Jump if Sign) ve JNS (Jump if No Sign) komutlarının icrası sırasında sign flag kontrol
edilir. Sign flag içerisindeki değerin 1 olması JS için, sıfır olması JNS için gerekli koşuldur.
39
Gerekli koşulun sağlanması durumunda program JS veya JNS komutu ile gösterilen noktadan
akışına devam edecektir.
3.6.12 JO ve JNO Komutları
JO (Jump if Overflow) ve JNO (Jump if No Overflow) komutlarının icrası sırasında overflow
flag içerisindeki değere bakılır. Overflow flag içerisinde 1 JO komutu için ve sıfır olması JNO
komutu için gerekli koşuldur.
3.6.13 JCXZ Komutu
JCXZ (Jump if CX is Zero) komutu CX register’ının değerini kontrol eder. Eğer CX
içerisindeki değer sıfır ise program JCXZ komutu ile gösterilen yerden akışına devam eder.
Yukarıda verilen koşullu dallanma komutları ile sadece +128/-128 bayt’lık bir atlama
gerçekleştirilebilir. Eğer program içerisinde daha uzak bir mesafeye dallanma yapmak
gerekiyorsa aşağıdaki gibi bir yol izlenmelidir.
• JMP komutu ile istenilen noktaya dallanma yapılır
• JMP komutundan sonraki noktaya bir etiket verilir
• Kullanılacak komutun tersi JMP komutunun önüne yazılarak JMP komutundan sonraki
etikete dallanma yapılır
Örneğin DEBUG içerisinde 0100 numaralı offsetde iken “JE 184” komutunu veremezsiniz.
Bu komutu çalıştırmak için yapmanız gerekenler sırasıyla
???? : 0100 jne 105
???? : 0102 jmp 184
???? : 0105
komutlarını vermektir. Dikkatli bir şekilde incelenirse yukarıdaki komut kümesinin “JE 184”
komutu ile aynı şeyi yaptığı görülecektir.
3.7 Döngü Komutları
Bu kategorideki komutlar herhangi bir rutini belirli kereler tekrarlamak için kullanılır.
Assembly dilinde kullanılan döngü komutları bir bakıma C dilindeki “for” ve “while” döngüleri
ile eşleştirilebilir.
3.7.1 LOOP Komutu
Bu komut herhangi bir durumu belirli kereler tekrarlamak için kullanılır. Sayaç olarak CX
register’ı içerisindeki değer alınır. Her döngüde CX içerisindeki değer bir azaltılır ve CX’in
değeri sıfır oluncaya kadar işlem devam eder. Komutun genel kullanım kalıbı aşağıdaki gibidir.
loop hedef
“hedef” ile belirtilen değer DEBUG için bir offset adresi, herhangi bir assembler kullanılarak
birleştirilecek bir program için bir etiket olmalıdır. LOOP komutu ile yapılabilecek maksimum
atlama +128/-128 bayt’tır. Komutun kullanımı gereği atlanılacak nokta LOOP komutundan
önceki adreslerden birisi olduğu için maksimum gidilebileceğimiz adres –128 bayt
mesafededir.
40
1E27:0100 XOR AX, AX
1E27:0102 MOV CX,0005
1E27:0105 INC AX
1E27:0106 LOOP 0105
Yukarıdaki programın sonunda AX’in değeri 5 olacaktır. Programın başında CX içerisine
atılan 5 değeri LOOP ile gerçekleştirilecek döngü sayısını belirlemektedir.
1E27:0100 XOR AX, AX
1E27:0102 MOV CX,0005
1E27:0105 INC AX
1E27:0106 DEC CX
1E27:0107 JNZ 0105
Yukarıdaki program bir önceki örnekteki program ile aynı işlemi gerçekleştirmektedir. Tek
fark “LOOP 0105” komutu yerine “INC CX” ve “JNZ 0105” komutlarının kullanılmasıdır.
Gerçekte de LOOP ile yapılan bu iki komutun yaptığı işlemden başka bir şey değildir.
3.7.2 LOOPZ/LOOPE Komutları
LOOPZ/LOOPE komutları da herhangi bir durumu belirli kereler tekrarlamak için kullanılır.
Komutun kullanımı LOOP komutu ile aynıdır. Tek fark LOOPZ komutu icrası sırasında CX
register’ının değerinin yanı sıra zero flag’ı da kontrol eder. CX’in değeri sıfırdan farklı olduğu
sürece ve zero flag içerisindeki değer 1 olduğu sürece komut ile gösterilen yere dallanma
yapılır.
Her iki durumdan birisinin gerçekleşmemesi halinde döngüden çıkılır.
3.7.3 LOOPNZ/LOOPNE Komutları
LOOPNZ/LOOPNE komutları da LOOP komutu gibi CX register’ını sayaç olarak kabul
ederek bir koşulu belirli kereler tekrar etmek için kullanılır. Döngü işlemi CX’in değeri sıfırdan
farklı iken ve zero flag içerisindeki değer 1 değil iken devam eder.
Hiç yorum yok:
Yorum Gönder