Bölüm 4.2: Değişkenler
Giriş
Öğrenme Çıktıları
DB, DW, DD, DUP ve ? ile değişken ve dizi tanımlamak.
Derleyicinin değişkenleri hangi bağıl konumlara, hangi bayt sırasıyla yerleştirdiğini çıkarmak.
LEA ve OFFSET ile değişken adresini almak ve dizi elemanlarına indisle erişmek.
Değişkenler arasında veri taşıyan, toplayan ve karşılaştıran programları adım adım izlemek.
Değişkenler
Değişkenler
- Bir değişken bir bellek konumunu temsil eder.
- Programcı için
var1adını kullanmak,5A73:235Badresini kullanmaktan çok daha kolaydır. - Derleyici iki temel tür destekler:
- BYTE (8 bit):
ad DB değer(Define Byte) - WORD (16 bit):
ad DW değer(Define Word)
- BYTE (8 bit):
DD(Define Double word, 32 bit) de vardır: 4 bayt.
counter DB 10h ; BYTE sum DW 0FFFFh ; WORD
Değişkenler
Adlandırma ve İlk Değer
- Değişken adları harfle başlamalıdır; sonrasında harf ve rakam kombinasyonları içerebilir.
- Yazmaç ve komut adları (
AX,MOV…) değişken adı olamaz. - Ad belirtilmeyen değişkenler de olabilir: adları yoktur ama adresleri vardır.
- Herhangi bir sayısal değer (ikili, onluk, onaltılık, karakter) alabilir.
- İlk değer atanmamış değişkenler için
?kullanılır (emu8086 belleğe 00 koyar).
| Tanım | ? |
|---|---|
sayi1 DB 5 | geçerli |
1sayi DB 5 | rakamla başlıyor |
ax DW 0 | yazmaç adı |
DB 0Ah | adsız, ama adresi var |
sonuc DW ? | ilk değersiz |
harf DB 'A' | 41h |
Değişkenler
Değer Aralıkları
| Direktif | Boyut | İşaretsiz | İşaretli | Örnek |
|---|---|---|---|---|
DB | 1 bayt | 0 … 255 | −128 … 127 | x DB -1 → FFh |
DW | 2 bayt | 0 … 65535 | −32768 … 32767 | y DW -2 → FE FF |
DD | 4 bayt | 0 … 4 294 967 295 | −231 … 231−1 | z DD 1 → 01 00 00 00 |
DB 300 bir bayta sığmaz → assembler hata verir.Değişkenler · Kodu adım adım çalıştır
Kod İzleme: FFh 255 mi, −1 mi?
ORG 100h MOV AL, x ; FFh ADD AL, 1 ; 255 + 1 ? MOV AL, x CBW ; işaretli: −1 MOV BX, y ; FFFEh NEG BX ; −(−2) RET x DB -1 y DW -2
Bellekte x = FFh, y = FE FF (little-endian FFFEh). AL = x = FFh: işaretsiz 255, işaretli −1.
ADD AL, 1: işaretsiz bakışla 255 + 1 = 256 bayta sığmaz → AL = 00h, CF = 1. İşaretli bakışla −1 + 1 = 0 doğru: OF = 0.
AL yeniden FFh.
CBW AL'yi işaretli kabul eder: MSB = 1 → AH = FFh, AX = FFFFh = −1 (16 bit).
BX = y = FFFEh: işaretsiz 65534, işaretli −2.
NEG BX: 0 − (−2) = 0002h. Bit deseninin anlamını komut seçti: ADD/CF işaretsiz, CBW/NEG işaretli yorumladı.
DB/DW yalnızca bit desenini saklar; işaretli mi işaretsiz mi olduğuna değeri kullanan komut karar verir.
Değişkenler
Değişkenin Türü ve Boyut Denetimi
- Assembler her değişken adının yanında bir tür saklar: DB → BYTE (1), DW → WORD (2), DD → DWORD (4).
- Komuttaki diğer işlenen yazmaçsa boyutlar eşleşmelidir; eşleşmezse derleme durur.
- Sabit yazarken boyutu değişkenin türü belirler:
MOV w, 5bir sözcük yazar. - Değişken adı olmayan
[BX]gibi işlenenlerin türü yoktur; sabitle kullanılırkenBYTE PTRya daWORD PTRgerekir. BYTE PTRtürü yalnızca o komut için değiştirir; değişkenin tanımı aynı kalır.
| Komut (w DW 1234h, b DB 5) | Sonuç |
|---|---|
MOV AL, w | hata: 1 bayt / 2 bayt |
MOV AL, BYTE PTR w | AL = 34h (düşük bayt) |
MOV AL, BYTE PTR w+1 | AL = 12h (yüksek bayt) |
MOV w, 5 | w = 0005h (sözcük) |
MOV AX, b | hata: 2 bayt / 1 bayt |
MOV [BX], 5 | hata: boyut belirsiz |
MOV b, w | hata: bellekten belleğe |
INC b | b = 6 (bayt artırılır) |
Değişkenler · Kodu adım adım çalıştır
Kod İzleme: Aynı Belleğe İki Ad (LABEL)
ORG 100h MOV AX, sozcuk ; WORD MOV BL, baytlar ; düşük MOV BH, baytlar+1 ; yüksek MOV baytlar, 0FFh ; tek bayt MOV CX, sozcuk ; sözcük RET sozcuk LABEL WORD baytlar DB 34h, 12h
sozcuk LABEL WORD yer ayırmaz; yalnızca 0115h adresine WORD türünde ikinci bir ad verir. MOV AX, sozcuk iki baytı birden okur: AX = 1234h.
baytlar aynı adresin BYTE türündeki adıdır: BL = 34h. PTR yazmaya gerek kalmadı.
baytlar+1 ikinci bayt: BH = 12h. BX = 1234h; little-endian sıranın sonucu.
Tür BYTE olduğu için MOV baytlar, 0FFh yalnızca 0115h adresine yazar: bellek FF 12.
Aynı bellek WORD adıyla okununca değişiklik görülür: CX = 12FFh. İki ad, tek bellek konumu.
RET. LABEL bellekte bayt üretmedi; program boyutu iki baytlık tanım kadar arttı.
ad LABEL tür, kendisinden sonraki ilk bayta yeni bir ad ve tür verir. Bir tamponu hem bayt bayt hem sözcük sözcük işlemek için PTR yazmaktan daha okunaklıdır.
Bellek Yerleşimi
Örnek Kod
ORG 100h MOV AL, var1 ; AL ← var1 MOV BX, var2 ; BX ← var2 RET ; programı bitir VAR1 DB 7 ; BYTE, 7 var2 DW 1234h ; WORD, 1234h
- Kod önce, değişkenler RET'ten sonra: CPU onlara hiç ulaşmaz.
- Derleyici kaynağı bir bayt dizisine çevirir ve değişken adlarını bellek konumlarıyla değiştirir.
- Büyük-küçük harfe duyarsızdır:
VAR1ilevar1aynı değişkendir.
Bellek Yerleşimi · Kodu adım adım çalıştır
Kod İzleme: var1 ve var2
Program 0B56:0100'e yüklendi; DS = CS = 0B56h, IP = 0100h.
MOV AL, [0108h]: VAR1'in değeri → AL = 07h. IP = 0103h.
MOV BX, [0109h]: 34h düşük, 12h yüksek bayt → BX = 1234h. IP = 0107h.
RET (0107h'de C3) yığından 0000h'yi alır: IP = 0000h, PSP'deki INT 20h programı bitirir. 0108h'den sonrası veridir.
ORG 100h MOV AL, var1 ; AL ← var1 MOV BX, var2 ; BX ← var2 RET ; programı bitir VAR1 DB 7 ; BYTE, 7 var2 DW 1234h ; WORD, 1234h
Bellek Yerleşimi
Derleyici Ne Yapar?
- Kaynak kodu bir dizi bayta dönüştürür; değişken adlarını bağıl konumlarla değiştirir:
MOV AL, var1→MOV AL, [0108h]. - .COM dosyaları yüklendiğinde DS, CS yazmacının değerini alır (ES ve SS de aynıdır).
- Bağıl konum (offset), bellek kesiminin başlangıcından itibaren olan uzaklıktır.
VAR1'in bağıl konumu 0108h, tam adresi 0B56:0108'dir.var2'nin bağıl konumu 0109h, tam adresi 0B56:0109'dur.- WORD türünde olduğu için 2 bayt kaplar (0109h ve 010Ah).
- Düşük bayt düşük adreste saklanır: 34h, 12h'den önce yer alır (little-endian).
Bellek Yerleşimi
ORG 100h Direktifi
- Derleyiciye çalıştırılabilir dosyanın yükleneceği adresi söyler; değişken adları adreslerle değiştirilirken dikkate alınır.
- .COM dosyalarında kullanılır; bu dersteki örneklerin çoğu emu8086 .COM şablonuyla yazılır.
- İşletim sistemi kesimin ilk 256 baytında (PSP) programla ilgili verileri tutar; komut satırı parametreleri bu alandadır.
- .EXE dosyaları 0000h bağıl konumuna yüklenir ve değişkenler için ayrı bir kesim kullanır.
- Direktifler gerçek makine koduna dönüştürülmez.
Bellek Yerleşimi
Hizalama: Sözcük Hangi Adreste?
a DB 5 ; 0200h EVEN ; 0201h: dolgu w DW 1234h ; 0202h (çift)
- 8086'nın veri yolu 16 bittir: çift adresten başlayan bir sözcük tek yol döngüsünde okunur.
- Tek adresteki sözcük için iki yol döngüsü gerekir; 8086 bunu kendiliğinden yapar, yalnızca daha yavaştır (sözcük erişimi başına 4 saat turu).
- MASM ve TASM'daki
EVENdirektifi konum sayacını çift sayıya yuvarlar; gerekirse araya bir dolgu baytı koyar. Tanımlar yer değiştirmez, yalnızca kayar. - 8 bitlik veri yolu olan 8088'de her sözcük zaten iki döngüdür; hizalama orada fark yaratmaz.
MOV AX, w 8086'da 10 saat turudur; w tek adresteyse 14 olur. Bir döngüde 1000 kez okunan sözcük için fark 4000 tur, 5 MHz'de 0,8 ms eder. Bayt değişkenler için hizalama gerekmez.Bellek Yerleşimi
Değişkenler Nereye Yazılır?
| Yer | Örnek | Dikkat edilecek nokta |
|---|---|---|
| Kodun sonunda | RET · x DB 5 | Yürütme RET'te biter, veriye hiç ulaşmaz. .COM'da en sık kullanılan düzen. |
| Kodun başında | JMP basla · x DB 5 · basla: | JMP veriyi atlar; unutulursa veri baytları komut olarak yürütülür. |
| Ayrı veri kesimi (.EXE) | .DATA · x DB 5 | Program başında MOV AX, @data · MOV DS, AX şarttır. |
MOV AL, x doğru bağıl konumu kullanır ama yanlış kesimden okur: hata vermeden yanlış değer gelir.Diziler
Diziler
- Diziler değişken zincirleri olarak düşünülebilir: ardışık bellek konumlarında saklanan veri gruplarıdır.
- Tırnak içindeki metin otomatik olarak bayt dizisine (ASCII kodları) dönüştürülür.
- Dizi elemanlarına bellek adresi üzerinden erişilir: ilk eleman dizinin adresinde, sonrakiler ardından.
a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h b DB 'Hello', 0
a ve b bellekte aynı baytları tutar: 48h 'H', 65h 'e', 6Ch 'l', 6Ch 'l', 6Fh 'o', 00h (dizgi sonu).
Diziler · Kodu adım adım çalıştır
Kod İzleme: Dizi Elemanlarına Erişim
a[3], a + 3 bayt demektir: AL = 6Ch ('l').
İndis yazmacı SI = 0.
a[SI] = [a + SI]: BL = 48h ('H').
SI = 1: bir sonraki bayt.
BH = a[1] = 65h ('e'). BX = 6548h.
Dizi bayt türünde olduğu için boyut belli: a[1] ← 45h ('E'). Dizi artık “HEllo”.
RET. Dizi tanımı kodun sonunda, yürütülmeyen bölgede.
MOV AL, a[3] ; a + 3 MOV SI, 0 MOV BL, a[SI] ; a + 0 INC SI MOV BH, a[SI] ; a + 1 MOV a[SI], 'E' ; a[1] ← 45h RET a DB 48h,65h,6Ch,6Ch,6Fh,0
Diziler
Erişim Yolları ve DUP
- Köşeli parantezle sabit indis:
MOV AL, a[3] - Bellek indis yazmaçları (BX, SI, DI, BP) ile:
MOV SI, 3·MOV AL, a[SI] - Eşdeğer yazımlar:
a[SI]=[a + SI]=[SI + a] - İndis bayt cinsindendir, eleman sayısı değil.
sayı DUP(değer(ler))
c DB 5 DUP(9)=c DB 9, 9, 9, 9, 9d DB 5 DUP(1, 2)=d DB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2tampon DB 100 DUP(?): 100 baytlık ilk değersiz alantablo DW 10 DUP(0): 10 sözcük = 20 bayt
w DW 1000h, 2000h); kullanılamadığı şey metin dizgileridir (DW 'Hello' geçersiz). Değerler 255'ten büyük ya da −128'den küçükse DW gerekir.Diziler · Kodu adım adım çalıştır
Kod İzleme: DW Dizisinde İndis
w[0]: ilk sözcük → AX = 1111h.
İkinci eleman w[2]'dedir (her eleman 2 bayt): BX = 2222h.
i. elemanın indisi = 2 × i: üçüncü eleman için SI = 4.
CX = w[SI] = 3333h.
w[1] elemanın ortasından okur: baytlar 11h, 22h → DX = 2211h. Sık yapılan hata!
MOV AX, w[0] ; 1. eleman MOV BX, w[2] ; 2. eleman MOV SI, 4 MOV CX, w[SI] ; 3. eleman MOV DX, w[1] ; dikkat! RET w DW 1111h, 2222h, 3333h
Diziler
Tanımdan Bayta
Yazılan DB / DW / DD satırı baytlara açılır. Sayılar (onluk, h, b, o), 'metin' (yalnız DB), ? ve n DUP(…) desteklenir. Hücre üstü: değişkenin başından bayt uzaklığı.
Diziler
Dizgiler ve Sonlandırıcılar
s1 DB 'Merhaba', 0 ; sıfırla biten dizgi s2 DB 'Merhaba$' ; '$' ile biten (INT 21h / AH = 09h) s3 DB 13, 10, 'Satır', 13, 10, '$' ; CR LF: satır başı + yeni satır s4 DB 7, 'Merhaba' ; uzunluk önekli: ilk bayt = 7 s5 DB "Ali'nin", 0 ; çift tırnak içinde tek tırnak
| Biçim | Sonu nasıl anlaşılır? | Nerede kullanılır? |
|---|---|---|
| 0 ile biten | okunan bayt 0 olunca | emu8086.inc PRINT_STRING, C dili |
| '$' ile biten | okunan bayt 24h olunca | DOS dizgi yazdırma hizmeti |
| uzunluk önekli | ilk bayttaki sayı kadar | DOS satır girişi tamponu (AH = 0Ah) |
- Dizginin bellekte kapladığı yer = karakter sayısı + sonlandırıcı: s1 için 8 bayt. Sonlandırıcı unutulursa yazdırma, dizginin ardındaki baytları da karakter sanıp devam eder.
- '$' ile biten bir dizgi '$' karakterini yazdıramaz. Türkçe harflerin (ç, ğ, ş…) kodu kullanılan kod sayfasına bağlıdır; ASCII'nin 0–127 aralığında değildir.
Diziler
Karakter Sabitleri ve ASCII Aritmetiği
| Karakterler | ASCII kodları |
|---|---|
| '0' … '9' | 30h … 39h |
| 'A' … 'Z' | 41h … 5Ah |
| 'a' … 'z' | 61h … 7Ah |
| boşluk · '$' | 20h · 24h |
| CR · LF | 0Dh · 0Ah |
- Tırnak içindeki karakter assembler için yalnızca bir sayıdır:
MOV AL, 'A'=MOV AL, 41h. - Rakam karakterinden sayıya:
SUB AL, '0'('7' = 37h → 7). Ters yön:ADD AL, '0'. - Büyük ve küçük harf arasındaki fark 20h, yani yalnızca bit 5'tir:
SUB AL, 20hya daAND AL, 0DFhbüyütür,OR AL, 20hküçültür.
AND AL, 0DFh yalnızca harflerde doğru çalışır. '1' (31h) üzerinde uygulanırsa sonuç 11h olur ve rakam bozulur; bu yüzden harf olup olmadığı önce denetlenir ('a' ≤ AL ≤ 'z').Diziler · Kodu adım adım çalıştır
Kod İzleme: Dizgiyi Büyük Harfe Çevirme
ORG 100h LEA SI, s don: MOV AL, [SI] CMP AL, 0 ; sonlandırıcı? JE bitti CMP AL, 'a' JB sonraki CMP AL, 'z' JA sonraki SUB AL, 20h ; 'a' - 'A' MOV [SI], AL sonraki: INC SI JMP don bitti: RET s DB 'Ab1c', 0
LEA SI, s: SI = 0119h, dizginin ilk baytı. Dizgi 'Ab1c' ve sonlandırıcı 0.
'A' (41h): 0 değil; CMP AL, 'a' → 41h < 61h, JB atlar. Büyük harf olduğu için yazılmadı; SI ilerledi.
'b' (62h): 'a' ≤ 62h ≤ 'z' → SUB AL, 20h = 42h ('B'), MOV [SI], AL belleğe geri yazar.
'1' (31h): 'a'dan küçük, atlanır. Harf denetimi olmasaydı 31h − 20h = 11h ile rakam bozulurdu.
'c' (63h) → 43h ('C'). Dizgi artık 'AB1C'.
Okunan bayt 0: CMP AL, 0 → ZF = 1, JE bitti. Döngü dizginin uzunluğunu bilmeden, sonlandırıcıda durdu.
Dizgi yerinde değiştirildi: her bayt okunur, harfse 20h çıkarılıp aynı adrese yazılır. Uzunluk yerine sonlandırıcı (0) kullanıldı.
Diziler
İki Boyutlu Diziler (Tablolar)
mat DB 3 DUP(4 DUP(0)) ; 3 × 4 tab DW 3 DUP(4 DUP(0)) ; 24 bayt
- Bellek tek boyutludur; tablo satır öncelikli düzende yerleşir: önce 0. satırın tüm sütunları, sonra 1. satır…
- Bağıl uzaklık = (satır × sütun sayısı + sütun) × eleman boyu.
- Sözcük tablosunda [1][2]: (1 × 4 + 2) × 2 = 12 bayt.
- İç içe DUP satır ve sütunu birlikte ayırır: 3 kez (4 kez 0).
SHL. Satır sayısı dizinin yerleşimine girmez; yalnızca satır indisinin sınırını belirler.Diziler · Kodu adım adım çalıştır
Kod İzleme: mat[2][1] Elemanını Okuma
SUTSAY EQU 4 ORG 100h MOV AL, satir ; AL = 2 MOV BL, SUTSAY ; BL = 4 MUL BL ; AX = 2 × 4 ADD AL, sutun ; + 1 MOV SI, AX ; SI = 9 MOV DL, mat[SI] ; mat[2][1] RET mat DB 11h, 12h, 13h, 14h DB 21h, 22h, 23h, 24h DB 31h, 32h, 33h, 34h satir DB 2 sutun DB 1
AL ← satir = 2. Hedef eleman: mat[2][1]. Tablo 0112h adresinde, 3 satır × 4 sütun bayt.
SUTSAY EQU 4 komuta gömülür: BL = 04h (sütun sayısı).
MUL BL: AX = AL × BL = 2 × 4 = 0008h. 2. satırın başı, tablonun 8. baytı.
ADD AL, sutun: 8 + 1 = 9. AH zaten 0 olduğu için AX = 0009h.
Uzaklık indis yazmacına alınır: SI = 0009h. AL indis olarak kullanılamaz; adreslemede yalnız BX, SI, DI, BP.
mat[SI] = [0112h + 9]: DL = 32h. 2. satır 1. sütun.
RET. Sabit adı SUTSAY seçildi: SUTUN EQU 4 yazılsaydı assembler büyük-küçük harfe duyarsız olduğundan sutun DB 1 ile aynı ad olur ve “iki kez tanımlı” hatası verirdi.
Satır ve sütun çalışma anında değişkenlerden okundu; aynı kod her eleman için çalışır. Sözcük tablosunda sonuç ayrıca 2 ile çarpılırdı.
Adresler
Değişkenin Adresini Alma
LEA BX, VAR1. İndisli değişkenlerin adresini almak için de kullanılabilir: LEA BX, a[SI].MOV BX, OFFSET VAR1.| Komut | BX'e ne yüklenir? |
|---|---|
MOV BX, VAR1 (VAR1 DW) | VAR1'in değeri (içerik) |
LEA BX, VAR1 · MOV BX, OFFSET VAR1 | VAR1'in adresi (bağıl konum) |
Adresler · Kodu adım adım çalıştır
Kod İzleme: LEA ile Değişken Güncelleme
Kod 0100h'den başlar; derleyici VAR1'i 010Dh'ye yerleştirdi (12 bayt kod + RET).
AL = VAR1'in değeri = 22h.
BX = VAR1'in adresi = 010Dh. BX artık VAR1'i gösteren bir işaretçidir.
[BX] üzerinden VAR1 güncellenir: [010Dh] = 44h.
VAR1 tekrar okunur: AL = 44h. Değişkene adı ile de işaretçi ile de erişilebilir.
RET. END kaynak dosyanın sonunu bildiren direktiftir.
ORG 100h MOV AL, VAR1 ; değer LEA BX, VAR1 ; adres MOV BYTE PTR [BX], 44h MOV AL, VAR1 ; yeni değer RET VAR1 DB 22h END
Adresler
LEA ve OFFSET Aynı mı?
OFFSET ile aynı program
ORG 100h MOV AL, VAR1 MOV BX, OFFSET VAR1 MOV BYTE PTR [BX], 44h MOV AL, VAR1 RET VAR1 DB 22h END
- emu8086'da
LEA BX, VAR1veMOV BX, OFFSET VAR1aynı makine koduna derlenir:BB 0D 01(3 bayt,MOV BX, 010Dh). İki programda da VAR1 = 010Dh'dir. - Gerçek 8086 assembler'ı MASM ise LEA'yı ayrı bir komut olarak kodlar:
8D 1E 0D 01(4 bayt). - Fark:
LEA BX, a[SI]adresi çalışma anında hesaplar (a + SI); OFFSET yalnızca sabit adres verir. - Köşeli parantez içinde yalnızca BX, SI, DI, BP kullanılabilir.
Adresler · Kodu adım adım çalıştır
Kod İzleme: LEA a[BX] ile OFFSET a
ORG 100h MOV BX, 2 LEA SI, a[BX] ; SI = a + BX MOV DI, OFFSET a ; sabit adres ADD DI, BX ; elle ekle MOV AL, [SI] INC BX LEA SI, a[BX] ; yeni adres MOV AH, [SI] RET a DB 'ABCD'
BX = 2: indis. a dizisi 0116h'de başlıyor: 'A' 'B' 'C' 'D'.
LEA SI, a[BX]: adres çalışma anında hesaplanır: 0116h + 2 = 0118h. Bellek okunmaz.
OFFSET a derleme anında bilinen sabittir: DI = 0116h. BX'i katamaz.
Aynı adres için OFFSET ile ayrıca ADD gerekir: DI = 0118h = SI.
AL = [SI] = 43h ('C').
BX = 3.
LEA güncel BX ile yeniden hesaplar: SI = 0119h.
AH = [SI] = 44h ('D'). AX = 4443h.
LEA adresi yazmaçlarla çalışma anında hesaplar; OFFSET yalnızca derleme anında bilinen sabit adresi verir.
Adresler
İşaretçi Değişkenleri
ORG 100h MOV BX, p ; 010Bh LEA SI, p ; 010Fh MOV DI, OFFSET dizi RET dizi DB 'KAYA' ; 010Bh p DW dizi ; 010Fh, içi 010Bh uzak DD dizi ; bağıl konum + kesim
- DW'nin değeri bir değişken adı olursa o değişkenin adresi saklanır: p bir işaretçi değişkendir.
- İşaretçi bellekte durduğu için değiştirilebilir:
ADD p, 2onu dizinin ilerisine kaydırır. - Kullanmak için önce bir adres yazmacına alınır:
MOV BX, p·MOV AL, [BX]. DDile tanımlanan uzak işaretçi bağıl konum ve kesimi birlikte tutar;LDS SI, uzakya daLES DI, uzakile tek komutta yüklenir.
| Komut | Yazmaca ne yüklenir? | Değer |
|---|---|---|
MOV BX, p | p'nin içindeki adres (dizinin adresi) | 010Bh |
LEA SI, p | p'nin kendi adresi | 010Fh |
MOV DI, OFFSET dizi | dizinin adresi, derleme anında sabit | 010Bh |
Adresler · Kodu adım adım çalıştır
Kod İzleme: Bellekteki İşaretçi
ORG 100h MOV BX, p ; p'nin içi MOV AL, [BX] ; dizi[0] ADD p, 2 ; ilerlet MOV BX, p MOV AH, [BX] ; dizi[2] RET dizi DB 'KAYA' p DW dizi ; adres
MOV BX, p: p'nin içeriği okunur. p = DW dizi olduğundan BX = 0112h, dizinin adresi.
MOV AL, [BX]: işaretçinin gösterdiği bayt: AL = 4Bh ('K').
ADD p, 2: bellekteki işaretçi artık 0114h'yi gösterir. BX değişmedi; eski adresi tutuyor.
İşaretçi yeniden yüklenir: BX = 0114h.
MOV AH, [BX]: AH = 59h ('Y'). AX = 594Bh.
RET. Dizinin adresi kodda hiç yazılmadı; hangi elemanın okunacağına bellekteki işaretçi karar verdi.
İşaretçi değişkeni bir adresi bellekte saklar; yazmaçlar azken pek çok dizinin konumunu tutmanın yoludur. Her kullanımda önce BX, SI ya da DI'ye alınır.
Sabitler
Sabitler (EQU)
- Değişkenlere benzer, ancak yalnızca derleme sırasında var olurlar; bellekte yer kaplamazlar.
- Bir sabitin değeri tanımlandıktan sonra değiştirilemez.
- Programın farklı bölümlerinde aynı değerin kullanılmasını sağlar; değer tek yerden güncellenir.
- Tanım:
ad EQU <herhangi bir ifade> - Assembler her kullanımda adı değeriyle değiştirir:
MOV AX, k→MOV AX, 5(B8 05 00).
k EQU 5 SATIR EQU 80 MOV AX, k ; AX = 5 MOV BX, SATIR*2 ; BX = 160 MOV CL, k+1 ; CL = 6
k EQU 5 | k DB 5 | |
|---|---|---|
| Bellek | kullanmaz | 1 bayt |
MOV AL, k | AL ← 5 (anlık) | AL ← [k] (bellekten) |
| Değiştirilebilir mi? | hayır | evet: MOV k, 7 |
Sabitler · Kodu adım adım çalıştır
Kod İzleme: EQU Komuta Gömülür
k EQU 5 SATIR EQU 80 ORG 100h MOV AX, k ; MOV AX, 5 MOV BX, SATIR*2 ; MOV BX, 160 MOV CL, k+1 ; MOV CL, 6 MOV DL, v ; bellekten RET v DB 5 ; 1 bayt yer
k EQU 5: assembler sembol tablosuna k = 5 yazar. Bellekte yer ayrılmaz, makine kodu üretilmez.
SATIR = 80 da yalnız derleme anında vardır. Program 0100h'den başlar; ilk bayt MOV AX, k'nın kodudur.
MOV AX, k → MOV AX, 5 (B8 05 00): 5 komutun içinde, anlık değer. AX = 0005h.
SATIR*2 derleme anında hesaplandı: 160 = 00A0h → BX = 00A0h.
k+1 = 6 → CL = 06h. Çalışma anında toplama yapılmadı.
v bir değişken: komut adresini (010Dh) taşır, değer bellekten okunur: DL = 05h. v 1 bayt yer kaplar, k hiç kaplamaz.
Makine kodları MASM/emu8086 kodlamasıdır: B8 iw (MOV AX, sabit), BB iw (MOV BX, sabit), B1 ib (MOV CL, sabit), 8A 16 adres (MOV DL, [adres]).
Sabitler
Konum Sayacı ($) ve Boyut İşleçleri
- Assembler bir sonraki baytın yerleşeceği bağıl konumu bir sayaçta tutar: konum sayacı. Kaynakta
$ile okunur. - Bir dizinin hemen arkasında
$ − dizi, dizinin bayt sayısıdır. Dizi büyüyüp küçülse de sabit kendiliğinden doğru kalır. - EQU satırı dizinin hemen ardından gelmelidir; araya başka bir tanım girerse onun baytları da sayılır.
- MASM'daki
TYPE,LENGTHOFveSIZEOFişleçleri aynı bilgiyi değişkenin tanımından okur.
s DB 'Merhaba', 0 n EQU $ - s ; 8 w DW 10 DUP(0)
| İfade | Değer | Anlamı |
|---|---|---|
n | 8 | s'nin bayt sayısı |
TYPE s | 1 | eleman boyu (DB) |
LENGTHOF s | 8 | eleman sayısı |
TYPE w | 2 | eleman boyu (DW) |
LENGTHOF w | 10 | eleman sayısı |
SIZEOF w | 20 | LENGTHOF × TYPE |
MOV CX, LENGTHOF w komuta 10 gömer, bellekte yer kaplamaz. Sözcük dizisinde döngü sayacı LENGTHOF, bayt uzunluğu SIZEOF ile alınır.Sabitler · Kodu adım adım çalıştır
Kod İzleme: $ ile Boyut, Döngüyle En Büyük Eleman
ORG 100h JMP basla dizi DB 12, 47, 5, 31 n EQU $ - dizi ; 4 enb DB ? basla: MOV CX, n ; CX = 4 MOV SI, 0 MOV AL, dizi[SI] ; ilk aday bak: CMP AL, dizi[SI] JAE gec ; AL >= eleman MOV AL, dizi[SI] ; yeni aday gec: INC SI LOOP bak MOV enb, AL RET
JMP basla veriyi atlar. n EQU $ − dizi = 4 derleme anında hesaplandı: CX = 0004h. İlk eleman aday: AL = 12.
1. tur: 12 ile 12 karşılaştırılır; JAE atlar (eşit). SI = 1, LOOP: CX = 3.
2. tur: 12 < 47 → CF = 1, JAE atlamaz; AL = 47 (2Fh). SI = 2, CX = 2.
3. tur: 47 ≥ 5 → atlanır, AL değişmez. SI = 3, CX = 1.
4. tur: 47 ≥ 31 → atlanır. LOOP: CX = 0, döngü biter.
MOV enb, AL: en büyük eleman 2Fh = 47 belleğe yazıldı; RET.
Döngü sayısı elle yazılmadı; diziye eleman eklenirse n kendiliğinden değişir. JAE işaretsiz karşılaştırır; işaretli dizilerde JGE kullanılır.
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Değişkenler Arasında Veri Taşıma
jmp start CPU'yu verilerin üzerinden atlatır; aksi hâlde veri baytları komut gibi yürütülürdü.
value1 → AX = 000Ah. Bellekten belleğe doğrudan MOV olmadığı için ara yazmaç gerekir.
AX → value2: bellekte 0A 00. Artık value1 = value2 = 10.
end start: kaynağın sonu; start programın giriş noktasıdır.
jmp start value1 DW 10 ; 2 baytlık değişken value2 DW 0 ; ikinci değişken start: MOV AX, value1 ; AX ← value1 MOV value2, AX ; value2 ← AX end start
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Değişkenleri Toplama
Başlangıç: result ? ile tanımlı; emu8086 belleğe 00 00 koyar, ama değerine güvenilmez.
AX = value1 = 0105h.
ADD bellek işlenenini doğrudan kullanabilir: 0105h + 0103h = 0208h. Bayraklar: CF = 0, ZF = 0, PF = 0 (08h'de bir adet 1).
result ← AX: bellekte 08 02 (little-endian).
Sonuç: result = 0208h = 520 (261 + 259).
jmp start value1 DW 105h ; ilk değer 105h value2 DW 103h ; ilk değer 103h result DW ? ; belirsiz start: MOV AX, value1 ; AX ← value1 ADD AX, value2 ; AX ← AX + value2 MOV result, AX ; result ← AX end start
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Büyük Olanı Bul (10, 5)
AX = value1 = 000Ah.
CMP çıkarma yapar ama sonucu saklamaz, yalnız bayrakları ayarlar: 10 − 5.
JGE (işaretli ≥): SF = OF olduğundan atlanır → greater_or_equal.
AX = value1 (zaten öyleydi; bu satır gereksiz ama zararsız).
max_value ← AX = 000Ah.
RET: DOS'a dönüş. RET olmasaydı CPU value1'in baytlarını komut sanıp yürütürdü.
ORG 100h MOV AX, value1 ; AX ← value1 CMP AX, value2 ; AX − value2 JGE greater_or_equal MOV AX, value2 ; küçükse value2 JMP store_max greater_or_equal: MOV AX, value1 store_max: MOV max_value, AX ; sonucu sakla RET value1 DW 10 value2 DW 5 max_value DW ?
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: Büyük Olanı Bul (3, 7)
AX = value1 = 0003h.
CMP çıkarma yapar ama sonucu saklamaz, yalnız bayrakları ayarlar: 3 − 7.
SF ≠ OF → koşul sağlanmaz, atlanmaz; sıradaki komuta geçilir.
AX = value2 = 0007h (büyük olan).
JMP koşulsuz atlar → store_max.
max_value ← AX = 0007h.
RET: DOS'a dönüş. RET olmasaydı CPU value1'in baytlarını komut sanıp yürütürdü.
ORG 100h MOV AX, value1 ; AX ← value1 CMP AX, value2 ; AX − value2 JGE greater_or_equal MOV AX, value2 ; küçükse value2 JMP store_max greater_or_equal: MOV AX, value1 store_max: MOV max_value, AX ; sonucu sakla RET value1 DW 3 value2 DW 7 max_value DW ?
Örnek Programlar
Karşılaştırma Notları
CMP a, b = a − b hesaplanır, sonuç atılır; yalnız bayraklar (CF, ZF, SF, OF, PF, AF) güncellenir.JGE, JG, JL: işaretli (SF, OF). JAE, JA, JB: işaretsiz (CF). value1 = −1 (FFFFh), value2 = 5 için JGE atlamaz, JAE atlar.RET olmasaydı CPU 0A 00 05 00… baytlarını komut olarak yürütürdü. Çözüm: RET (ya da başta jmp start).MOV AX, value1 gereksizdir; AX zaten value1'dir. Etiket doğrudan store_max'e atlayabilir.Örnek Programlar
Çift Sözcük Değişken
jmp start mydouble dd 12345678h ; double word mywords dw 5678h ; 2 ayrı word dw 1234h mybytes db 78h ; 4 ayrı byte db 56h db 34h db 12h data dd 00010010001101000101011001111000b start: ; data'yı DX:AX'e yükle mov ax, word ptr data mov dx, word ptr [data+2]
Dört tanımın da bellekteki karşılığı aynıdır:
DD32 bit = 4 bayt; en düşük bayt en düşük adreste.- 8086'nın 32 bitlik yazmacı yoktur: değer DX:AX çiftinde tutulur (DX yüksek, AX düşük sözcük).
Örnek Programlar · Kodu adım adım çalıştır
Kod İzleme: DX:AX'e 32 Bitlik Yükleme
data'nın ilk iki baytı (78 56) → AX = 5678h. word ptr: data DD olduğu için boyut açıkça belirtilir.
data+2'deki iki bayt (34 12) → DX = 1234h. DX:AX = 1234:5678h = 12345678h.
mov ax, word ptr data ; data+0 mov dx, word ptr [data+2] ; data+2 ret data dd 12345678h
Örnek Programlar
Değişkenlerle İlgili Sık Hatalar
MOV SI, dizi ilk sözcüğü yükler; adres için LEA SI, dizi.MOV v1, v2 yoktur; değer bir yazmaçtan geçer.w[4]'tedir: indis bayt cinsindendir.toplam DW ? sıfır olmayabilir; önce MOV toplam, 0.DW 10 onluk 10'dur (000Ah); onaltılık için 10h.SUTUN EQU 4 ile sutun DB 1 aynı addır: “iki kez tanımlı”.Örnek Programlar
Veri Tanımlama Özeti
| Yazım | Anlamı | Bellek |
|---|---|---|
x DB 7 | bir bayt | 07 |
y DW 1234h | bir sözcük | 34 12 |
z DD 12345678h | çift sözcük | 78 56 34 12 |
s DB 'Hi', 0 | dizgi + sonlandırıcı | 48 69 00 |
t DB 3 DUP(0) | tekrar | 00 00 00 |
u DW ? | ilk değersiz | ?? ?? (emu8086: 00 00) |
k EQU 10 | sabit | yer kaplamaz |
Adres: LEA BX, x / MOV BX, OFFSET x. Değer: MOV AL, x. Boyut değiştirme: word ptr, byte ptr.
Özet
Özet
? ilk değersiz.a[i] bayt uzaklığıdır; DUP ile tekrar; DW dizisinde indis 2 × i.Özet
Alıştırmalar
x DB 5, 6·y DW 0ABCDh·z DB 'OK'tanımları 0200h'den başlıyorsa her baytın adresi ve değeri?tablo DW 10 DUP(?)kaç bayt kaplar? 7. elemanın (indis 6) bağıl uzaklığı nedir?- Önceki sorudaki
yiçinMOV AL, BYTE PTR yveMOV AL, BYTE PTR y+1sonrası AL? LEA SI, a[BX]ileMOV SI, OFFSET aarasındaki fark nedir?- İki DW değişkenin toplamını üçüncüsüne yazan, toplamda taşma olursa (CF = 1)
tasma DB 1yapan kodu yazın. dd 0FFFFFFFFhdeğerine 1 eklemek için DX:AX'te hangi komut çifti gerekir?
Cevaplar
- 0200: 05, 0201: 06, 0202: CD, 0203: AB, 0204: 4F ('O'), 0205: 4B ('K').
- 20 bayt; uzaklık 6 × 2 = 12 = 0Ch.
- CDh ve ABh.
- LEA, a + BX'i çalışma anında hesaplar; OFFSET yalnızca a'nın sabit adresidir.
MOV AX,v1·ADD AX,v2·MOV v3,AX·JNC son·MOV tasma,1·son:ADD AX,1·ADC DX,0(eldeyi yüksek sözcüğe taşır).
Özet
Kaynaklar
- emu8086 belgeleri, 8086 assembler tutorial for beginners, bölüm 3: variables (DB, DW, DUP, LEA, OFFSET, EQU).
- Barry B. Brey, The Intel Microprocessors, 8. baskı, Pearson.
- Kip R. Irvine, Assembly Language for x86 Processors, Pearson (veri tanımlama direktifleri).
- Microsoft MASM 6.1 Programmer's Guide: DB/DW/DD, DUP, EQU, OFFSET.