Bölüm 4: 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; bölüm sonunda ele alınır.
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, onlu, onaltılı, 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.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) programı bitirir. 0108h'den sonrası veridir, komut olarak yürütülmez.
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 yürütülebilir 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.
- İş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
.COM ve .EXE
| .COM | .EXE | |
|---|---|---|
| Başlangıç | ORG 100h, IP = 0100h | giriş noktası END start ile belirtilir |
| Kesimler | tek kesim: CS = DS = ES = SS | ayrı kod, veri ve yığın kesimleri |
| Boyut | en fazla 64 KB (PSP dahil) | 64 KB'tan büyük olabilir |
| DS | hazır, değişkenlere doğrudan erişilir | programın başında MOV AX, @data · MOV DS, AX |
| Dosya | yalnızca makine kodu (başlık yok) | yeniden yerleştirme (relocation) bilgili başlık |
Bu dersteki örneklerin çoğu emu8086 .COM şablonuyla yazılmıştır.
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! w DW 1111h, 2222h, 3333h
Diziler
Tanımdan Bayta
Bir DB / DW / DD satırı yazın: sayılar (onlu, h, b, o), 'metin' (yalnız DB), ? ve n DUP(…) desteklenir. Hücre üstü: değişkenin başından bayt uzaklığı.
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:MOV BX, num(BB 0D 01); num, değişkenin bağıl konumunun 16 bitlik değeridir. - MASM/TASM
LEA BX, VAR1'i gerçek LEA komutu olarak kodlar (8D 1E 0D 01, 4 bayt); sonuç yine aynıdır. - 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.
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 (dolaysız) | AL ← [k] (bellekten) |
| Değiştirilebilir mi? | hayır | evet: MOV k, 7 |
Ö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 ; (kaynakta eksikti) 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 ; (kaynakta eksikti) value1 DW 10 value2 DW 5 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 yoktu; CPU 0A 00 05 00… baytlarını komut olarak yürütürdü. Düzeltme: RET (ya da başta jmp start).MOV AX, value1 gereksizdir; AX zaten value1'dir. Etiket doğrudan store_max'e atlayabilir.Koşullu atlamalar “Akış Kontrolü” bölümünde ayrıntılı işlenir.
Örnek Programlar
Double Word 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 data dd 12345678h
Ö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 | double word | 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.