Bir derleyicinin yığını nasıl yönettiğine ve yığın üzerindeki değerlere nasıl erişildiğinin somut bir örneğini vermek için görsel tasvirlere, ayrıca GCC
Linux ortamında i386 ile hedef mimari olarak oluşturulan kodlara bakabiliriz .
1. Yığın çerçeveler
Bildiğiniz gibi, yığın, işlev veya yordamlar tarafından kullanılan, işlem için kullanılan argümanların yanı sıra, yerel olarak bildirilen değişkenler için boşluğa yığın tahsis edildiği anlamında çalışan bir işlemin adres alanındaki bir konumdur. Herhangi bir fonksiyonun dışında bildirilen değişkenler için boşluk (yani global değişkenler) sanal bellekte farklı bir bölgede tahsis edilir). Bir fonksiyonun tüm verileri için ayrılan alan bir yığın çerçeveye yönlendirilir . Birden fazla yığın çerçevesinin görsel bir tasviri ( Bilgisayar Sistemlerinden: Bir Programcının Bakış Açısı ):
2. Yığın çerçeve yönetimi ve değişken konum
Belirli bir yığın çerçevesi içinde yığına yazılan değerlerin, derleyici tarafından yönetilmesi ve program tarafından okunması için, bu değerlerin konumlarını hesaplamak ve hafıza adreslerini almak için bazı yöntemler bulunmalıdır. CPU'daki kayıtlar yığın işaretçisi ve temel işaretçi olarak adlandırılır.
Temel işaretçi, ebp
kurallara göre, yığının tabanının veya tabanının bellek adresini içerir. Yığın çerçevesindeki tüm değerlerin konumları, referans olarak taban göstergesindeki adres kullanılarak hesaplanabilir. Bu, yukarıdaki resimde tasvir edilmiştir: %ebp + 4
örneğin, temel göstergede artı 4'te depolanan hafıza adresidir.
3. Derleyici tarafından oluşturulan kod
Ama anlamadığım şey, yığıntaki değişkenlerin nasıl bir uygulama tarafından okunmasıdır - eğer x'i bir tamsayı olarak ilan edip atarsam, x = 3 deyin ve depoda yığın ayrılır ve sonra 3 değeri saklanır. orada, ve sonra aynı fonksiyonda y olarak 4 deyim ve y olarak bildiririm ve sonra başka bir ifadede x kullandığımı izler, (z = 5 + x diyelim) program z'yi değerlendirmek için x değerini nasıl okuyabilir? yığında y'nin altında mı?
Bunun nasıl çalıştığını görmek için C ile yazılmış basit bir örnek program kullanalım:
int main(void)
{
int x = 3;
int y = 4;
int z = 5 + x;
return 0;
}
Bu C kaynak metin için GCC tarafından üretilen montaj metnini inceleyelim (netlik amacıyla biraz temizledim):
main:
pushl %ebp # save previous frame's base address on stack
movl %esp, %ebp # use current address of stack pointer as new frame base address
subl $16, %esp # allocate 16 bytes of space on stack for function data
movl $3, -12(%ebp) # variable x at address %ebp - 12
movl $4, -8(%ebp) # variable y at address %ebp - 8
movl -12(%ebp), %eax # write x to register %eax
addl $5, %eax # x + 5 = 9
movl %eax, -4(%ebp) # write 9 to address %ebp - 4 - this is z
movl $0, %eax
leave
Ne gözlemlemek değişkenler x, y ve z adreslerinde yer olmasıdır %ebp - 12
, %ebp -8
ve %ebp - 4
sırasıyla. Başka bir deyişle, yığın çerçevesindeki değişkenlerin yerleri main()
CPU kaydına kaydedilen bellek adresi kullanılarak hesaplanır %ebp
.
4. Yığın işaretçisinin ötesindeki bellekteki veriler kapsam dışındadır.
Açıkça bir şey eksik. Yığındaki konumun yalnızca değişkenin kullanım ömrü / kapsamı ile ilgili olduğu ve tüm yığının programa her zaman gerçekten erişilebildiği mi? Öyleyse, değerlerin alınmasına izin vermek için yalnızca yığıntaki adreslerin adreslerini tutan başka bir dizin var mıdır? Ama sonra yığının asıl amacının, değerlerin değişken adresiyle aynı yerde depolanması olduğunu düşündüm.
Yığın, sanal bellekteki kullanımı derleyici tarafından yönetilen bir bölgedir. Derleyici, kod işaretçisini, yığın işaretçisinin ötesindeki değerlere (yığının üst kısmındaki değerler) hiçbir zaman referans verilmeyen şekilde oluşturur. Bir işlev çağrıldığında, yığın işaretçisinin pozisyonu, tabiri caizse, "sınırların dışında" olmadığı düşünülen yığında boşluk yaratmak üzere değişir.
İşlevler çağrıldığında ve döndürüldüğünde, yığın işaretçisi azaltılır ve artırılır. Yığına yazılan veriler kapsam dışı olduktan sonra kaybolmaz, ancak derleyici bu verileri referans alarak yönergeler üretmez, çünkü derleyicinin %ebp
veya kullanarak bu verilerin adreslerini hesaplaması mümkün değildir %esp
.
5. Özet
CPU tarafından doğrudan çalıştırılabilen kod, derleyici tarafından oluşturulur. Derleyici yığını yönetir, işlevler için yığını çerçeveler ve CPU kayıtlarını yönetir. GCC tarafından, i386 mimarisinde çalıştırılmak istenen koddaki yığın çerçevelerindeki değişkenlerin konumlarını izlemek için kullanılan bir strateji %ebp
, referans olarak yığın adresini taban çerçeve işaretçisinde, bellek adresini kullanmak ve değişkenlerin yığın çerçevelerindeki konumlara referans değerleri yazmaktır. adrese olan uzaklık %ebp
.