Stack ve Heap Bölgesi Hakkında

Başlatan fatihinanc, 07 Temmuz 2011, 09:52:12

fatihinanc

Merhaba,

Bir projemde MSP430 ile sıcaklık ölçümü yapmam gerekiyordu ve kodu IAR da yazdım, bitirdim.
Fakat debug ederken alt kısımda Stack dolu diye bir uyarı çıktığını farkettim.
Stack alanı için 80 byte yer ayırılıyormuş. Ayarlardan tekrar düzelttim ve Stack alanını da Heap alanını da 170 byte yaptım.
Sonra debug menüsünde hiçbir uyarı çıkmamaya başladı. 170 baytın toplam 138 baytı kullanılıyor şu an.

Aslında kodu yazarken böyle birşey olacağını tahmin etmiştim ama 80 baytı da geçeceğini düşünmemiştim.
Toplamda 3 kere iç içe fonksiyon çağırıyorum. Bu kadar yüksek yer kaplamasının nedenini anlayamadım.
Program fonksiyona dallandığı anda kaldığı adresi stack e yüklediğini biliyorum. Ve eğer bu alan dolarsa da programın düzgün çalışmayacağını da biliyorum.

Sorum ise şu : Stack ve Heap alanlarının organizasyonu derleyici tarafından nasıl yapılıyor ?
Ve bu kadar yüksek bellek gereksinimine neden ihtiyaç duyuluyor ?


NOT : 16 bit MSP430 kullanıyorum. Toplam flash = 8kb, RAM = 256 Byte

Kodun tamamını ekleyip işi iyice anlaşılmaz hale getirmek istemediğimden sadece gerekli kısmı ekliyorum.
Sonradan ihtiyaç olursa tamamını ekleyebilirim.

Bu konu hakkında fikir sahibi olan forumdaki üstadlardan yardım bekliyorum.

#include "io430.h"
#include "in430.h"
#include "yazilimsal_uart.h"
#include "adc.h"

extern unsigned int txData;
unsigned int sicaklik=0;
  
unsigned int hesapla(unsigned int* gelen_s);
void sicaklik_gonder(unsigned int gelen_t);

void main( void )
{
  unsigned int sicaklik_dizi[64];
  .
  .
  .
  __enable_interrupt();

  TimerA_UART_init();  
  adc_init();

  TimerA_UART_print("MSP430G2452 -> ADC -> UART\r\n");
  TimerA_UART_print("Sicaklik Olcme Uygulamasi\r\n");  
  
  while(1)
  {
    ADC10CTL0 &= ~ENC;
      
    while (ADC10CTL1 & BUSY);          
    ADC10SA = (unsigned int)sicaklik_dizi;
    ADC10CTL0 |= ENC + ADC10SC;
    
    sicaklik_gonder(hesapla(sicaklik_dizi));

    _NOP(); //breakpoint için...
  }
}

unsigned int hesapla(unsigned int* gelen_s)
{
  unsigned int toplam=0;

  for(char i=0;i<64;i++)
    toplam+=gelen_s[i];
  
  sicaklik=sicaklik_oku(toplam>>=6);
  
  _NOP(); //breakpoint için...

  return sicaklik;
}
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

z

İşlemcinle uğraşmadım bu yüzden kesin konuşmuyorum.

Herşeyden önce işlemci 16 bit. Stackda geri dönüş adresleri 2 byte byte saklanıyor.
Aynı şekilde saklanması gereken registerler de stackta 2 byte byte yer kaplıyor.
Eğer C kullanıyorsan fonskiyonlara parametre aktarımı gene stack üzerinden gerçeleşir.
Float işlemler yazboz alanı ister ve bunun için gene stack alanından yararlanılır.
Fonksiyonlarındaki lokal değişkenler de stack alanından yer çalar.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

fatihinanc

@bunalmis hocam
Haklısınız. Bahsettiğiniz tüm işlemler programda yapılıyor. Hem float hesaplaması hem de bir fonksiyona 64 lük int (64 x 2 = 128 b) dizi aktarıyorum.
Muhtemelen bundan olsa gerek. Bu programda hafıza sorunum yok ondan dolayı stack alanını arttırabiliyorum fakat ileride belki problem olur diye sebebini şimdiden öğrenmek istedim.
Bu arada stack %90 dolunca uyarı veriyormuş şu an 150 bayt stack ihtiyacı var ben de 152 bayt stack alanı tanımladım ve toplamda da 157 bayt RAM kullanıyorum ;)

@FxDev
Dedğin bugün öğlen aklıma geldi aslında. Diziden olduğundan şüphelendim fakat bunun tek alternatifi o diziyi global tanımlamak olacağından o da işime yaramayacaktı ki öyle oldu.
Diziyi global tanımladım. RAM kullanımı 160 baytlardan 213 bayta çıktı. Fakat stack alanında dediğin gibi azalma oldu. Ama totalde işe yaramıyor ;)

Üstadlar yardımcı olduğunuz için teşekkür ediyorum.

Heap alanı hakkında bir fikri olan var mı peki ? Ben hem heap alanını hem de stack alanını 152 bayt tanımladım çünkü...
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

Klein

#3
Alıntı YapHeap alanı hakkında bir fikri olan var mı peki ? Ben hem heap alanını hem de stack alanını 152 bayt tanımladım çünkü...

OOP programlamada nesneleri tutmak için ayrılmış alan.  Aslında bir çeşit stack. Ama Stack alanında  değişkenler tutulurken , heap alanında nesneler ( sınıflar , class) tutulur.
C++ için gerekli bir ayar. C'de bir işlevi var mı bilmiyorum. Belki yapılar(struct) burada tutuluyor olabilir. Emin değilim.

diziyi global alanda tutmak neden işini görmedi? 

fatihinanc

Alıntı yapılan: Klein - 08 Temmuz 2011, 22:42:29
diziyi global alanda tutmak neden işini görmedi? 

Anladım hocam sağolun.
Diziyi global alana aldığım zaman toplam kullanılan bellek miktarı arttı. Normalde 160 bayt (152 bayt stack için ayrılıyor) civarında olan RAM kullanımı 213 bayta çıktı.
Zaten bu şekilde de ancak stack alanını azaltınca kodu derleyebiliyorum. Çünkü toplam hafızam 256 bayt.

Ben de stack alanını geniş tutup diziyi local alanda tanımlayarak bellekten tasarruf sağlamayı seçtim.
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

fatihinanc

Az önce tekrar denedim. Normalde diziyi global alana alınca stack kullanımı 22 bayta düşüyor.
Eğer ben de maksimum stack alanını 24 bayt yaparsam toplam RAM kullanımı 157 bayt oluyor.

dizi localde iken de toplam RAM kullanımım 157 bayt idi.

Fakat ben dizi alanını globalde tutmak yerine localde tutmanın daha iyi olacağını düşünüyorum.
Neticede dizinin kullanılmadığı bloklarda bu alan yerine başka değişkenler iş yapabilecek.
Globalde ise o alanlar programın başından sonuna kadar dizi için ayrılacak diye biliyorum.
Doğru mudur?
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

Klein

#6
:) Yok aslında öyle olmayacak.
Çünkü:
Dizi "main" fonksiyonu içinde tanımlı.  Main fonksiyonuna ilk girişte o dizi için stack ayrılacak. Ancak siz "main" fonksiyonundan hiç çıkmadığınız için o dizi için ayrılan stack alanı hiç boşaltılmayacak.

Ben olsam stack'i  rahatlatmaya çalışırdım.

fatihinanc

 :o
Ama ana döngü içerisinde fonksiyondan fonksiyona toplam 3 kere geçiş yapıyorum hocam.
O geçişlerde burayı boşaltması lazım ki debug ekranında diğer fonksiyonların içindeki satırlara breakpoint koyup içeriği gözlemlediğim zaman bu dizinin değişkenlerini göremiyorum.
içerikler Unknown... olarak görünüyor.
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

Klein

Boşaltmaz.
Bir fonksiyonun değişkenlerininin yığından boşaltılmasının şartı fonksiyondan çıkmaktır.  içiçe yazdığımız fonksiyonlarda stack şişmesinin sebebi de budur.  Sen fonksiyondan fonksiyona geçiş yapmıyorsun. Main fonksiyonu içinde başka bir fonksiyon çağırıyorsun.
Şöyle düşün.
Bir fonksiyon çağırdık fonksiyon işlenirken başka bir fonksiyon çağırdık. ilk fonksiyonumuzun bilgileri nerede? stack'te , sonra bir fonksiyon daha çağırdık önceki fonksiyonumuzun içeriği nerede? stack'te
eğer böyle olmasaydı fonksiyon içinde fonksiyon çağırdığımızda önceki fonksiyonun içeriği kaybolmaz mıydı? ya da stack şişer miydi?
Main de sonuçta bir fonksiyon. Main içerisinde başka fonksiyon çağırman main fonksiyonunu sonlandırmaz.
Program eğer stack üzerinde bir array açtıysa  onun neresi kullanılmış , neresi kullanılmamış bakmaz. Çünkü çok farklı yollardan , dolaylı adresleme ile vs.. oraya veri atmış olabilirsin. O alanı başka birine kullandırması çok ciddi karışıklıklara neden olabilir.

fatihinanc

Anladım hocam. Haklısınız. bu şekilde fonksiyon sonlanmıyor. Hem de diğer fonksiyona geçişte bu bilgileri stacke attığı için stack doluyor.
Az önce tekrar debugtan baktım stack tamamen 64 lük dizi ile dolu neredeyse...

Bu alanı globalde tutup stacki daha geniş(rahat) tutmayı tavsiye ediyorsunuz...
Peki hocam sağolun vakit ayırıp ilgilendiğiniz için...
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)

camby

#10
Donanımsal Stack ve yazılımsal stack farklı yerler değil mi ?

Bir fonksiyona giderken , geri dönülecek yerin adresini tutan stack alanı donanımsal alan. Push pop Call return gibi komutlardan etkilenen alan burası.

Bunun dışında yukarıda bahsettiğiniz fonksiyon parametreleri ve local değişkenler de ayrıca tanımlanmış yazılımsal bir stack alanında mı saklanıyor ?

Fonksiyona ait parametreler ve local değişkenler bu donanımsal stack alanına kayıt ediliyor mu ?

( Bunları genel olarak soruyorum MSP için yada IAR için değil  )

z

Cevabı kullanılan işlemciye de bağlı.

Donanımsal stack, return adresi yanısıra, parametre aktarımı için de kullanılır.

Bu tür numaralarda işlemcinin yetenekleri çok ön plana çıkıyor.

Yazılımsal stack olayına ihtiyaç CPU nun beceriksizliğinden.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

camby

18f'lerde tek stack dönüş adresi için bildiğim kadarıyla.

M3 , M4 'de durum nasıl ? Donanım destekliyor mu peki ?


Yazılımsal olarak oluşturacağım ben de..

camby

Gerbay hocam , konu biraz eski ancak başlıkta konuşulmuşlar yararlı olduğu olduğu için bu konu altına yazayım dedim ben de.

ASM ortamına bir stack yapısı oluşturmaya çalışıyordum , çünkü kesmede aynı fonksiyonları tekrar tekrar kullanınca datalarım bozuluyor. Donanımsal ekstra bir FIFO'ya sahip değil 18f , yazılımsal yapmaya da karar veremedim henüz. RAM çok o yüzden şuan lık kritik ram alanlarını kesmeye giderken yedekliyorum.

fatihinanc

Selamlar,

Konu biraz eskimiş ama bilgiler faydalı olabilir.

@camby hocam,
Kullandığımız 8-16 bit kontrolörlerin çoğunda stack için ayrı bir FIFO yok diye biliyorum.
Editör'de stack alanı için kullanacağınız boyutu belirledikten sonra derleme sonucunda derleyici "Sen kullansan da kullanmasan da ben RAM den bu alanı stack için ayırdım arkadaş !" diyor aslında. Ve ona göre de normale göre daha fazla RAM kullanımı çıktısı veriliyor.

@gerbay hocam stack ve heap i çok güzel anlatmış aslında. Ben bu başlığı açtığımda hala bazı yerler oturmamıştı. Yakın zamanda bir kaynaktan okuduktan sonra iyice anladım. Benim okuduğumun tam özeti olmuş bu anlatım.

Bu arada IAR'dan elf çıktısını aldım. Aşağıda;
http://bit.ly/THJZtt
Kainat dediğimiz kitap, yazıldığı dil ve harfler öğrenilmedikçe anlaşılamaz.  (Galileo Galilei)