Aracılığıyla paylaş


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 Tanım
    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_FARdışı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_FARiçin uzaklık her zaman 16'nın katıdır. Bu nedenle, için UWOP_SAVE_XMM12816 ö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üğüm

    Geç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ışındaki UWOP_PUSH_MACHFRAMEdiğer tüm geri alma kodları için geçerlidir.

  • UWOP_ALLOC_LARGE (1) 2 veya 3 düğüm

    Yığı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üğüm

    Yığı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 = 0
    512K - 4G-8 bayt UWOP_ALLOC_LARGE, işlem bilgileri = 1
  • UWOP_SET_FPREG (3) 1 düğüm

    Yazmaç 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üğüm

    Push 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üğüm

    Push 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üğüm

    128 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üğüm

    128 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üğüm

    Makine ç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:

    1. YıĞıNın üstünden Temp'e RIP dönüş adresini pop

    2. SS gönderme

    3. Eski RSP'ye gönderme

    4. EFLAGS gönderme

    5. CS gönderme

    6. Anında İletme Geçici

    7. 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
Kategori 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:

  1. 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.

  2. İş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.

  3. İş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.

  4. Dile özgü işleyici işlenen bir durum döndürürse, yürütmeye özgün bağlam kaydı kullanılarak devam edilir.

  5. 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

Sahte işlem Tanım
PROC FRAME [:ehandler] MASM'nin .pdata içinde bir işlev tablosu girdisi oluşturmasına ve bir işlevin geri alma davranışını işleyen yapılandırılmış özel durum için .xdata'da geri alma bilgileri oluşturmasına neden olur. ehandler varsa, bu proc dile özgü işleyici olarak .xdata içine girilir.

FRAME özniteliği kullanıldığında, bunu bir takip etmesi gerekir. ENDPROLOG yönergesi. İşlev yaprak bir işlevse (İşlev türlerinde tanımlandığı gibi) FRAME özniteliği de bu sahte işlemlerin geri kalanı gibi gereksizdir.
. PUSHREG yazmaç Prologue'daki geçerli uzaklığı kullanarak belirtilen kayıt numarası için UWOP_PUSH_NONVOL bir geri sarma kodu girişi oluşturur.

Yalnızca geçici olmayan tamsayı yazmaçlarıyla kullanın. Geçici yazmaçların gönderimleri için kullanın. Bunun yerine ALLOCSTACK 8
. SETFRAME yazmaç, uzaklık Belirtilen yazmaç ve uzaklığı kullanarak geri sarma bilgilerinde çerçeve yazmaç alanını ve uzaklığı doldurur. Uzaklık 16'nın katı ve 240'tan küçük veya buna eşit olmalıdır. Bu yönerge ayrıca geçerli prologue uzaklığını kullanarak belirtilen yazmaç için bir UWOP_SET_FPREG geri sarma kodu girişi oluşturur.
. ALLOCSTACK boyutu Prologue'daki geçerli uzaklık için belirtilen boyuta sahip bir UWOP_ALLOC_SMALL veya UWOP_ALLOC_LARGE oluşturur.

Boyut işleneni 8'in katı olmalıdır.
. SAVEREG yazmaç, uzaklık Geçerli prologue uzaklığını kullanarak belirtilen yazmaç ve uzaklık için bir UWOP_SAVE_NONVOL veya UWOP_SAVE_NONVOL_FAR bırakma kodu girişi oluşturur. MASM en verimli kodlamayı seçer.

uzaklık pozitif ve 8'in katı olmalıdır. uzaklık , genellikle RSP'de olan yordamın çerçevesinin tabanına veya çerçeve işaretçisi kullanılıyorsa ölçeklendirilmemiş çerçeve işaretçisine göre belirlenir.
. SAVEXMM128 yazmaç, uzaklık Geçerli prologue uzaklığını kullanarak belirtilen XMM yazmacı ve uzaklığı için bir UWOP_SAVE_XMM128 veya UWOP_SAVE_XMM128_FAR geri alma kodu girişi oluşturur. MASM en verimli kodlamayı seçer.

uzaklık pozitif ve 16'nın katı olmalıdır. uzaklık , genellikle RSP'de olan yordamın çerçevesinin tabanına veya çerçeve işaretçisi kullanılıyorsa ölçeklendirilmemiş çerçeve işaretçisine göre belirlenir.
. PUSHFRAME [kod] bir UWOP_PUSH_MACHFRAME geri sarma kodu girdisi oluşturur. İsteğe bağlı kod belirtilirse, geri sarma kodu girdisine 1 değiştiricisi verilir. Aksi takdirde değiştirici 0'dır.
.ENDPROLOG Prolog bildirimlerinin sonuna işaret eder. İşlevin ilk 255 bayt içinde gerçekleşmesi gerekir.

İş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 Tanım
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 movleakullanarak) 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))

Ayrıca bkz.

x64 yazılım kuralları