Bölüm 8: Yığın
Giriş
Öğrenme Çıktıları
8086 yığınının SS:SP ile nasıl adreslendiğini ve aşağı doğru büyüdüğünü açıklamak.
Geçerli işlenen türlerini bilmek ve her komutta SP'nin nasıl değiştiğini adım adım izlemek.
Yığını yazmaç değerlerini korumak, geri yüklemek ve takas etmek için doğru sırayla kullanmak.
Dönüş adresinin ve bayrakların yığında nasıl saklandığını, parametrelerin BP ile nasıl okunduğunu göstermek.
Dengesiz PUSH/POP, taşma ve yanlış sıralama hatalarını tanımak ve önlemek.
Programları tek adım çalıştırırken yazmaç ve yığın pencerelerini yorumlamak.
Yığın Kavramı
Yığın (Stack)
- Yığın, geçici verileri saklamak için ayrılmış bir bellek alanıdır.
CALLkomutu prosedürün dönüş adresini yığına koyar;RETbu değeri yığından alır ve o adrese döner.INTbir kesmeyi çağırdığında benzer bir işlem olur: bayrak (durum) yazmacı, kod kesimi (CS) ve bağıl konum (IP) yığına saklanır;IRETile kesmeden dönülür.PUSH: 16 bitlik bir değeri yığına koyar.POP: 16 bitlik bir değeri yığından alır.
PUSH AL geçersizdir.Yığın Kavramı
LIFO Algoritması
- LIFO, Last In First Out (son giren ilk çıkar) ifadesinin kısaltmasıdır.
- Yığına eklenen son öğe, yığından çıkan ilk öğe olur.
- Yığına konan değerler sırasıyla 1, 2, 3, 4, 5 ise ilk alınan değer 5 olur; ardından 4, 3, 2 ve en son 1 alınır.
Başlangıçta yığın boş.
PUSH 1: 1 yığının üstüne konur.
PUSH 2: 2 yığının üstüne konur.
PUSH 3: 3 yığının üstüne konur.
PUSH 4: 4 yığının üstüne konur.
PUSH 5: 5 yığının üstüne konur.
POP → 5 çıkar. Çıkış sırası şimdiye kadar: 5
POP → 4 çıkar. Çıkış sırası şimdiye kadar: 5, 4
POP → 3 çıkar. Çıkış sırası şimdiye kadar: 5, 4, 3
POP → 2 çıkar. Çıkış sırası şimdiye kadar: 5, 4, 3, 2
POP → 1 çıkar. Çıkış sırası şimdiye kadar: 5, 4, 3, 2, 1
Yığın Kavramı
Yığın Belleği: SS ve SP
- Yığın belleği SS (Stack Segment, yığın kesimi) ve SP (Stack Pointer, yığın işaretçisi) yazmaçlarını kullanır.
- SS:SP her zaman yığının üstündeki (en son konan) word'ü gösterir.
- Başlangıç değerlerini genellikle işletim sistemi (yükleyici) belirler: .COM'da SS = CS, SP = FFFEh; .EXE'de başlıktaki değerler.
- BP de varsayılan olarak SS kesimini kullanır; yığındaki verilere erişmek için idealdir.
Yığın kesimi SS = 0700h (emu8086'da .COM programı için tüm kesim yazmaçları 0700h).
Kesim değeri 16 ile çarpılır (hex'te sağa bir 0 eklenir): 07000h.
Bağıl konum olarak yığın işaretçisi SP = FFFEh eklenir.
Yığının üstü fiziksel olarak 16FFEh adresindedir (20 bit).
Yığın Kavramı
Yığın Aşağı Doğru Büyür
- .COM programında kod, veri ve yığın aynı 64 KB kesimi paylaşır.
- Program 0100h'den yukarı doğru, yığın FFFEh'den aşağı doğru yerleşir; aradaki boş alan ikisine de yeter.
- Her PUSH SP'yi 2 azaltır, her POP 2 artırır.
- Çok fazla PUSH yapılırsa yığın kodun/verinin üzerine yazabilir: yığın taşması (stack overflow).
PUSH ve POP
PUSH Komutu
| Biçim | Geçerli işlenenler | Örnek |
|---|---|---|
PUSH REG | AX, BX, CX, DX, DI, SI, BP, SP | PUSH AX |
PUSH SREG | DS, ES, SS, CS | PUSH DS |
PUSH memory | [BX], [BX+SI+7], 16 bitlik değişken… | PUSH [BX], PUSH sayi |
PUSH immediate | 5, −24, 3Fh, 10001101b… | PUSH 3Fh |
PUSH immediate komutu 8086/8088'de yoktur; 80186 ile gelmiştir. emu8086 bunu kabul eder ama gerçek 8086 için MOV AX, 5 + PUSH AX yazılmalıdır.PUSH AL, PUSH byte_degisken hatalıdır. Bayraklar için ayrı komut vardır: PUSHF.Ayrıntı: 8086'da PUSH SP, SP azaltıldıktan sonraki değeri yığına yazar; 80286 ve sonrası azaltmadan önceki değeri yazar.
PUSH ve POP
POP Komutu
| Biçim | Geçerli işlenenler | Örnek |
|---|---|---|
POP REG | AX, BX, CX, DX, DI, SI, BP, SP | POP BX |
POP SREG | DS, ES, SS (CS hariç) | POP DS |
POP memory | [BX], [BX+SI+7], 16 bitlik değişken… | POP sonuc |
RETF, IRET, uzak JMP/CALL ile birlikte değişir.POP 5 anlamsızdır: alınan değer bir yere yazılmalıdır.POPF bayrak yazmacının tamamını yığından yükler.Yaygın deyim: PUSH CS + POP DS → DS'ye CS'nin değeri kopyalanır (kesim yazmaçları arasında doğrudan MOV yoktur).
PUSH ve POP
PUSH ve POP Nasıl Çalışır?
- SP yazmacından 2 çıkarılır.
- Kaynak değeri SS:SP adresine yazılır.
- SS:SP adresindeki değer hedefe yazılır.
- SP yazmacına 2 eklenir.
Sıra önemlidir: PUSH önce azaltır sonra yazar; POP önce okur sonra artırır. Böylece SP her an dolu olan en üst hücreyi gösterir.
Başlangıç: SP = FFFEh, AX = 1234h. (.COM'da FFFEh'de DOS'un koyduğu 0000h vardır.)
PUSH AX ① SP ← SP − 2 = FFFCh. Yeni üst hücre henüz yazılmadı.
② Kaynak değer SS:SP adresine yazılır: [FFFCh] ← 1234h.
POP BX ① SS:SP'deki değer hedefe yazılır: BX ← 1234h.
② SP ← SP + 2 = FFFEh. FFFCh'deki 1234h silinmez; yalnızca artık yığının dışında kalır (soluk).
PUSH ve POP
Yığında Bayt Sırası (Little-Endian)
- 8086 bir word'ü belleğe düşük bayt önce yazar:
PUSH AX(AX = 1234h) sonrası [FFFCh] = 34h, [FFFDh] = 12h. - emu8086'nın stack penceresi word'leri gösterir; memory penceresi baytları gösterir. İkisi aynı veriyi farklı biçimde sunar.
- SP her zaman çift bir değer olarak tutulmalıdır; tek adreste word erişimi 8086'da ek bir bellek döngüsü harcar.
PUSH ve POP
Ne Değişir, Ne Değişmez?
| Komut | SP | Bellek | Hedef | Bayraklar |
|---|---|---|---|---|
PUSH kaynak | −2 | [SS:SP] ← kaynak | — | değişmez |
POP hedef | +2 | okunur, silinmez | hedef ← [SS:SP] | değişmez |
PUSHF | −2 | [SS:SP] ← FLAGS | — | değişmez |
POPF | +2 | okunur | FLAGS ← [SS:SP] | hepsi yüklenir |
CALL (yakın) | −2 | [SS:SP] ← dönüş IP | IP ← hedef | değişmez |
RET (yakın) | +2 | okunur | IP ← [SS:SP] | değişmez |
INT n | −6 | FLAGS, CS, IP | CS:IP ← vektör | IF = TF = 0 |
IRET | +6 | okunur | IP, CS, FLAGS | hepsi yüklenir |
Bu yüzden bir karşılaştırmanın sonucunu (bayrakları) PUSH/POP arasında güvenle taşıyabilirsiniz; bayrağı saklamak gerekiyorsa PUSHF/POPF kullanılır.
Örnekler · Kodu adım adım çalıştır
İlk Örnek: PUSH AX / POP BX
emu8086 .COM başlangıcı: CS = DS = SS = ES = 0700h, IP = 0100h, SP = FFFEh.
MOV AX, 42: 42 onluk sayıdır → AX = 002Ah (42h değil!).
PUSH AX: SP = FFFEh − 2 = FFFCh; [FFFCh] ← 002Ah.
POP BX: BX ← [FFFCh] = 002Ah; SP tekrar FFFEh. Değer AX'ten BX'e yığın üzerinden kopyalandı.
RET: yığındaki 0000h alınır, IP = 0000h → PSP'deki INT 20h programı sonlandırır.
ORG 100h MOV AX, 42 ; AX'e 42 ata PUSH AX ; AX'i yığına koy POP BX ; yığından BX'e al RET ; işletim sistemine dön END
Örnekler · Kodu adım adım çalıştır
LIFO Sırası: 1, 2, 3 Girer → 3, 2, 1 Çıkar
Başlangıç: SP = FFFEh.
AX = 0001h.
PUSH: SP = FFFCh, [FFFCh] = 0001h.
AX = 0002h (AX'in eski değeri yığında güvende).
PUSH: SP = FFFAh, [FFFAh] = 0002h.
AX = 0003h.
PUSH: SP = FFF8h; yığında üç değer var.
POP BX → 3 (son giren ilk çıkar). SP = FFFAh.
POP BX → 2. SP = FFFCh.
POP BX → 1. SP = FFFEh; yığın başlangıç hâline döndü.
MOV AX, 1 ; AX'e 1 ata PUSH AX ; 1'i yığına koy MOV AX, 2 ; AX'e 2 ata PUSH AX ; 2'yi yığına koy MOV AX, 3 ; AX'e 3 ata PUSH AX ; 3'ü yığına koy POP BX ; BX ← 3 POP BX ; BX ← 2 POP BX ; BX ← 1
Örnekler · Kodu adım adım çalıştır
Bir Yazmacın Değerini Saklamak
Amaç: AX'i geçici olarak başka bir iş için kullanıp sonra eski değerine döndürmek.
AX = 1234h.
AX yığına saklandı: [FFFCh] = 1234h.
AX başka bir iş için kullanıldı: AX = 5678h.
POP AX: AX eski değerine döndü → 1234h.
RET: 0000h'ye dönüş, program biter.
ORG 100h MOV AX, 1234h PUSH AX ; AX'in değerini sakla MOV AX, 5678h ; AX'i değiştir POP AX ; eski değeri geri yükle RET END
Prosedürlerin girişinde kullandıkları yazmaçları PUSH, çıkışta POP etmesi bu desenin aynısıdır.
Örnekler · Kodu adım adım çalıştır
Yığın ile İki Yazmacı Takas Etmek
emu8086'da yükleme sonrası: CX = 000Bh (programın bayt sayısı: 3+3+1+1+1+1+1 = 11), SP = FFFEh.
AX = 1212h.
BX = 3434h.
PUSH AX: [FFFCh] = 1212h, SP = FFFCh.
PUSH BX: [FFFAh] = 3434h, SP = FFFAh.
POP AX: üstteki 3434h AX'e gelir.
POP BX: sıradaki 1212h BX'e gelir. Takas tamam!
RET: program sonu.
ORG 100h MOV AX, 1212h ; AX ← 1212h MOV BX, 3434h ; BX ← 3434h PUSH AX ; AX'i yığına koy PUSH BX ; BX'i yığına koy POP AX ; AX ← BX'in eski değeri POP BX ; BX ← AX'in eski değeri RET END
Aynı sırayla POP etseydik (önce BX) değerler yerinde kalırdı. Takasın sırrı LIFO'dur.
Örnekler · Kodu adım adım çalıştır
Yığın Kullanımı: Üç Yazmaç
.BIN olarak yüklendi: CS = SS = 0100h, IP = 0000h, SP = FFFEh. Yığın başlangıçta boş.
AX = 0002h.
BX = 0004h.
CX = 0008h.
push ax: SP = FFFCh, [FFFCh] = 0002h.
push bx: SP = FFFAh, [FFFAh] = 0004h.
push cx: SP = FFF8h, [FFF8h] = 0008h.
pop ax: AX ← 0008h (üstteki).
pop bx: BX ← 0004h (ortadaki; değişmedi).
pop cx: CX ← 0002h. Sonuç: AX ile CX'in değerleri yer değiştirdi.
mov ax, 2 mov bx, 4 mov cx, 8 push ax push bx push cx pop ax pop bx pop cx
Kaynak: emu8086 ile tek adım çalıştırma (single step). Yığın penceresi SS:SP çevresini gösterir.
Örnekler · Kodu adım adım çalıştır
Yığınla Diziyi Ters Çevirme
metin = 'ABC' bellekte 0117h adresinde. Hedef: ekrana ters sırada yazmak.
SI = 0117h (metin dizisinin adresi).
Döngü sayacı CX = 3.
AL ← [SI] = 'A' (41h).
PUSH AX: 'A' yığına (AH = 00h ile birlikte, 0041h).
SI = 0118h: sonraki karakter.
LOOP: CX = 2 → geri dön.
AL ← [SI] = 'B' (42h).
PUSH AX: 'B' yığına (AH = 00h ile birlikte, 0042h).
SI = 0119h: sonraki karakter.
LOOP: CX = 1 → geri dön.
AL ← [SI] = 'C' (43h).
PUSH AX: 'C' yığına (AH = 00h ile birlikte, 0043h).
SI = 011Ah: sonraki karakter.
LOOP: CX = 0 → döngü biter.
İkinci döngü için CX = 3.
POP DX: DX = 0043h → DL = 'C' (son giren ilk çıkar).
AH = 02h: DOS karakter yazma işlevi.
INT 21h: ekrana C yazılır.
LOOP: CX = 2 → geri dön.
POP DX: DX = 0042h → DL = 'B' (son giren ilk çıkar).
AH = 02h: DOS karakter yazma işlevi.
INT 21h: ekrana B yazılır.
LOOP: CX = 1 → geri dön.
POP DX: DX = 0041h → DL = 'A' (son giren ilk çıkar).
AH = 02h: DOS karakter yazma işlevi.
INT 21h: ekrana A yazılır.
LOOP: CX = 0 → döngü biter.
Ekranda CBA: dizi yığın sayesinde ters çevrildi. RET ile program biter.
ORG 100h MOV SI, OFFSET metin MOV CX, 3 koy: MOV AL, [SI] PUSH AX ; karakteri sakla INC SI LOOP koy MOV CX, 3 yaz: POP DX ; DL = karakter MOV AH, 2 INT 21h ; DL'yi ekrana yaz LOOP yaz RET metin DB 'ABC' ; 0117h
Örnekler
Tahmin Et: Yazmaçlar Ne Olur?
Kod çalıştıktan sonra AX, BX, CX ve SP ne olur? (Başlangıç: SP = FFFEh)
MOV AX, 1111h MOV BX, 2222h MOV CX, 3333h PUSH AX PUSH BX PUSH CX POP AX POP CX PUSH AX POP BX POP BX
Önce kendiniz düşünün, sonra › ile adım adım açın.
PUSH'lardan sonra yığın (üstten alta): 3333h, 2222h, 1111h; SP = FFF8h.
POP AX → AX = 3333h; POP CX → CX = 2222h; SP = FFFCh.
PUSH AX (3333h), POP BX → BX = 3333h; ardından POP BX → BX = 1111h.
Sonuç: AX = 3333h, BX = 1111h, CX = 2222h, SP = FFFEh (4 PUSH, 4 POP → dengeli).
Örnekler
Takas Yöntemlerinin Karşılaştırması
PUSH AX PUSH BX POP AX POP BX4 bayt · 4 bellek erişimi. Her yazmaç çifti ve kesim yazmaçları için çalışır.
MOV CX, AX MOV AX, BX MOV BX, CX6 bayt · bellek erişimi yok, ama CX'in değeri bozulur.
XCHG AX, BX1 bayt (93h) · en kısa ve en hızlı yol. Kesim yazmaçlarıyla kullanılamaz.
PUSH DS / POP ES).Örnekler
Etkileşimli Yığın Simülatörü
Yazmaçlar (hex, düzenlenebilir)
Çalıştırılan komutlar
Deneyin: AX ve BX'i takas edin; sonra yığın boşken POP yapmayı deneyin (gerçek 8086 bunu engellemez, SP yine 2 artar).
CALL / RET
CALL ve RET
CALL hedef(yakın): bir sonraki komutun adresini (dönüş IP'si) yığına koyar, sonra IP ← hedef.RET: yığının üstündeki word'ü IP'ye alır; program CALL'dan sonraki komuttan devam eder.- Uzak (far) CALL önce CS'yi sonra IP'yi koyar;
RETFikisini ters sırada alır. RET n: dönüşten sonra SP'ye ayrıca n ekler; yığına konmuş parametreleri temizlemek için kullanılır.- İç içe çağrılarda her CALL yığına yeni bir dönüş adresi ekler; RET'ler bunları ters sırada tüketir (LIFO).
| Komut | Yığına | SP |
|---|---|---|
CALL near | IP | −2 |
CALL far | CS, IP | −4 |
RET | ← IP | +2 |
RETF | ← IP, CS | +4 |
RET 4 | ← IP | +2+4 |
CALL / RET · Kodu adım adım çalıştır
CALL / RET Adım Adım
Başlangıç: IP = 0100h, SP = FFFEh.
AX = 0005h; IP bir sonraki komutu (0103h) gösterir.
CALL KARE: dönüş adresi 0106h (CALL 3 bayt: 0103h + 3) yığına konur; IP = 0107h.
MUL AX: DX:AX = 5 × 5 = 0019h (25). DX = 0000h.
RET: IP ← [FFFCh] = 0106h; SP = FFFEh. Ana programa dönüldü.
Ana programın RET'i 0000h'yi alır → program biter.
ORG 100h ; 0100h MOV AX, 5 ; 0100h CALL KARE ; 0103h RET ; 0106h KARE PROC MUL AX ; 0107h DX:AX = AX*AX RET ; 0109h KARE ENDP
CALL / RET
Prosedürde Yazmaç Koruma
TOPLA_N PROC ; AX = 1+2+...+CX PUSH BX ; BX'i koru PUSH CX ; CX'i koru XOR AX, AX MOV BX, 1 dongu: ADD AX, BX INC BX LOOP dongu POP CX ; ters sıra! POP BX RET TOPLA_N ENDP
- Prosedür, kullandığı yazmaçları girişte yığına koyar, çıkışta ters sırada geri alır. Çağıran taraf yazmaçlarının bozulmayacağını bilir.
- Dönüş adresi bu PUSH'ların altında kalır; RET'e gelindiğinde tüm PUSH'lar POP edilmiş olmalıdır.
- Sonucu döndüren yazmaç (burada AX) korunmaz; aksi hâlde sonuç kaybolur.
CALL / RET · Kodu adım adım çalıştır
Yığınla Parametre Geçirme (BP ile)
Çağıran, parametreleri yığına koyar; prosedür bunları BP üzerinden okur.
AX = 7.
1. parametre yığında: [FFFCh] = 0007h.
AX = 3.
2. parametre: [FFFAh] = 0003h.
CALL: dönüş adresi 010Bh → [FFF8h]. IP = 010Fh.
Eski BP saklanır: [FFF6h] = 0000h.
MOV BP, SP: BP = FFF6h sabit bir çerçeve noktası olur.
[BP+6] = [FFFCh] = 0007h → AX = 7.
[BP+4] = [FFFAh] = 0003h → AX = 000Ah.
BP eski değerine döner; SP = FFF8h (dönüş adresi üstte).
RET: IP = 010Bh, SP = FFFAh.
ADD SP, 4: iki parametre atılır, SP = FFFEh. Yığın dengelendi.
Program biter.
ORG 100h MOV AX, 7 PUSH AX ; 1. parametre MOV AX, 3 PUSH AX ; 2. parametre CALL TOPLA ADD SP, 4 ; parametreleri at RET TOPLA PROC PUSH BP MOV BP, SP MOV AX, [BP+6] ; 1. parametre ADD AX, [BP+4] ; 2. parametre POP BP RET TOPLA ENDP
[BP+0] = eski BP, [BP+2] = dönüş adresi, [BP+4] = son konan parametre. ADD SP, 4 yerine prosedürde RET 4 de yazılabilirdi.
CALL / RET
Yığın Çerçevesi ve Yerel Değişkenler
PUSH BP MOV BP, SP SUB SP, 4 ; yerel alan MOV [BP-2], AX ; yerel 1 ... MOV SP, BP ; yerelleri at POP BP RET 4 ; 2 parametreyi at
SUB SP, 4yığında iki word'lük yerel alan açar: [BP−2], [BP−4].MOV SP, BPyerel alanı tek komutla geri verir.- Parametreler pozitif, yereller negatif BP ofsetindedir.
INT / IRET
INT ve IRET: Yığında Üç Word
0700:0103h adresindeki INT 21h (2 bayt) çalışacak. FLAGS = 0202h (IF = 1), SP = FFFEh.
① FLAGS yığına: SP = FFFCh, [FFFCh] = 0202h.
② CS yığına: SP = FFFAh, [FFFAh] = 0700h.
③ Dönüş IP'si yığına: SP = FFF8h, [FFF8h] = 0105h (INT'ten sonraki komut). Ardından IF = TF = 0.
④ Yeni CS:IP, vektör tablosundaki 21h × 4 = 84h adresinden okunur: IP ← [0000:0084h], CS ← [0000:0086h]. Kesme yordamı çalışır.
⑤ Yordamın sonundaki IRET: IP, CS ve FLAGS ters sırada geri alınır; SP = FFFEh. Program 0700:0105h'den devam eder.
Donanım kesmelerinde (ör. zamanlayıcı, klavye) CPU aynı üç word'ü kendisi yığına koyar. Bu yüzden kesme yordamları kullandıkları yazmaçları mutlaka PUSH/POP ile korumalıdır.
INT / IRET · Kodu adım adım çalıştır
Bayrakları Saklamak: PUSHF / POPF
Başlangıç: bayraklar temiz (IF = 1).
AX = FFFFh.
FFFFh + 1 = 1 0000h → AX = 0000h, CF = 1, ZF = 1.
PUSHF: FLAGS word'ü (F257h: CF, PF, AF, ZF, IF ve 8086'nın hep 1 olan bitleri) yığına.
BX = 5.
5 + 3 = 8 → CF = 0, ZF = 0. Önceki sonuç bayrakları kayboldu…
…POPF ile geri geldi: CF = 1, ZF = 1.
Program biter.
ORG 100h MOV AX, 0FFFFh ADD AX, 1 ; CF=1, ZF=1 PUSHF ; bayrakları sakla MOV BX, 5 ADD BX, 3 ; CF=0, ZF=0 POPF ; bayraklar geri RET
Kesme yordamları bayrakları kendileri saklamaz; INT bunu otomatik yapar. Normal kodda bir sonucu korumak için PUSHF/POPF gerekir.
Yığın Güvenliği
Yığın Güvenliği
- PUSH ve POP komutları programın çalışması süresince geçici verileri saklar.
- Yığının bütünlüğü eşit sayıda PUSH ve POP ile korunmalıdır (her yolda, her dalda!).
- Eşit sayıda PUSH ve POP yapılmazsa yığın bozulur; işletim sistemine geri dönüş yapılamayabilir.
RETyığının üstünde bir dönüş adresi bekler. .COM programında DOS, yığına başlangıçta 0000h koyar: RET ile CS:0000h'ye (PSP) gidilir; orada duranINT 20hprogramı sonlandırır.
Yığın Güvenliği · Kodu adım adım çalıştır
Hata Örneği: Dengesiz PUSH
Program sonunda RET ile DOS'a dönmek istiyoruz.
AX = 1234h.
AX yığına kondu ama hiç POP edilmeyecek.
RET üstteki word'ü dönüş adresi sanar: IP = 1234h. CPU 0700:1234h'deki rastgele baytları komut olarak çalıştırmaya başlar → program çöker ya da donar.
ORG 100h MOV AX, 1234h PUSH AX ; POP unutuldu! RET ; IP ← ?
Düzeltme: RET'ten önce POP AX ekleyin ya da hiç PUSH etmeyin. Her dalın (JMP/Jcc) PUSH/POP sayısını ayrı ayrı sayın.
Yığın Güvenliği
Yığın Taşması ve Alt Taşma
- Sonsuz özyineleme, döngü içinde POP'suz PUSH.
- SP küçüldükçe yığın aşağı inip kod ve verinin üzerine yazar (.COM'da aynı kesim).
- 8086 bunu denetlemez; hata yoktur, yalnızca bozulma vardır.
- PUSH edilmemiş değeri POP etmek.
- SP = FFFEh iken POP → SP = 0000h (16 bitte sarar); sonraki PUSH FFFEh'ye yazar.
- Okunan değer çöptür (ya da DOS'un 0000h'si).
.STACK 100h gibi bir yönergeyle ayrı ve yeterli bir yığın kesimi ayırın.Yığın Güvenliği
İyi Uygulamalar
MOV BP, SP kullanın.Yığın Güvenliği
emu8086 ile Yığını İzlemek
B8 12 12 = MOV AX, 1212h. Little-endian burada görülür.Özet
Özet
| Kavram | Hatırlanacak nokta |
|---|---|
| Adres | Yığının üstü = SS:SP; fiziksel adres SS × 16 + SP. |
| Büyüme yönü | Aşağı: PUSH SP −= 2, POP SP += 2. Birim her zaman word. |
| PUSH / POP | REG, SREG, bellek (POP CS yok). PUSH sabit yalnızca 80186+ / emu8086. |
| LIFO | Değerler ters sırada döner → saklarken ayna sırası, takasta aynı sıra. |
| CALL / RET | Dönüş adresi = CALL'dan sonraki komutun adresi; RET n parametreleri temizler. |
| INT / IRET | FLAGS, CS, IP (6 bayt) otomatik saklanır; vektör adresi n × 4. |
| Parametreler | PUSH ile verilir, [BP+4], [BP+6]… ile okunur. |
| Güvenlik | Eşit sayıda PUSH/POP; .COM'da son RET DOS'un 0000h'sini alır. |
Özet
Alıştırmalar
- SS = 2000h, SP = 0100h iken
PUSH AXsonrası yazılan baytların fiziksel adresleri nedir? MOV AX,1 / MOV BX,2 / MOV CX,3 / PUSH AX / PUSH BX / PUSH CX / POP BX / POP CX / POP AXsonunda AX, BX, CX?- Yalnızca PUSH/POP ile DS'nin değerini ES'ye kopyalayın.
- Bir prosedür girişte
PUSH BX,PUSH CXyapıp çıkışta yalnızcaPOP BXyaparsa ne olur? - 0700:0200h'deki
CALL 0300h(3 bayt) yürütülürken SP = FFF0h ise sonrasında SP ve [SS:SP]? - Üç parametreli bir prosedürde (PUSH BP / MOV BP,SP sonrası) ilk konan parametre hangi adrestedir?
Cevaplar
- SP = 00FEh → 20000h + 00FEh = 200FEh (AL) ve 200FFh (AH).
- AX = 1, BX = 3, CX = 2: AX yerinde kalır, BX ile CX takas edilir.
PUSH DS+POP ES.- RET, CX'in eski değerini dönüş adresi sanır → yanlış adrese atlar.
- SP = FFEEh, [FFEEh] = 0203h.
- [BP+8] (sonra [BP+6], en son konan [BP+4]).
Özet
Kaynaklar
- Intel, The 8086 Family User's Manual, 1979 — PUSH, POP, CALL, RET, INT, IRET komut tanımları.
- B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009 — Bölüm 4 ve 6.
- K. R. Irvine, Assembly Language for x86 Processors, 7. baskı, Pearson, 2014 — yığın işlemleri ve prosedürler.
- emu8086 yardım belgeleri: 8086 Assembler Tutorial, Part 9 (The Stack).