x64 giriş ve bitiş bölümü
Yığın alanı ayıran, diğer işlevleri çağıran, geçici olmayan yazmaçları kaydeden veya özel durum işleme kullanan her işlevin, ilgili işlev tablosu girişiyle ilişkili geri sarma verilerinde adres sınırları açıklanan bir prologu olmalıdır. Daha fazla bilgi için bkz . x64 özel durum işleme. Prolog, gerekirse bağımsız değişken yazmaçlarını giriş adreslerine kaydeder, yığına geçici olmayan yazmaçlar yazar, yığının sabit bölümünü yereller ve geçiciler için ayırır ve isteğe bağlı olarak bir çerçeve işaretçisi oluşturur. İlişkili geri alma verilerinin prolog eylemini tanımlaması ve prolog kodunun etkisini geri almak için gerekli bilgileri sağlaması gerekir.
Yığındaki sabit ayırma birden fazla sayfaysa (yani 4096 bayttan büyükse), yığın ayırma birden fazla sanal bellek sayfasına yayılabilir ve bu nedenle ayırma ayrılmadan önce denetlenmelidir. Prologdan çağrılabilen ve bağımsız değişken kayıtlarından hiçbirini yok içermeyen özel bir yordam bu amaç için sağlanır.
Kalıcı olmayan yazmaçları kaydetmek için tercih edilen yöntem, sabit yığın ayırmadan önce bunları yığına taşımaktır. Sabit yığın ayırma, geçici olmayan yazmaçlar kaydedilmeden önce gerçekleştirilirse, büyük olasılıkla kaydedilen kayıt alanını ele almak için 32 bit yer değiştirme gerekir. (Bildirildiğine göre, yazmaçların gönderimleri taşımalar kadar hızlıdır ve gönderimler arasındaki zımni bağımlılıklara rağmen öngörülebilir gelecek için bu şekilde kalmalıdır.) Geçici olmayan yazmaçlar herhangi bir sırayla kaydedilebilir. Ancak, günlükte geçici olmayan bir kaydın ilk kullanımı kaydı kaydetmek olmalıdır.
Prolog kodu
Tipik bir prolog kodu şu şekilde olabilir:
mov [RSP + 8], RCX
push R15
push R14
push R13
sub RSP, fixed-allocation-size
lea R13, 128[RSP]
...
Bu prolog, rcx bağımsız değişkenini giriş konumunda depolar, kalıcı olmayan R13-R15 kayıtlarını kaydeder, yığın çerçevesinin sabit bölümünü ayırır ve sabit ayırma alanına 128 bayt işaret eden bir çerçeve işaretçisi oluşturur. Uzaklık kullanmak, sabit ayırma alanının daha fazlasının tek baytlık uzaklıklarla ele alınmasına olanak tanır.
Sabit ayırma boyutu bir sayfa bellekten büyük veya buna eşitse, RSP'yi değiştirmeden önce bir yardımcı işlev çağrılmalıdır. Bu yardımcı, __chkstk
yığının düzgün genişletildiğinden emin olmak için ayrılacak yığın aralığını yoklar. Bu durumda, bunun yerine önceki prolog örneği şöyle olacaktır:
mov [RSP + 8], RCX
push R15
push R14
push R13
mov RAX, fixed-allocation-size
call __chkstk
sub RSP, RAX
lea R13, 128[RSP]
...
Yardımcı __chkstk
, R10, R11 ve koşul kodları dışında hiçbir kaydı değiştirmez. Özellikle, RAX'ı değiştirmeden döndürür ve tüm kalıcı yazmaçları ve bağımsız değişken geçirme yazmaçlarını değiştirilmeden bırakır.
Epilog kodu
Bir işleve yapılan her çıkışta epilog kodu vardır. Normalde yalnızca bir giriş listesi olsa da, birçok epilog olabilir. Epilog kodu yığını sabit ayırma boyutuna (gerekirse) kırpar, sabit yığın ayırmasını serbestleştirir, kayıtlı değerlerini yığından çıkararak kalıcı olmayan kayıtları geri yükler ve döndürür.
Epilog kodu, özel durumlar ve kesmeler aracılığıyla güvenilir bir şekilde geri almak için geri sarma kodunun katı bir kural kümesine uyması gerekir. Bu kurallar, her bir tanımlamayı açıklamak için ek veri gerekmediğinden gereken geri sarma verilerinin miktarını azaltır. Bunun yerine, geri sarma kodu bir epilog tanımlamak için bir kod akışında ileri doğru tarama yaparak bir epilog yürütüldüğünü belirleyebilir.
İşlevde çerçeve işaretçisi kullanılmazsa, epilogun önce yığının sabit bölümünü serbest bırakması gerekir, kalıcı olmayan yazmaçlar açılır ve denetim çağrı işlevine döndürülür. Örneğin,
add RSP, fixed-allocation-size
pop R13
pop R14
pop R15
ret
İşlevde bir çerçeve işaretçisi kullanılıyorsa, yığın, epilog yürütülmadan önce sabit ayırmasına göre kırpılmalıdır. Bu eylem teknik olarak kapsamın bir parçası değildir. Örneğin, daha önce kullanılan prologu geri almak için aşağıdaki kapsam kullanılabilir:
lea RSP, -128[R13]
; epilogue proper starts here
add RSP, fixed-allocation-size
pop R13
pop R14
pop R15
ret
Uygulamada, bir çerçeve işaretçisi kullanıldığında, RSP'yi iki adımda ayarlamak için iyi bir neden yoktur, bu nedenle bunun yerine aşağıdaki kapsam kullanılır:
lea RSP, fixed-allocation-size - 128[R13]
pop R13
pop R14
pop R15
ret
Bu formlar bir epilog için tek yasal formlardır. Bir veya 'den add RSP,constant
ve ardından sıfır veya daha fazla 8 baytlık kayıt pop'larından oluşan bir seriden ve veya return
bir jmp
'den oluşmalıdır.lea RSP,constant[FPReg]
(Epilogda yalnızca bir deyim alt kümesine jmp
izin velanabilir. Alt küme yalnızca ModRM mod alanı değerinin jmp
00 olduğu ModRM bellek başvurularına sahip deyim sınıfıdır. ModRM mod alanı değeri 01 veya 10 ile girişteki deyimlerin kullanılması jmp
yasaktır. İzin verilebilen ModRM başvuruları hakkında daha fazla bilgi için bkz. AMD x86-64 Mimarisi Programcı El İle Ses 3: Genel Amaçlı ve Sistem Yönergeleri'ndeki Tablo A-15.) Başka hiçbir kod görünemez. Özellikle, bir sonuç değerinin yüklenmesi dahil olmak üzere bir kapsam içinde hiçbir şey zamanlanamaz.
Çerçeve işaretçisi kullanılmadığında, yığının sabit bölümünü serbest bırakmak için epilog kullanılmalıdır add RSP,constant
. Bunun yerine kullanamayabilir lea RSP,constant[RSP]
. Bu kısıtlama mevcut olduğundan, sarma kodunun epilog ararken tanıyacak daha az deseni vardır.
Bu kuralların takip edilmesi, geri sarma kodunun şu anda bir epilog yürütülmekte olduğunu belirlemesine ve çağrı işlevinin bağlamını yeniden oluşturmasına izin vermek için epilogun geri kalanının yürütülmesini simüle etmesine olanak tanır.