|
Stack Memory (Yığın Hafıza Bölgesi) |
|
Gönderiliyor lütfen bekleyin... |
|
|
Bu makalede stack
(yığın) hafıza bölgesini anlatmaya çalışacağım.
Stack memory geçici değerlerin saklandığı bir hafıza alanıdır. Mikroişlemci SS:SP
kaydedicileri ile bu hafıza alanına erişir. SS stack alanının segment adresini
tutarken SP bu alandaki offsetleri işaret eder. Stack hafıza alanını kullanmama
diye bir lüksümüz yok, bu makaleye kadar stack memory ile ilgili hiç bir komut
yazmasakta, bu hafıza alanını yadığımız tüm programlar kullandı.
Bununla beraber
stack memoryyi kendi isteklerimiz doğrultusunda da kullanabiliriz. Bunun için
bir çok komut mevcuttur. PUSH, POP, CALL, RET bunlardan bazıları ve bu
makalede anlatılacaklar arasındadır.
LIFO
Mikroişlemci stack memoryyi diğer hafıza alanlarını adreslerken kullandığı
yöntemden biraz daha farklı adresler. Öncelikle stack hafıza alanına yüklenen
bilgiler LIFO (Last In First Out) yani ilk giren son çıkar yada ilk yüklenen
bilgi en son alınır düzenine göre sıralanırlar.
Şekil 1 -
Stack (Yığın) hafıza.
Yukarıdaki şekilde
kırmızı bloğu stack memory olarak düşünebilirsiniz. BU alanın büyüklüğünü kod
yazarken .stack talimatı ile belirliyoruz, .stack 32, .stack 100h gibi. Geçici
verilerinizi saklamak için ne kadar alana ihtiyacınız varsa o kadar stack tahsis
edebilirsiniz.
Yine yukarıdaki
şekilde orijinal SP yığın boşken SP kaydedicisinin aldığı değerdir. Mesela
.stack 32 diye direktif verdiyseniz SP=0020h ı gösterir. Yığına veri itildikçe
SPnin değeri azalır, bu değerler yığından çekildikçe SP artar. x86 mimarisinde
yığın hafızaya 16 bitlik çalışma modunda 16 bitlik değerler, 32 bitlik çalışma
modunda ise 32 bitlik değerler saklayabilirsiniz.
PUSH ve POP
komutları
Stack memoryde
verilerinizi saklamak için kullanılan komutlardır. Stackta saklanan veriler
veya adres bilgileri için genelde "stacka itilen" kelimeleri kullanılır.
Stacktan geri alınan veriler içinse "stacktan çekilen" kelimesi kullanılır.
Özetle PUSH komutu stacka bir veriyi itmek için, POP ise verileri çekmek için
kullanılır.
Yığın hafıza alanını
etkileyen komutların genel kullanım formatları aşağıdaki gibidir;
push reg16
pop reg16
push reg32
(**)
pop reg32
(**)
push segreg
pop segreg
(CS hariç)
push mem
pop mem
push imm
(*)
pusha
(*)
popa
(*)
pushad
(**)
popad
(**)
pushf
popf
pushfd
(**)
popfd
(**)
(*)- Sadece 80286 ve sonrası işlemcilerde.
(**)- Sadece 80386 ve sonrası işlemcilerde.
En çok kullanılan
komutlar PUSH ve POP komutlarıdır. PUSHA ve PUSHAD tüm kaydedicileri yığında
saklamak amacıyla kullanılır, POPA ve POPAD ise saklanan bu kaydedicileri geri
almak için kullanılır. PUSHF, PUSHFD bayrak kaydedicisini saklamak POPF ve POPFD
ise bunları geri almak için kullanılır. Peki neden kaydedicilerin içeriğini
saklamak durumunda kalalım?
Programcıların
programlarını düz mantıkla yazmadığını biliyorsunuz, modüler programlama
teknikleri kullanılmazsa 30-40 satırdan sonra kaynak kod anlaşılmaz hale gelir.
Günümüzdeki programlar onbinlerce hatta milyonlarca komut satırından meydana
geliyor. Bunun için programı parçalara ayırmak, modüller hazırlamak şart. Yüksek
düzeyli programlama dillerinde kullanılan, sınıf, fonksiyon gibi kavramlar hep
bu amaç için türetilmiştir. Assembly dilinde CALL ve RET komutlarıda bunu
amaçlar. Hatta C dilinde ve birçok programlama dilinde fonksiyon çağrımlarının
assembly dilindeki tam karşılığı CALL komutudur. İster assembly dilinde call
komutunu kullanın isterseniz C dilinde bir fonksiyonu çağırın, dallanma işlemi
gerçekleşmeden önce geçici parametreler stackta saklanır.
CALL
ve RET Komutları
Bu komutları
anlatmadan önce assembly dilinde prosedür (procedure) mantığını kavramanız
lazım. Bir örnekle prosedürleri anlayalım.
Şekil 2 -
Prosedürler kullanılarak yapılmış bir kaynak kod..
Kaynak kodu buradan indirebilirsiniz.
Bu program bir önceki makaledeki string komutlarına örnek olmakla beraber biz
burada sadeve CALL ve RET komutlarını inceleyeceğiz. Program çalıştığında komut
isteminden bir yazının girilmesini ister, şayet yazıyı oluşturan karakterler
büyük harfli ise bunları küçük harfe dönüştürür.
Programda üç tane
prosedür bulunmakta ve ana prosedüre baktığınızda klasik kodlar olan segment
ayarlama ve dosa dönüşün dışında sadece CALL komutlarını görüyorsunuz. Ana
prosedürden 3 kere alt prosedürlere dallanma gerçekleşiyor. Her dallanma
sırasında geri dönüş adresi yığında saklanır. Alt prosedürlerden dönerkende ret
komutu ile bu adres geri yüklenir. Şayet dallanma bir başka segmente tapılıyorsa
CS ve IP, buradaki gibi aynı segment içindeyse sadece IP yani offset adresi
yığında saklanır. Offset ve segment adreslerinin 2 byte olduğunu düşünecek
olursanız bunun stackın yapısınada uygun olduğunu anlarsınız.
Yığın hafıza yada
stackın kullanılmadığı bir program yok gibidir. Tüm kesmeler (bunlarda bir çeşit
alt prosedür gibi düşünüle bilir) çağrılmadan önce, o anki CS ve IP ayrıca tüm
kaydediciler yığında saklanmak zorundadır. Aksi halde geri dönüş yapıldığında
alt prosedürün değiştirdiği kaydediciler ile karşılaşılır, hatta bu bile mümkün
olmaz çünkü mevcut CS ve IP saklanmadan geri dönüş söz konusu değildir.
Satırlar yığın
hafızayı anlatmakta biraz yetersiz kalıyor olabilir, bu konuyu anlamamış
olabilirsiniz diye sizlere birde video hazırladım. Yukarıdaki programın örnek
alındığı videoyu buradan download edip
izlediğinizde sanırım problem çözülecek :)
Şunları hatırlamakta
fayda var;
1- Programlar
genelde 3 adet hafıza alanından oluşur, bunlar code, data ve stack tır.
2- CPU bu alanlara adresleme yaparak erişir,
3- CPU CS ve IP kaydedicilerini kodlara erişip onları işlemek için,
4- DS, SI ve DIyı değişkenlere datalara erişmek için,
5- SS, SP ve BPyi yığın hafıza alanına erişmek ve biçimlendirmek için
kullanılır.
Örnek
programımızdaki ana prosedür dışındada CALL komutunu kullanabilirsiniz, alt
prosedürleri istediğiniz kadar çağırabilirsiniz. Fakat bir prosedür içinden
kendini çağırırken dikkatli olmalısınız, yazacağınız kodlarla programın sonsuz
döngüye girmesini engellemezseniz, "memory overflow" hatasından önce "stack
overflow" hatasını alırsınız.
Bu makaleyi iyice
anlamak için mutlaka videoyu izleyin ve bu örnek programın kaynak kodlarını
kendiniz derleyip çalıştırın ve bu programa başka prosedürler ekleyip onları
başka prosedürlerden yada ana prosedürden çağırarak programı inceleyin. İyi
çalışmalar... :)
Makale:
Stack Memory (Yığın Hafıza Bölgesi) Assembly ve X86 Programlama Eren Erener
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|