x64 özel durum işleme
x64'te yapılandırılmış özel durum işlemeye ve C++ özel durum işleme kodlama kurallarına ve davranışına genel bakış. Özel durum işleme hakkında genel bilgi için bkz . Visual C++'da Özel Durum İşleme.
Özel durum işleme, hata ayıklayıcı desteği için verileri geri alma
Özel durum işleme ve hata ayıklama desteği için çeşitli veri yapıları gerekir.
struct RUNTIME_FUNCTION
Tablo tabanlı özel durum işleme, yığın alanı ayıran veya başka bir işlev çağıran tüm işlevler için bir tablo girişi gerektirir (örneğin, işlev olmayan işlevler). İşlev tablosu girdileri şu biçime sahiptir:
Size | Değer |
---|---|
ULONG | İşlev başlangıç adresi |
ULONG | İşlev bitiş adresi |
ULONG | Geri sarma bilgisi adresi |
RUNTIME_FUNCTION yapısı belleğe hizalanmış DWORD olmalıdır. Tüm adresler görüntü görelidir, yani işlev tablosu girişini içeren görüntünün başlangıç adresinden 32 bit uzaklıklardır. Bu girdiler sıralanır ve PE32+ görüntüsünün .pdata bölümüne konur. Dinamik olarak oluşturulan [JIT derleyicileri] işlevleri için, bu işlevleri destekleyen çalışma zamanının işletim sistemine bu bilgileri sağlamak için RtlInstallFunctionTableCallback veya RtlAddFunctionTable kullanması gerekir. Bunun yapılmaması, işlemlerin güvenilir olmayan özel durum işlemesine ve hata ayıklamasına neden olur.
struct UNWIND_INFO
Geri sarma veri bilgileri yapısı, bir işlevin yığın işaretçisine sahip olduğu etkileri ve kalıcı olmayan yazmaçların yığına kaydedildiği yerleri kaydetmek için kullanılır:
Size | Değer |
---|---|
UBYTE: 3 | Sürüm |
UBYTE: 5 | Bayraklar |
UBYTE | Prolog boyutu |
UBYTE | Geri sarma kodlarının sayısı |
UBYTE: 4 | Çerçeve Yazmaç |
UBYTE: 4 | Çerçeve Yazmaç uzaklığı (ölçeklendirilmiş) |
USHORT * n | Unwind codes dizisi |
değişken | Aşağıdaki biçimde (1) veya (2) olabilir |
(1) Özel Durum İşleyicisi
Size | Değer |
---|---|
ULONG | Özel durum işleyicisinin adresi |
değişken | Dile özgü işleyici verileri (isteğe bağlı) |
(2) Zincirleme Geri Sarma Bilgileri
Size | Değer |
---|---|
ULONG | İşlev başlangıç adresi |
ULONG | İşlev bitiş adresi |
ULONG | Geri sarma bilgisi adresi |
UNWIND_INFO yapısı belleğe hizalanmış DWORD olmalıdır. Her alanın anlamı şu şekildedir:
Sürüm
Şu anda 1 olan geri sarma verilerinin sürüm numarası.
Bayrak
Şu anda üç bayrak tanımlanmıştır:
Bayrak Açıklama UNW_FLAG_EHANDLER
İşlevin, özel durumları incelemesi gereken işlevler aranırken çağrılması gereken bir özel durum işleyicisi vardır. UNW_FLAG_UHANDLER
İşlev, bir özel durum geri alınırken çağrılması gereken bir sonlandırma işleyicisine sahiptir. UNW_FLAG_CHAININFO
Bu geri sarma bilgisi yapısı, yordamın birincil yapısı değildir. Bunun yerine zincirleme geri sarma bilgisi girişi, önceki bir RUNTIME_FUNCTION girdisinin içeriğidir. Daha fazla bilgi için bkz . Zincirleme geri sarma bilgi yapıları. Bu bayrak ayarlanırsa, UNW_FLAG_EHANDLER ve UNW_FLAG_UHANDLER bayrakları temizlenmelidir. Ayrıca, çerçeve yazmaç ve sabit yığın ayırma alanlarının birincil geri alma bilgileriyle aynı değerlere sahip olması gerekir. Prolog boyutu
İşlev prologunun bayt cinsinden uzunluğu.
Geri sarma kodlarının sayısı
Geri sarma kodları dizisindeki yuva sayısı. UWOP_SAVE_NONVOL gibi bazı geri sarma kodları dizide birden fazla yuva gerektirir.
Çerçeve yazmaç
Sıfır değilse, işlev bir çerçeve işaretçisi (FP) kullanır ve bu alan, UNWIND_CODE düğümlerinin işlem bilgisi alanı için aynı kodlamayı kullanarak çerçeve işaretçisi olarak kullanılan geçici olmayan yazmaç sayısıdır.
Çerçeve yazmaç uzaklığı (ölçeklendirilmiş)
Çerçeve yazmaç alanı sıfır değilse, bu alan FP yazmaç kurulduğunda FP yazmaca uygulanan RSP'den ölçeklendirilmiş uzaklıktır. Gerçek FP yazmaç RSP + 16 * bu sayı olarak ayarlanır ve 0'dan 240'a uzaklıklara izin verir. Bu uzaklık, FP yazmaçlarının dinamik yığın çerçeveleri için yerel yığın ayırmasının ortasına işaretlenmesine izin verir ve daha kısa yönergelerle daha iyi kod yoğunluğu sağlar. (Diğer bir ifadeyle, daha fazla yönerge 8 bit imzalı uzaklık formunu kullanabilir.)
Unwind codes dizisi
Prolog'un kalıcı yazmaçlar ve RSP üzerindeki etkisini açıklayan bir öğe dizisi. Tek tek öğelerin anlamları için UNWIND_CODE bölümüne bakın. Hizalama amacıyla, bu dizi her zaman çift sayıda girdiye sahiptir ve son girdi kullanılmamış olabilir. Bu durumda dizi, geri sarma kodları alanının sayısıyla belirtilenden bir daha uzundur.
Özel durum işleyicisinin adresi
bayrak UNW_FLAG_CHAININFO açıksa ve UNW_FLAG_EHANDLER veya UNW_FLAG_UHANDLER bayraklarından biri ayarlandıysa, işlevin dile özgü özel durumu veya sonlandırma işleyicisi için görüntü göreli işaretçi.
Dile özgü işleyici verileri
İşlevin dile özgü özel durum işleyici verileri. Bu verilerin biçimi belirtilmemiştir ve kullanımdaki özel durum işleyicisi tarafından tamamen belirlenir.
Zincirleme Geri Sarma Bilgileri
Bayrak UNW_FLAG_CHAININFO ayarlanırsa, UNWIND_INFO yapısı üç UWORD ile biter. Bu UWORD'ler zincirleme geri sarma işlevinin RUNTIME_FUNCTION bilgilerini temsil eder.
struct UNWIND_CODE
Geri sarma kodu dizisi, geçici olmayan yazmaçları ve RSP'yi etkileyen prologdaki işlem dizisini kaydetmek için kullanılır. Her kod öğesi şu biçime sahiptir:
Size | Değer |
---|---|
UBYTE | Girişte uzaklık |
UBYTE: 4 | Geri sarma işlemi kodu |
UBYTE: 4 | İşlem bilgileri |
Dizi, girişte azalan uzaklık düzenine göre sıralanır.
Girişte uzaklık
Bu işlemi gerçekleştiren yönergenin sonunun uzaklığı (prologun başından itibaren) artı 1 (bir sonraki yönergenin başlangıcının uzaklığı).
Geri sarma işlemi kodu
Not: Bazı işlem kodları, yerel yığın çerçevesindeki bir değere işaretsiz bir uzaklık gerektirir. Bu uzaklık başlangıçtan, yani sabit yığın ayırmanın en düşük adresidir. UNWIND_INFO Çerçeve Kaydı alanı sıfırsa, bu uzaklık RSP'dendir. Çerçeve Yazmaç alanı sıfır değilse, bu uzaklık FP yazmaç oluşturulduğunda RSP'nin bulunduğu konumdandır. FP yazmaç ile FP yazmaç uzaklığı (16 * UNWIND_INFO ölçeklendirilmiş çerçeve yazmaç uzaklığı) eşit olur. Bir FP yazmaç kullanılırsa, uzaklık alan herhangi bir geri sarma kodu yalnızca FP yazmaç girişinde oluşturulduktan sonra kullanılmalıdır.
ve UWOP_SAVE_XMM128_FAR
dışındaki UWOP_SAVE_XMM128
tüm opcode'lar için, tüm yığın değerleri 8 baytlık sınırlarda depolandığından uzaklık her zaman 8'in katıdır (yığının kendisi her zaman 16 bayt hizalanır). Kısa bir uzaklık (512K'den az) alan işlem kodları için, bu kodun düğümlerindeki son USHORT uzaklığı 8'e bölünür. Uzun bir uzaklık (512K <= uzaklık < 4 GB) alan işlem kodları için, bu kodun son iki USHORT düğümü uzaklığı (küçük endian biçiminde) tutar.
tüm 128 bit XMM işlemlerinin 16 bayt hizalanmış bellekte gerçekleşmesi gerektiğinden, işlem kodları UWOP_SAVE_XMM128
ve UWOP_SAVE_XMM128_FAR
için uzaklık her zaman 16'nın katıdır. Bu nedenle, için UWOP_SAVE_XMM128
16 ölçek faktörü kullanılır ve 1M'den küçük uzaklıklara izin verilir.
Geri sarma işlemi kodu şu değerlerden biridir:
UWOP_PUSH_NONVOL
(0) 1 düğümGeçici olmayan bir tamsayı yazmaç göndererek RSP'yi 8'e kadar azaltma. İşlem bilgileri, yazmaç numarasıdır. Kapsamlardaki kısıtlamalar nedeniyle,
UWOP_PUSH_NONVOL
geri sarma kodlarının ilk olarak prologda ve buna karşılık olarak, geri sarma kodu dizisinde son olarak görünmesi gerekir. Bu göreli sıralama, dışındakiUWOP_PUSH_MACHFRAME
diğer tüm geri alma kodları için geçerlidir.UWOP_ALLOC_LARGE
(1) 2 veya 3 düğümYığında büyük boyutlu bir alan ayırın. İki form vardır. İşlem bilgileri 0'a eşitse ayırmanın boyutu 8'e bölünür ve 512K - 8'e kadar ayırmaya izin verir. İşlem bilgisi 1'e eşitse, ayırmanın ölçeklendirilmemiş boyutu little-endian biçiminde sonraki iki yuvaya kaydedilir ve 4 GB - 8'e kadar ayırmaya izin verir.
UWOP_ALLOC_SMALL
(2) 1 düğümYığında küçük boyutlu bir alan ayırın. Ayırmanın boyutu, 8 ila 128 bayt ayırmaya izin veren işlem bilgisi alanı * 8 + 8'dir.
Yığın ayırmanın geri sarma kodu her zaman mümkün olan en kısa kodlamayı kullanmalıdır:
Ayırma Boyutu Kodu Geri Al 8 - 128 bayt UWOP_ALLOC_SMALL
136 - 512K-8 bayt UWOP_ALLOC_LARGE
, işlem bilgileri = 0512K - 4G-8 bayt UWOP_ALLOC_LARGE
, işlem bilgileri = 1UWOP_SET_FPREG
(3) 1 düğümYazmaç değerini geçerli RSP'nin bir uzaklığı olarak ayarlayarak çerçeve işaretçisi kaydını oluşturun. Uzaklık, UNWIND_INFO * 16'daki Çerçeve Yazmaç uzaklığı (ölçeklendirilmiş) alanına eşittir ve 0'dan 240'a kadar olan uzaklıklara izin verir. Uzaklık kullanımı, sabit yığın ayırmanın ortasına işaret eden bir çerçeve işaretçisi oluşturulmasına izin verir ve kısa yönerge formlarını kullanmak için daha fazla erişime izin vererek kod yoğunluğuna yardımcı olur. İşlem bilgileri alanı ayrılmıştır ve kullanılmamalıdır.
UWOP_SAVE_NONVOL
(4) 2 düğümPush yerine MOV kullanarak yığına geçici olmayan bir tamsayı yazmaç kaydedin. Bu kod öncelikli olarak, geçici olmayan bir kaydın daha önce ayrılmış bir konumda yığına kaydedildiği küçültme sarmalama için kullanılır. İşlem bilgileri, yazmaç numarasıdır. Ölçeklendirilmiş 8 yığın uzaklığı, yukarıdaki notta açıklandığı gibi bir sonraki geri sarma işlemi kod yuvasına kaydedilir.
UWOP_SAVE_NONVOL_FAR
(5) 3 düğümPush yerine MOV kullanarak uzun uzaklık ile yığında kalıcı olmayan bir tamsayı yazmaç kaydedin. Bu kod öncelikli olarak, geçici olmayan bir kaydın daha önce ayrılmış bir konumda yığına kaydedildiği küçültme sarmalama için kullanılır. İşlem bilgileri, yazmaç numarasıdır. Ölçeklendirilmemiş yığın uzaklığı, yukarıdaki notta açıklandığı gibi sonraki iki geri sarma işlemi kod yuvasına kaydedilir.
UWOP_SAVE_XMM128
(8) 2 düğüm128 bitlik kalıcı XMM kaydının tamamını yığına kaydedin. İşlem bilgileri, yazmaç numarasıdır. Ölçeklendirilmiş 16 yığın uzaklığı sonraki yuvaya kaydedilir.
UWOP_SAVE_XMM128_FAR
(9) 3 düğüm128 bitlik kalıcı XMM yazmacının tamamını uzun bir uzaklık ile yığına kaydedin. İşlem bilgileri, yazmaç numarasıdır. Ölçeklendirilmemiş yığın uzaklığı sonraki iki yuvaya kaydedilir.
UWOP_PUSH_MACHFRAME
(10) 1 düğümMakine çerçevesini itme. Bu geri sarma kodu, bir donanım kesintisinin veya özel durumun etkisini kaydetmek için kullanılır. İki form vardır. İşlem bilgisi 0'a eşitse, bu çerçevelerden biri yığına gönderilmiştir:
Konum Değer RSP+32 SS RSP+24 Eski RSP RSP+16 EFLAGS RSP+8 CS RSP RIP İşlem bilgisi 1'e eşitse, bu çerçevelerden biri gönderilmiştir:
Konum Değer RSP+40 SS RSP+32 Eski RSP RSP+24 EFLAGS RSP+16 CS RSP+8 RIP RSP Hata kodu Bu geri sarma kodu her zaman aslında hiçbir zaman yürütülmeyen, ancak bunun yerine bir kesme yordamının gerçek giriş noktasından önce görünen ve yalnızca bir makine çerçevesinin gönderimini simüle etmek için bir yer sağlamak için var olan bir sahte giriş günlüğünde görünür.
UWOP_PUSH_MACHFRAME
, makinenin kavramsal olarak bu işlemi yaptığını gösteren simülasyonu kaydeder:YıĞıNın üstünden Temp'e RIP dönüş adresini pop
SS gönderme
Eski RSP'ye gönderme
EFLAGS gönderme
CS gönderme
Anında İletme Geçici
Gönderme Hatası Kodu (işlem bilgisi 1'e eşitse)
Simülasyon
UWOP_PUSH_MACHFRAME
işlemi RSP'yi 40 (op bilgisi 0'a eşittir) veya 48 (op bilgisi 1'e eşittir) kadar azaltmaya neden olur.
İşlem bilgileri
İşlem bilgisi bitlerinin anlamı, işlem koduna bağlıdır. Genel amaçlı (tamsayı) bir kaydı kodlamak için bu eşleme kullanılır:
Bit | Kaydol |
---|---|
0 | RAX |
1 | RCX |
2 | RDX |
3 | RBX |
4 | RSP |
5 | RBP |
6 | RSI |
7 | RDI |
8 - 15 | R8 - R15 |
Zincirleme geri sarma bilgi yapıları
UNW_FLAG_CHAININFO bayrağı ayarlanırsa, geri alma bilgisi yapısı ikincil bir yapıdır ve paylaşılan özel durum işleyicisi/zincirli-bilgi adresi alanı birincil geri alma bilgilerini içerir. Bu örnek kod, UNW_FLAG_CHAININFO bayrağının ayarlandığı yapı olduğu unwindInfo
varsayılarak birincil geri alma bilgilerini alır.
PRUNTIME_FUNCTION primaryUwindInfo = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);
Zincirlenmiş bilgiler iki durumda kullanışlıdır. İlk olarak, bitişik olmayan kod kesimleri için kullanılabilir. Zincirleme bilgileri kullanarak, birincil geri alma bilgilerinden geri alma kodları dizisini yinelemeniz gerekmediğinden, gerekli geri alma bilgilerinin boyutunu küçültebilirsiniz.
Geçici kayıt kayıtlarını gruplandırmak için zincirlenmiş bilgileri de kullanabilirsiniz. Derleyici, bazı geçici yazmaçların kaydedilmesini işlev giriş prologunun dışında olana kadar geciktirebilir. Bunları, işlevin gruplandırılmış koddan önceki bölümü için birincil geri alma bilgilerine sahip olarak kaydedebilir ve ardından zincirlenmiş bilgilerdeki geri sarma kodlarının kalıcı olmayan kayıtlardan tasarruf ettiği sıfır olmayan bir girişle zincirlenmiş bilgileri ayarlayabilirsiniz. Bu durumda, geri sarma kodlarının tümü UWOP_SAVE_NONVOL örnekleridir. Push kullanarak geçici olmayan yazmaçları kaydeden veya ek bir sabit yığın ayırma kullanarak RSP kaydını değiştiren bir gruplandırma desteklenmez.
UNW_FLAG_CHAININFO kümesi olan bir UNWIND_INFO öğesi, UNWIND_INFO öğesinde de UNW_FLAG_CHAININFO ayarlanmış olan ve bazen birden çok küçültme kaydırma olarak adlandırılan bir RUNTIME_FUNCTION girişi içerebilir. Sonunda zincirleme geri sarma bilgi işaretçileri, UNW_FLAG_CHAININFO temizlenmiş bir UNWIND_INFO öğeye ulaşır. Bu öğe, asıl yordam giriş noktasına işaret eden birincil UNWIND_INFO öğesidir.
Geri sarma yordamı
Geri sarma kodu dizisi azalan düzende sıralanır. Bir özel durum oluştuğunda, bağlamın tamamı işletim sistemi tarafından bir bağlam kaydında depolanır. Ardından özel durum dağıtma mantığı çağrılır ve bir özel durum işleyicisi bulmak için bu adımları tekrar tekrar yürütür:
Geçerli işlevi (veya zincirlenmiş UNWIND_INFO girişleri için işlev bölümünü) açıklayan bir RUNTIME_FUNCTION tablo girişi aramak için bağlam kaydında depolanan geçerli RIP'i kullanın.
İşlev tablosu girişi bulunmazsa yaprak işlevindedir ve RSP doğrudan dönüş işaretçisini giderir. [RSP] konumundaki dönüş işaretçisi güncelleştirilmiş bağlamda depolanır, sanal RSP 8 artırılır ve 1. adım yinelenir.
İşlev tablosu girişi bulunursa, RIP üç bölgede bulunabilir: a) bir girişte, b) girişte veya c) özel durum işleyicisi kapsamında olabilecek kodda.
Büyük/küçük harf a) RIP bir giriş içindeyse, denetim işlevden ayrılıyorsa, bu işlev için bu özel durumla ilişkilendirilmiş bir özel durum işleyicisi olamaz ve çağıran işlevinin bağlamını hesaplamak için kapsamın etkileri devam etmelidir. RIP'in bir kapsam içinde olup olmadığını belirlemek için, RIP'den ileriye doğru kod akışı incelendi. Bu kod akışı, meşru bir kapsamın sondaki bölümüyle eşleştirilebiliyorsa, bir giriştedir ve her yönerge işlenirken bağlam kaydı güncelleştirilerek epilogun kalan kısmı benzetilir. Bu işlemden sonra 1. adım yinelenir.
Olay b) RIP prologue içinde yer alıyorsa, denetim işleve girmemişse, bu işlev için bu özel durumla ilişkili bir özel durum işleyicisi olamaz ve çağıran işlevinin bağlamını hesaplamak için prologun etkileri geri alınmalıdır. İşlevin başlangıcından RIP'e olan uzaklık, geri sarma bilgilerinde kodlanmış prolog boyutundan küçük veya buna eşitse, RIP giriş içindedir. İşlev başlangıcından RIP uzaklığından küçük veya buna eşit bir uzaklık ile ilk giriş için geri alma kodları dizisinde ileri doğru tarama yaparak ve ardından geri sarma kodu dizisindeki kalan tüm öğelerin etkisini geri alarak prologun etkileri çözülebilir. 1. adım tekrarlanır.
Olay c) RIP bir giriş veya kapsam içinde değilse ve işlevin özel durum işleyicisi varsa (UNW_FLAG_EHANDLER ayarlandıysa), dile özgü işleyici çağrılır. İşleyici verilerini tarar ve filtre işlevlerini uygun şekilde çağırır. Dile özgü işleyici, özel durumun işlendiğini veya aramanın devam etmek üzere olduğunu döndürebilir. Ayrıca doğrudan bir geri sarma başlatabilir.
Dile özgü işleyici işlenen bir durum döndürürse, yürütmeye özgün bağlam kaydı kullanılarak devam edilir.
Dile özgü bir işleyici yoksa veya işleyici "aramaya devam et" durumu döndürüyorsa, bağlam kaydı çağıranın durumuna kadar kaldırılmalıdır. Bu işlem, tüm geri sarma kodu dizisi öğelerini işleyerek ve her birinin etkisini geri alarak gerçekleştirilir. 1. adım tekrarlanır.
Zincirleme geri alma bilgileri söz konusu olduğunda, bu temel adımlar yine de izlenir. Tek fark, bir prologun etkilerini çözmek için kod dizisini geri sarmak için yürürken, dizinin sonuna ulaşıldıktan sonra üst geri alma bilgilerine bağlanır ve orada bulunan tüm geri sarma kod dizisinin yürüdüğüdür. Bu bağlantı, UNW_CHAINED_INFO bayrağı olmadan bir geri alma bilgilerine ulaşana kadar devam eder ve ardından geri sarma kodu dizisini yürümeyi tamamlar.
En küçük geri sarma veri kümesi 8 bayttır. Bu, yalnızca 128 bayt veya daha az yığın ayıran ve büyük olasılıkla geçici olmayan bir kayıt kaydeden bir işlevi temsil eder. Ayrıca, geriye doğru kod içermeyen sıfır uzunlukta bir prolog için zincirleme geri sarma bilgi yapısının boyutu da bu şekildedir.
Dile özgü işleyici
Dile özgü işleyicinin göreli adresi, UNW_FLAG_EHANDLER veya UNW_FLAG_UHANDLER bayraklar her ayarlandığında UNWIND_INFO bulunur. Önceki bölümde açıklandığı gibi, dile özgü işleyici bir özel durum işleyicisi aramasının parçası olarak veya bir geri sarmanın parçası olarak çağrılır. Bu prototipe sahiptir:
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) (
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG64 EstablisherFrame,
IN OUT PCONTEXT ContextRecord,
IN OUT PDISPATCHER_CONTEXT DispatcherContext
);
ExceptionRecord , standart Win64 tanımına sahip bir özel durum kaydına işaretçi sağlar.
EstablisherFrame , bu işlev için sabit yığın ayırma tabanının adresidir.
ContextRecord , özel durumun oluşturulduğu sırada özel durum bağlamını (özel durum işleyicisi durumunda) veya geçerli "geri sarma" bağlamını (sonlandırma işleyicisi durumunda) gösterir.
DispatcherContext , bu işlevin dağıtıcı bağlamını gösterir. Şu tanıma sahiptir:
typedef struct _DISPATCHER_CONTEXT {
ULONG64 ControlPc;
ULONG64 ImageBase;
PRUNTIME_FUNCTION FunctionEntry;
ULONG64 EstablisherFrame;
ULONG64 TargetIp;
PCONTEXT ContextRecord;
PEXCEPTION_ROUTINE LanguageHandler;
PVOID HandlerData;
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
ControlPc , bu işlev içindeki RIP değeridir. Bu değer, bir özel durum adresi veya denetimin oluşturma işlevini bıraktığı adrestir. RIP, denetimin veya için bir blok gibi bu işlevin içindeki korumalı bir __try
yapı içinde olup olmadığını belirlemek için __try
__finally
__try
/__except
/kullanılır.
ImageBase , bu işlevi içeren modülün görüntü tabanıdır (yük adresi), işlev girişinde kullanılan 32 bit uzaklıklara eklenir ve göreli adresleri kaydetmek için geri sarma bilgilerini geri alır.
FunctionEntry , işlevi tutan RUNTIME_FUNCTION işlev girdisine bir işaretçi sağlar ve bu işlev için bilgi görüntü tabanı göreli adreslerini geri alır.
EstablisherFrame , bu işlev için sabit yığın ayırma tabanının adresidir.
TargetIp , geri sarmanın devam adresini belirten isteğe bağlı bir yönerge adresi sağlar. EstablisherFrame belirtilmezse bu adres yoksayılır.
ContextRecord , sistem özel durumu gönderme/geri sarma kodu tarafından kullanılmak üzere özel durum bağlamını gösterir.
LanguageHandler , çağrılan dile özgü dil işleyici yordamını gösterir.
HandlerData , bu işlev için dile özgü işleyici verilerini gösterir.
MASM için yardımcıları geri sarma
Düzgün derleme yordamları yazmak için, uygun .pdata ve .xdata oluşturmak için gerçek derleme yönergeleriyle paralel olarak kullanılabilecek bir dizi sahte işlem vardır. Ayrıca, en yaygın kullanımları için sahte işlemlerin basitleştirilmiş kullanımını sağlayan bir makro kümesi vardır.
Ham sahte işlemler
İşlem kodlarının çoğunun düzgün kullanımıyla ilgili örnek işlev listesi aşağıda verilmiştir:
sample PROC FRAME
db 048h; emit a REX prefix, to enable hot-patching
push rbp
.pushreg rbp
sub rsp, 040h
.allocstack 040h
lea rbp, [rsp+020h]
.setframe rbp, 020h
movdqa [rbp], xmm7
.savexmm128 xmm7, 020h ;the offset is from the base of the frame
;not the scaled offset of the frame
mov [rbp+018h], rsi
.savereg rsi, 038h
mov [rsp+010h], rdi
.savereg rdi, 010h ; you can still use RSP as the base of the frame
; or any other register you choose
.endprolog
; you can modify the stack pointer outside of the prologue (similar to alloca)
; because we have a frame pointer.
; if we didn't have a frame pointer, this would be illegal
; if we didn't make this modification,
; there would be no need for a frame pointer
sub rsp, 060h
; we can unwind from the next AV because of the frame pointer
mov rax, 0
mov rax, [rax] ; AV!
; restore the registers that weren't saved with a push
; this isn't part of the official epilog, as described in section 2.5
movdqa xmm7, [rbp]
mov rsi, [rbp+018h]
mov rdi, [rbp-010h]
; Here's the official epilog
lea rsp, [rbp+020h] ; deallocate both fixed and dynamic portions of the frame
pop rbp
ret
sample ENDP
Epilog örneği hakkında daha fazla bilgi için bkz. x64 prolog ve epilog'da epilog kodu.
MASM makroları
Raw sahte işlemlerinin kullanımını basitleştirmek için ksamd64.inc içinde tanımlanan ve tipik yordam prologları ve epilogları oluşturmak için kullanılabilen bir makro kümesi vardır.
Makro | Açıklama |
---|---|
alloc_stack(n) | N baytlık bir yığın çerçevesi ayırır (kullanarak sub rsp, n ) ve uygun geri sarma bilgilerini (.allocstack n) yayar |
save_reg reg, loc | RsP uzaklık konumundaki yığına kalıcı kayıt reg'i kaydeder ve uygun geri sarma bilgilerini yayar. (.savereg reg, loc) |
push_reg reg | Yığına geçici olmayan bir kayıt defteri iletir ve uygun geri sarma bilgilerini yayar. (.pushreg reg) |
rex_push_reg reg | 2 baytlık gönderim kullanarak kalıcı olmayan bir kaydı yığına kaydeder ve uygun geri sarma bilgilerini (.pushreg reg) yayar. gönderme işlevindeki ilk yönergeyse, işlevin çalışırken düzeltme eki uygulanabilir olduğundan emin olmak için bu makroyu kullanın. |
save_xmm128 reg, loc | RSP uzaklığı loc'taki yığına kalıcı bir XMM kayıt defteri kaydeder ve uygun geri sarma bilgilerini (.savexmm128 reg, loc) yayar |
set_frame reg, uzaklık | Çerçeve kayıt reg'ini RSP + uzaklık (bir veya bir mov lea kullanarak) olarak ayarlar ve uygun geri alma bilgilerini (.set_frame reg, uzaklık) yayar |
push_eflags | Eflags'ı bir pushfq yönergeyle iletir ve uygun geri sarma bilgilerini (.alloc_stack 8) yayar |
Aşağıda makroların düzgün kullanımıyla ilgili bir örnek işlev listesi verilmiştir:
sampleFrame struct
Fill dq ?; fill to 8 mod 16
SavedRdi dq ?; Saved Register RDI
SavedRsi dq ?; Saved Register RSI
sampleFrame ends
sample2 PROC FRAME
alloc_stack(sizeof sampleFrame)
save_reg rdi, sampleFrame.SavedRdi
save_reg rsi, sampleFrame.SavedRsi
.end_prolog
; function body
mov rsi, sampleFrame.SavedRsi[rsp]
mov rdi, sampleFrame.SavedRdi[rsp]
; Here's the official epilog
add rsp, (sizeof sampleFrame)
ret
sample2 ENDP
C'de veri tanımlarını geri sarma
İşte geri sarma verilerinin C açıklaması:
typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0, /* info == register number */
UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
} UNWIND_CODE_OPS;
typedef unsigned char UBYTE;
typedef union _UNWIND_CODE {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
#define UNW_FLAG_EHANDLER 0x01
#define UNW_FLAG_UHANDLER 0x02
#define UNW_FLAG_CHAININFO 0x04
typedef struct _UNWIND_INFO {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
/* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
* union {
* OPTIONAL ULONG ExceptionHandler;
* OPTIONAL ULONG FunctionEntry;
* };
* OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, *PUNWIND_INFO;
typedef struct _RUNTIME_FUNCTION {
ULONG BeginAddress;
ULONG EndAddress;
ULONG UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
#define GetUnwindCodeEntry(info, index) \
((info)->UnwindCode[index])
#define GetLanguageSpecificDataPtr(info) \
((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
#define GetExceptionHandler(base, info) \
((PEXCEPTION_HANDLER)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
#define GetChainedFunctionEntry(base, info) \
((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
#define GetExceptionDataPtr(info) \
((PVOID)((PULONG)GetLanguageSpecificData(info) + 1))