Stack bölgesi kullanımı hakkında sorular

Başlatan camby, 04 Aralık 2012, 11:07:34

camby

C programlamada stack alanı diye bir alan kullanılıyor,  anladığım kadarıyla bu stack alanı derleyici tarafından yazılımsal olarak oluşturuluyor. Donanımsal stack ise , fonksiyon dönüş adreslerini tutuluyor sadece ve FIFO özellikte bir alan.

Bir fonksiyona giderken parametreler ve tüm local değişkenler stack alanında yer işgal ediyorlar , o fonksiyon çalıştığı sürece tabi.

Herhangi bir fonksiyon esnasında kesme gelse ve bu kesme içinde tekrar aynı fonksiyona gidilse , stack alanda yeni değişkenler oluşturulur mu ? Kesmeye gitmeden önceki duruma ait datalar bozulur mu ?

Örnek olarak delay_ms fonksiyonu olsun ve bu fonksiyonun girişte 2 parametresi ve 2 de local değişkeni olsun. Fonksiyon  işletilirken ve kesme gelsin , kesme programında da delay_ms olsun. Kesme içerisindeki delay_ms işletilirken , stack alanında delay_ms fonksiyonu için toplamda 8 veri alanı mı ayrılmış olacaktır ? Yoksa önceki değerlerin üstüne mi yazılacaktır.

ASM kodda bu şekilde bir algoritma oluşturmak istiyorum. Ana program içerisinde işlettiğim fonksiyonlar kesme programı içerisinde tekrardan çağırılabiliyor ve döndüğümde önceki datalar kayboluyor.

Kabaca kesme geldiğinde tekrardan kullanılma ihtimali olan bütün değişkenleri ( WREG ve STATUS gibi ) yedekleyebilirim ancak bu şekilde yapmak  istemiyorum.

Nasıl bir algoritma kurmam gerekir ? Derleyiciler Yazılımsal stack işini nasıl yapıyorlar , yapısının FIFO olması gerekir mi , fikir verebilir misiniz ?

MT

Alıntı yapılan: camby - 04 Aralık 2012, 11:07:34
C programlamada stack alanı diye bir alan kullanılıyor,  anladığım kadarıyla bu stack alanı derleyici tarafından yazılımsal olarak oluşturuluyor. Donanımsal stack ise , fonksiyon dönüş adreslerini tutuluyor sadece ve FIFO özellikte bir alan.

Bir fonksiyona giderken parametreler ve tüm local değişkenler stack alanında yer işgal ediyorlar , o fonksiyon çalıştığı sürece tabi.

Herhangi bir fonksiyon esnasında kesme gelse ve bu kesme içinde tekrar aynı fonksiyona gidilse , stack alanda yeni değişkenler oluşturulur mu ? Kesmeye gitmeden önceki duruma ait datalar bozulur mu ?

Örnek olarak delay_ms fonksiyonu olsun ve bu fonksiyonun girişte 2 parametresi ve 2 de local değişkeni olsun. Fonksiyon  işletilirken ve kesme gelsin , kesme programında da delay_ms olsun. Kesme içerisindeki delay_ms işletilirken , stack alanında delay_ms fonksiyonu için toplamda 8 veri alanı mı ayrılmış olacaktır ? Yoksa önceki değerlerin üstüne mi yazılacaktır.




Konuyu hortlattım ama sorulara cevap gelmemiş benimde merak ettiğim konular umarım bu sorulara artık cevap verilebilir. Eksiklerimi gidermek istiyorum. 

Stack'te kaplanan alan mimariye göre değişiklik gösterir mi. Yazılımı yazıp geçiyoruz ama eksik kaldığım bazı temel konular var.

ek olarak şöyle temel bi sorum var.

void fonk1(void)
{
    degiskeler;
}


void fonk2(void)
{
    degiskenler2;
    fonk1();
}


void fonk3(void)
{
   degiskenler3;
   fonk2();
}

bu şekilde fonksiyonlar oluşturdum diyelim.

fonk3()'ü çağırdığımda stack'te kaplanan alan nasıl hesaplanıyor. fonk3() içinde fon2() var onunda kendi içinde çağırdığı değişkenler ve fonksiyon var sonuçta o anda oluşturuluyor hepsi. Stack'te kaplanan alan bu durumda o fonksiyon ve içinde barındırdığı değişkenler + çağırdığı fonksiyonlar... diye mi yer kaplıyor. Böyle olmaması gerektiğini düşünüyorum ama doğrusunu öğrenmek istiyorum. 



Tagli

#2
Konuyu yeni görüyorum. Soru eski ama bildiğim kadarıyla cevap vermeye çalışayım.

Alıntı YapDonanımsal stack ise , fonksiyon dönüş adreslerini tutuluyor sadece ve FIFO özellikte bir alan.
Aslında donanımsal yığın olayını sadece 8 bit PIC'lerde gördüm. Normalde yığın için bir donanım desteği olur (PUSH, POP komutları ve donanımsal yığın işaretçisi gibi) ama yığın alanı bellek içinde normal olarak erişilebilen bir yerdir. Derleyici de bunu kullanır zaten. Gelişmiş mimarilerde birden fazla yığın olabilir. Örneğin masaüstü bilgisayarlarda her process'in kendi ayrı yığını olur. Hatta galiba her thread'in de vardı, o kısımdan çok emin değilim.

Alıntı YapHerhangi bir fonksiyon esnasında kesme gelse ve bu kesme içinde tekrar aynı fonksiyona gidilse , stack alanda yeni değişkenler oluşturulur mu ? Kesmeye gitmeden önceki duruma ait datalar bozulur mu ?
Fonksiyonlarda thread safety denen bir olay var. Bir fonksiyonun farklı thread'ler tarafından aynı anda çağrılıp çağrılamayacağını ifade eder. Mikrodenetleyicilerdeki kesmeler de aslında bir çeşit thread gibi. Bilgisayarlarda bu nasıl çözülüyor bilmiyorum, ama XC8'in yaklaşımını biliyorum mesela. XC8, bir fonksiyon hem ana kodda hem kesmede kullanılırsa aslında onun bir kopyasını oluşturuyor arkada gizlice. Yani aynı fonksiyon hem normal kodda hem kesmede çağrılmamış oluyor.
Normalde aynı anda çağrılma state machine mantığı ile bir global değişkene erişilmiyorsa, yani çağrılmalar sırasında sıfırlanmayacak bir değişken yoksa sorun olmaz. Fonksiyon içinde tanımlanan statik değişkenler de bunun bir örneği. Fonksiyon her çağrıldığında kendi değişkenleri için yığında yeniden her açılır. Recursion denen olay da zaten bu şekilde mümkün oluyor. Ama dediğim gibi, global veya statik değişken olması durumunda işler karışır. Bu değişkenler zaten yığında saklanmazlar ve fonksiyon birden fazla kez üst üste çağrılsa bile sadece tek kopyaları olur bellekte.

singleiron, aslında yukarıda verdiğim cevaplar senin sorunla da ilgili. Bir fonksiyon her çağrıldığında, içindeki statik olmayan değişkenler yığın üzerinde oluşturulur. fonk3 çağrılınca degiskenler3 için yer açılır. Sonra fonk2 çağrılınca yığın üstüne degiskenler2 biner ve bu böyle gider. Bu şekilde kabaca yığın kullanımını hesaplayabilirsin. Ancak işin içine resursion, yani kodların kendi kendini çağırması olayı (doğrudan ya da dolaylı) girerse iş karışır. Recursion, bir yılanın kendi kuyruğunu yemesi gibi birşey...  :)

Gökçe Tağlıoğlu

MT

#3
@Tagli Sonuç olarak anladığımız kadarıyla Stackoverflow sıkıntımız varsa değişkenleri olabildiğince global tanımlamalıyız. Globalide olabildiğince döndürüp dündürüp kullanmalıyız. (Stm8Lxx kullanıyorum malesef max 512 Byte 'lık stack'im var.)

resursion etkilerinide bi araştırayım. Hocam çok sağolun aydınlandım resmen.

Peki bu durumlar mimariye göre değişir mi?

Tagli

#4
Bildiğim kadarıyla çoğu mimaride POP PUSH ve yığın işaretçisi gibi donanım destekleri var. Bunun haricinde, yığın, bellek içinde herhangi bir yerde olabiliyor. Veya bazen başı belli oluyor, azami sınırı belirlenebiliyor. Mimariye göre değişir.

Yığın için alan sınırlı ise, iç içe fazla fonksiyon çağırmamak veya fonksiyonlar içinde büyük alan talepleri yapmamak lazım. Özellikle uzun dizi tanımlamak gibi mesela. Yersiz olarak global değişken tanımlama başka sıkıntılar getirir. Programın anlaşılması, bakımı zorlaşır. Hata çıkma olasılığı artar. Özellikle nesne yönelimli programlamada, global değişken kullanımı mümkün olduğunca engellenmek istenir.

Recursion genelde bellekler küçük olduğundan mikrodenetleyicilerde pek desteklenmiyor. Zaten recursion programcının yazma işini kolaylaştıran ama bilgisayarın işini zorlaştıran ve çoğu durumda yavaşlatan bir şey. Teoriye göre, recursion ile yazılabilen her algoritma normal yöntemlerle de yazılabilir. Tam tersi de geçerli miydi onu hatırlamıyorum.
Gökçe Tağlıoğlu

MT

ek olarak: Stack, Heap kullanımını hintli dayı çok güzel açıklamış.

http://www.youtube.com/watch?v=_8-ht2AKyH4#ws

speak48

kesmede
işlemci nextpc yi stağe ve ilgili kesme fonksiyonun adresinide nextpc ye yazar sadece
bazı işlemciler extra işler yapabilir ama bu artık istenmiyen bir özellik.

gerikalan herşeyi kendin halletmen gerekir
yani derleyici kendi halleder.
hangi reg ler kullanılcak hangileri stağe yedeklenecek.
kaç değişkenin var stakta yer açılcak.
vs vs