Bagikan melalui


Penanganan pengecualian x64

Gambaran umum penanganan pengecualian terstruktur dan konvensi dan perilaku penanganan pengecualian C++ pada x64. Untuk informasi umum tentang penanganan pengecualian, lihat Penanganan Pengecualian di Visual C++.

Lepaskan data untuk penanganan pengecualian, dukungan debugger

Beberapa struktur data diperlukan untuk penanganan pengecualian dan dukungan penelusuran kesalahan.

RUNTIME_FUNCTION struktur

Penanganan pengecualian berbasis tabel memerlukan entri tabel untuk semua fungsi yang mengalokasikan ruang tumpukan atau memanggil fungsi lain (misalnya, fungsi nonleaf). Entri tabel fungsi memiliki format:

Ukuran Nilai
ULONG Alamat mulai fungsi
ULONG Alamat akhir fungsi
ULONG Melepas kelelahan alamat info

Struktur RUNTIME_FUNCTION harus diselaraskan DWORD dalam memori. Semua alamat relatif gambar, yaitu offset 32-bit dari alamat awal gambar yang berisi entri tabel fungsi. Entri ini diurutkan, dan dimasukkan ke bagian .pdata dari gambar PE32+. Untuk fungsi yang dihasilkan secara dinamis [pengkompilasi JIT], runtime untuk mendukung fungsi-fungsi ini harus menggunakan RtlInstallFunctionTableCallback atau RtlAddFunctionTable untuk memberikan informasi ini ke sistem operasi. Kegagalan untuk melakukannya akan mengakibatkan penanganan pengecualian yang tidak dapat diandalkan dan penelusuran kesalahan proses.

UNWIND_INFO struktur

Struktur info data unwind digunakan untuk merekam efek yang dimiliki fungsi pada penunjuk tumpukan, dan tempat register nonvolatile disimpan pada tumpukan:

Ukuran Nilai
UBYTE: 3 Versi
UBYTE: 5 Bendera
UBYTE Ukuran prolog
UBYTE Jumlah kode unwind
UBYTE: 4 Daftar Bingkai
UBYTE: 4 Offset Frame Register (diskalakan)
USHORT * n Unwind codes array
variabel Dapat berupa (1) atau (2) di bawah ini

(1) Handler Pengecualian

Ukuran Nilai
ULONG Alamat handler pengecualian
variabel Data handler khusus bahasa (opsional)

(2) Info Unwind Berantai

Ukuran Nilai
ULONG Alamat mulai fungsi
ULONG Alamat akhir fungsi
ULONG Melepas kelelahan alamat info

Struktur UNWIND_INFO harus diselaraskan DWORD dalam memori. Berikut arti setiap bidang:

  • Versi

    Nomor versi data unwind, saat ini 1.

  • Bendera

    Tiga bendera saat ini didefinisikan:

    Bendera Deskripsi
    UNW_FLAG_EHANDLER Fungsi ini memiliki handler pengecualian yang harus dipanggil saat mencari fungsi yang perlu memeriksa pengecualian.
    UNW_FLAG_UHANDLER Fungsi ini memiliki handler penghentian yang harus dipanggil saat melepaskan pengecualian.
    UNW_FLAG_CHAININFO Struktur info unwind ini bukan yang utama untuk prosedur. Sebaliknya, entri info unwind berantai adalah konten entri RUNTIME_FUNCTION sebelumnya. Untuk informasi, lihat Struktur info unwind berantai. Jika bendera ini diatur, maka bendera UNW_FLAG_EHANDLER dan UNW_FLAG_UHANDLER harus dihapus. Selain itu, bingkai mendaftar dan bidang alokasi tumpukan tetap harus memiliki nilai yang sama seperti dalam info unwind utama.
  • Ukuran prolog

    Panjang prolog fungsi dalam byte.

  • Jumlah kode unwind

    Jumlah slot dalam array kode unwind. Beberapa kode yang dilepaskan, misalnya, UWOP_SAVE_NONVOL, memerlukan lebih dari satu slot dalam array.

  • Register bingkai

    Jika bukan nol, maka fungsi menggunakan penunjuk bingkai (FP), dan bidang ini adalah jumlah register nonvolatile yang digunakan sebagai penunjuk bingkai, menggunakan pengodean yang sama untuk bidang info operasi simpul UNWIND_CODE.

  • Offset register bingkai (diskalakan)

    Jika bidang register bingkai bukan nol, bidang ini adalah offset berskala dari RSP yang diterapkan ke register FP saat dibuat. Register FP aktual diatur ke RSP + 16 * angka ini, memungkinkan offset dari 0 hingga 240. Offset ini memungkinkan penunjukkan register FP ke tengah alokasi tumpukan lokal untuk bingkai tumpukan dinamis, memungkinkan kepadatan kode yang lebih baik melalui instruksi yang lebih pendek. (Artinya, lebih banyak instruksi dapat menggunakan formulir offset bertanda tangan 8-bit.)

  • Unwind codes array

    Array item yang menjelaskan efek prolog pada register nonvolatile dan RSP. Lihat bagian tentang UNWIND_CODE untuk arti item individual. Untuk tujuan perataan, array ini selalu memiliki jumlah entri yang merata, dan entri akhir berpotensi tidak digunakan. Dalam hal ini, array adalah satu lebih panjang dari yang ditunjukkan oleh jumlah bidang kode unwind.

  • Alamat handler pengecualian

    Penunjuk relatif gambar ke pengecualian khusus bahasa fungsi atau penangan penghentian, jika bendera UNW_FLAG_CHAININFO jelas dan salah satu bendera UNW_FLAG_EHANDLER atau UNW_FLAG_UHANDLER diatur.

  • Data handler khusus bahasa

    Data handler pengecualian khusus bahasa fungsi. Format data ini tidak ditentukan dan sepenuhnya ditentukan oleh handler pengecualian tertentu yang digunakan.

  • Info Unwind Berantai

    Jika bendera UNW_FLAG_CHAININFO diatur, maka struktur UNWIND_INFO diakhir dengan tiga UWORD. UWORD ini mewakili informasi RUNTIME_FUNCTION untuk fungsi unwind berantai.

UNWIND_CODE struktur

Array kode unwind digunakan untuk merekam urutan operasi dalam prolog yang memengaruhi register nonvolatile dan RSP. Setiap item kode memiliki format ini:

Ukuran Nilai
UBYTE Offset dalam prolog
UBYTE: 4 Lepaskan kode operasi
UBYTE: 4 Info operasi

Array diurutkan berdasarkan urutan turun offset dalam prolog.

Offset dalam prolog

Offset (dari awal prolog) dari akhir instruksi yang melakukan operasi ini, ditambah 1 (yaitu, offset dari awal instruksi berikutnya).

Lepaskan kode operasi

Catatan: Kode operasi tertentu memerlukan offset yang tidak ditandatangani ke nilai dalam bingkai tumpukan lokal. Offset ini dari awal, yaitu, alamat terendah dari alokasi tumpukan tetap. Jika bidang Frame Register di UNWIND_INFO adalah nol, offset ini berasal dari RSP. Jika bidang Frame Register bukan nol, offset ini berasal dari tempat RSP berada ketika register FP dibuat. Ini sama dengan register FP dikurangi offset register FP (16 * offset register bingkai berskala di UNWIND_INFO). Jika register FP digunakan, maka kode unwind yang mengambil offset hanya boleh digunakan setelah register FP ditetapkan dalam prolog.

Untuk semua opcode kecuali UWOP_SAVE_XMM128 dan UWOP_SAVE_XMM128_FAR, offset selalu kelipatan 8, karena semua nilai tumpukan minat disimpan pada batas 8-byte (tumpukan itu sendiri selalu selaras 16 byte). Untuk kode operasi yang mengambil offset pendek (kurang dari 512K), USHORT akhir dalam simpul untuk kode ini menyimpan offset yang dibagi 8. Untuk kode operasi yang mengambil offset panjang (512K <= offset < 4GB), dua simpul USHORT akhir untuk kode ini menahan offset (dalam format little-endian).

Untuk opcode UWOP_SAVE_XMM128 dan UWOP_SAVE_XMM128_FAR, offset selalu kelipatan 16, karena semua operasi XMM 128-bit harus terjadi pada memori selaras 16 byte. Oleh karena itu, faktor skala 16 digunakan untuk UWOP_SAVE_XMM128, memungkinkan offset kurang dari 1M.

Kode operasi unwind adalah salah satu nilai berikut:

  • UWOP_PUSH_NONVOL (0) 1 simpul

    Dorong register bilangan bulat nonvolatile, menurunkan RSP sebesar 8. Info operasi adalah jumlah register. Karena kendala pada epilog, UWOP_PUSH_NONVOL kode unwind harus muncul terlebih dahulu di prolog dan secara sesuai, terakhir dalam array kode unwind. Pemesanan relatif ini berlaku untuk semua kode unwind lainnya kecuali UWOP_PUSH_MACHFRAME.

  • UWOP_ALLOC_LARGE (1) 2 atau 3 simpul

    Alokasikan area berukuran besar pada tumpukan. Ada dua bentuk. Jika info operasi sama dengan 0, maka ukuran alokasi dibagi 8 dicatat di slot berikutnya, memungkinkan alokasi hingga 512K - 8. Jika info operasi sama dengan 1, maka ukuran alokasi yang tidak diskalakan dicatat dalam dua slot berikutnya dalam format little-endian, memungkinkan alokasi hingga 4GB - 8.

  • UWOP_ALLOC_SMALL (2) 1 simpul

    Alokasikan area berukuran kecil pada tumpukan. Ukuran alokasi adalah bidang info operasi * 8 + 8, memungkinkan alokasi dari 8 hingga 128 byte.

    Kode unwind untuk alokasi tumpukan harus selalu menggunakan pengodean sesingkat mungkin:

    Ukuran Alokasi Lepaskan Kode
    8 hingga 128 byte UWOP_ALLOC_SMALL
    136 hingga 512K-8 byte UWOP_ALLOC_LARGE, info operasi = 0
    512K hingga 4G-8 byte UWOP_ALLOC_LARGE, info operasi = 1
  • UWOP_SET_FPREG (3) 1 simpul

    Buat register penunjuk bingkai dengan mengatur register ke beberapa offset RSP saat ini. Offset sama dengan bidang Offset Frame Register (diskalakan) di UNWIND_INFO * 16, memungkinkan offset dari 0 hingga 240. Penggunaan izin offset membuat penunjuk bingkai yang menunjuk ke tengah alokasi tumpukan tetap, membantu kepadatan kode dengan memungkinkan lebih banyak akses untuk menggunakan formulir instruksi singkat. Bidang info operasi dicadangkan dan tidak boleh digunakan.

  • UWOP_SAVE_NONVOL (4) 2 simpul

    Simpan register bilangan bulat nonvolatile pada tumpukan menggunakan MOV, bukan PUSH. Kode ini terutama digunakan untuk pembungkusan penyusutan, di mana register nonvolatile disimpan ke tumpukan dalam posisi yang sebelumnya dialokasikan. Info operasi adalah jumlah register. Offset tumpukan berskala demi 8 dicatat di slot kode operasi unwind berikutnya, seperti yang dijelaskan dalam catatan di atas.

  • UWOP_SAVE_NONVOL_FAR (5) 3 simpul

    Simpan register bilangan bulat nonvolatile pada tumpukan dengan offset panjang, menggunakan MOV alih-alih PUSH. Kode ini terutama digunakan untuk pembungkusan penyusutan, di mana register nonvolatile disimpan ke tumpukan dalam posisi yang sebelumnya dialokasikan. Info operasi adalah jumlah register. Offset tumpukan yang tidak diskalakan dicatat di dua slot kode operasi unwind berikutnya, seperti yang dijelaskan dalam catatan di atas.

  • UWOP_SAVE_XMM128 (8) 2 simpul

    Simpan semua 128 bit register XMM nonvolatile pada tumpukan. Info operasi adalah jumlah register. Offset tumpukan berskala demi 16 dicatat di slot berikutnya.

  • UWOP_SAVE_XMM128_FAR (9) 3 simpul

    Simpan semua 128 bit register XMM nonvolatile pada tumpukan dengan offset panjang. Info operasi adalah jumlah register. Offset tumpukan yang tidak diskalakan direkam di dua slot berikutnya.

  • UWOP_PUSH_MACHFRAME (10) 1 simpul

    Dorong bingkai mesin. Kode unwind ini digunakan untuk merekam efek interupsi atau pengecualian perangkat keras. Ada dua bentuk. Jika info operasi sama dengan 0, salah satu bingkai ini telah didorong pada tumpukan:

    Lokasi Nilai
    RSP+32 SS
    RSP+24 RSP lama
    RSP+16 EFLAGS
    RSP+8 CS
    RSP RIP

    Jika info operasi sama dengan 1, maka salah satu bingkai ini telah didorong:

    Lokasi Nilai
    RSP+40 SS
    RSP+32 RSP lama
    RSP+24 EFLAGS
    RSP+16 CS
    RSP+8 RIP
    RSP Kode kesalahan

    Kode unwind ini selalu muncul dalam prolog dummy, yang tidak pernah benar-benar dijalankan, tetapi sebaliknya muncul sebelum titik masuk nyata dari rutinitas interupsi, dan hanya ada untuk menyediakan tempat untuk mensimulasikan pendorongan bingkai mesin. UWOP_PUSH_MACHFRAME mencatat simulasi tersebut, yang menunjukkan bahwa komputer secara konseptual telah melakukan operasi ini:

    1. Alamat pengembalian POP RIP dari atas tumpukan ke dalam Temp

    2. Dorong SS

    3. Dorong RSP lama

    4. Dorong EFLAGS

    5. Dorong CS

    6. Dorong Temp

    7. Kode Kesalahan Push (jika info op sama dengan 1)

    Operasi simulasi UWOP_PUSH_MACHFRAME mengurangi RSP sebesar 40 (info op sama dengan 0) atau 48 (info op sama dengan 1).

Info operasi

Arti bit info operasi tergantung pada kode operasi. Untuk mengodekan register tujuan umum (bilangan bulat), pemetaan ini digunakan:

Bit Daftar
0 RAX
1 RCX
2 RDX
3 RBX
4 RSP
5 RBP
6 RSI
7 RDI
8 hingga 15 R8 ke R15

Struktur info unwind berantai

Jika bendera UNW_FLAG_CHAININFO diatur, struktur info unwind adalah yang sekunder, dan bidang alamat handler/chained-info pengecualian bersama berisi informasi utama unwind. Kode sampel ini mengambil informasi unwind utama, dengan asumsi bahwa unwindInfo adalah struktur yang memiliki set bendera UNW_FLAG_CHAININFO.

PRUNTIME_FUNCTION primaryUwindInfo = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);

Info berantai berguna dalam dua situasi. Pertama, dapat digunakan untuk segmen kode yang tidak berdekatan. Dengan menggunakan info berantai, Anda dapat mengurangi ukuran informasi unwind yang diperlukan, karena Anda tidak perlu menduplikasi array kode unwind dari info unwind utama.

Anda juga dapat menggunakan info berantai untuk mengelompokkan penyimpanan register volatil. Pengkompilasi dapat menunda penghematan beberapa register volatil sampai berada di luar prolog entri fungsi. Anda dapat merekamnya dengan memiliki info unwind utama untuk bagian fungsi sebelum kode yang dikelompokkan, lalu menyiapkan info berantai dengan ukuran prolog non-nol, di mana kode unwind dalam info berantai mencerminkan penyimpanan register nonvolatile. Dalam hal ini, kode unwind adalah semua instans UWOP_SAVE_NONVOL. Pengelompokan yang menyimpan register nonvolatile dengan menggunakan PUSH atau memodifikasi register RSP dengan menggunakan alokasi tumpukan tetap tambahan tidak didukung.

Item UNWIND_INFO yang memiliki set UNW_FLAG_CHAININFO dapat berisi entri RUNTIME_FUNCTION yang item UNWIND_INFO nya juga memiliki set UNW_FLAG_CHAININFO, kadang-kadang disebut beberapa pembungkusan penyusutan. Akhirnya, pointer info unwind berantai tiba di item UNWIND_INFO yang telah UNW_FLAG_CHAININFO dibersihkan. Item ini adalah item UNWIND_INFO utama, yang menunjuk ke titik masuk prosedur aktual.

Prosedur melepas lelah

Array kode unwind diurutkan ke dalam urutan turun. Ketika pengecualian terjadi, konteks lengkap disimpan oleh sistem operasi dalam rekaman konteks. Logika pengiriman pengecualian kemudian dipanggil, yang berulang kali menjalankan langkah-langkah ini untuk menemukan penangan pengecualian:

  1. Gunakan RIP saat ini yang disimpan dalam rekaman konteks untuk mencari entri tabel RUNTIME_FUNCTION yang menjelaskan fungsi saat ini (atau bagian fungsi, untuk entri UNWIND_INFO berantai).

  2. Jika tidak ada entri tabel fungsi yang ditemukan, maka berada dalam fungsi daun, dan RSP langsung mengatasi penunjuk pengembalian. Penunjuk pengembalian di [RSP] disimpan dalam konteks yang diperbarui, RSP yang disimulasikan bertambah 8, dan langkah 1 diulang.

  3. Jika entri tabel fungsi ditemukan, RIP dapat berada dalam tiga wilayah: a) dalam epilog, b) dalam prolog, atau c) dalam kode yang mungkin dicakup oleh handler pengecualian.

    • Kasus a) Jika RIP berada dalam epilog, maka kontrol meninggalkan fungsi, tidak ada penangan pengecualian yang terkait dengan pengecualian ini untuk fungsi ini, dan efek epilog harus dilanjutkan untuk menghitung konteks fungsi pemanggil. Untuk menentukan apakah RIP berada dalam epilog, aliran kode dari RIP dan seterusnya diperiksa. Jika aliran kode tersebut dapat dicocokkan dengan bagian berikutnya dari epilog yang sah, maka dalam epilog, dan bagian epilog yang tersisa disimulasikan, dengan rekaman konteks diperbarui saat setiap instruksi diproses. Setelah pemrosesan ini, langkah 1 diulang.

    • Kasus b) Jika RIP terletak dalam prolog, maka kontrol belum memasuki fungsi, tidak ada penangan pengecualian yang terkait dengan pengecualian ini untuk fungsi ini, dan efek prolog harus dibatalkan untuk menghitung konteks fungsi pemanggil. RIP berada dalam prolog jika jarak dari fungsi mulai ke RIP kurang dari atau sama dengan ukuran prolog yang dikodekan dalam info unwind. Efek prolog dilepaskan dengan memindai maju melalui array kode unwind untuk entri pertama dengan offset kurang dari atau sama dengan offset RIP dari fungsi mulai, lalu membatalkan efek semua item yang tersisa dalam array kode unwind. Langkah 1 kemudian diulang.

    • Kasus c) Jika RIP tidak berada dalam prolog atau epilog, dan fungsi memiliki handler pengecualian (UNW_FLAG_EHANDLER diatur), maka handler khusus bahasa dipanggil. Handler memindai datanya dan memanggil fungsi filter yang sesuai. Handler khusus bahasa dapat mengembalikan bahwa pengecualian ditangani atau pencarian akan dilanjutkan. Ini juga dapat memulai unwind secara langsung.

  4. Jika handler khusus bahasa mengembalikan status yang ditangani, maka eksekusi dilanjutkan menggunakan rekaman konteks asli.

  5. Jika tidak ada handler khusus bahasa atau handler mengembalikan status "lanjutkan pencarian", maka rekaman konteks harus dilepaskan ke status pemanggil. Ini dilakukan dengan memproses semua elemen unwind code array, membatalkan efek masing-masing. Langkah 1 kemudian diulang.

Ketika info unwind berantai terlibat, langkah-langkah dasar ini masih diikuti. Satu-satunya perbedaan adalah bahwa, saat berjalan larik kode melepas lelah untuk melepas lelah efek prolog, setelah akhir array tercapai, itu kemudian ditautkan ke info unwind induk dan seluruh array kode unwind yang ditemukan di sana berjalan. Penautan ini berlanjut sampai tiba di info unwind tanpa bendera UNW_CHAINED_INFO, dan kemudian selesai berjalan array kode unwind-nya.

Kumpulan data unwind terkecil adalah 8 byte. Ini akan mewakili fungsi yang hanya mengalokasikan 128 byte tumpukan atau kurang, dan mungkin menyimpan satu register nonvolatile. Ini juga ukuran struktur info unwind berantai untuk prolog panjang nol tanpa kode unwind.

Handler khusus bahasa

Alamat relatif penangan khusus bahasa ada di UNWIND_INFO setiap kali bendera UNW_FLAG_EHANDLER atau UNW_FLAG_UHANDLER diatur. Seperti yang dijelaskan di bagian sebelumnya, handler khusus bahasa dipanggil sebagai bagian dari pencarian untuk handler pengecualian atau sebagai bagian dari unwind. Ini memiliki prototipe ini:

typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) (
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN ULONG64 EstablisherFrame,
    IN OUT PCONTEXT ContextRecord,
    IN OUT PDISPATCHER_CONTEXT DispatcherContext
);

ExceptionRecord menyediakan pointer ke rekaman pengecualian, yang memiliki definisi Win64 standar.

EstablisherFrame adalah alamat dasar alokasi tumpukan tetap untuk fungsi ini.

ContextRecord menunjuk ke konteks pengecualian pada saat pengecualian dinaikkan (dalam kasus handler pengecualian) atau konteks "lepaskan" saat ini (dalam kasus handler penghentian).

DispatcherContext menunjuk ke konteks dispatcher untuk fungsi ini. Ini memiliki definisi ini:

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 adalah nilai RIP dalam fungsi ini. Nilai ini adalah alamat pengecualian atau alamat di mana kontrol meninggalkan fungsi pembentukan. RIP digunakan untuk menentukan apakah kontrol berada dalam beberapa konstruksi yang dijaga di dalam fungsi ini, misalnya, __try blok untuk__except/__try atau .__try/__finally

ImageBase adalah basis gambar (alamat beban) modul yang berisi fungsi ini, untuk ditambahkan ke offset 32-bit yang digunakan dalam entri fungsi dan melepas info untuk merekam alamat relatif.

FunctionEntry menyediakan penunjuk ke entri fungsi RUNTIME_FUNCTION yang memegang fungsi dan melepas kelelahan info alamat relatif basis gambar untuk fungsi ini.

EstablisherFrame adalah alamat dasar alokasi tumpukan tetap untuk fungsi ini.

TargetIp Menyediakan alamat instruksi opsional yang menentukan alamat kelanjutan unwind. Alamat ini diabaikan jika EstablisherFrame tidak ditentukan.

ContextRecord menunjuk ke konteks pengecualian, untuk digunakan oleh kode pengiriman/unwind pengecualian sistem.

LanguageHandler menunjuk ke rutinitas penanganan bahasa khusus bahasa yang dipanggil.

HandlerData menunjuk ke data handler khusus bahasa untuk fungsi ini.

Lepaskan bantuan untuk MASM

Untuk menulis rutinitas rakitan yang tepat, ada sekumpulan operasi pseudo yang dapat digunakan secara paralel dengan instruksi perakitan aktual untuk membuat .pdata dan .xdata yang sesuai. Dan, ada sekumpulan makro yang menyediakan penggunaan operasi semu yang disederhanakan untuk penggunaan yang paling umum.

Operasi pseudo mentah

Operasi Pseudo Deskripsi
PROC FRAME [:ehandler] Menyebabkan MASM menghasilkan entri tabel fungsi dalam .pdata dan melepaskan informasi di .xdata untuk pengecualian terstruktur fungsi yang menangani perilaku unwind. Jika ehandler ada, proc ini dimasukkan dalam .xdata sebagai handler khusus bahasa.

Ketika atribut FRAME digunakan, atribut harus diikuti oleh . Direktif ENDPROLOG. Jika fungsi adalah fungsi daun (seperti yang didefinisikan dalam jenis Fungsi) atribut FRAME tidak perlu, seperti halnya sisa operasi pseudo ini.
. Register PUSHREG Menghasilkan entri kode unwind UWOP_PUSH_NONVOL untuk nomor register yang ditentukan menggunakan offset saat ini dalam prolog.

Hanya gunakan dengan register bilangan bulat nonvolatile. Untuk dorongan register volatil, gunakan . ALLOCSTACK 8, sebagai gantinya
. SETFRAME register, offset Mengisi bidang register bingkai dan offset dalam informasi unwind menggunakan register dan offset yang ditentukan. Offset harus kelipatan 16 dan kurang dari atau sama dengan 240. Arahan ini juga menghasilkan entri kode UWOP_SET_FPREG unwind untuk register yang ditentukan menggunakan offset prolog saat ini.
. Ukuran ALLOCSTACK Menghasilkan UWOP_ALLOC_SMALL atau UWOP_ALLOC_LARGE dengan ukuran yang ditentukan untuk offset saat ini dalam prolog.

Operand ukuran harus kelipatan 8.
. REGISTER SAVEREG, offset Menghasilkan entri kode UWOP_SAVE_NONVOL atau UWOP_SAVE_NONVOL_FAR unwind untuk register dan offset yang ditentukan menggunakan offset prolog saat ini. MASM memilih pengodean yang paling efisien.

offset harus positif, dan kelipatan 8. offset relatif terhadap dasar bingkai prosedur, yang umumnya berada di RSP, atau, jika menggunakan penunjuk bingkai, penunjuk bingkai yang tidak diskalakan.
. SAVEXMM128 register, offset Menghasilkan entri kode UWOP_SAVE_XMM128 atau UWOP_SAVE_XMM128_FAR unwind untuk register dan offset XMM yang ditentukan menggunakan offset prolog saat ini. MASM memilih pengodean yang paling efisien.

offset harus positif, dan kelipatan 16. offset relatif terhadap dasar bingkai prosedur, yang umumnya berada di RSP, atau, jika menggunakan penunjuk bingkai, penunjuk bingkai yang tidak diskalakan.
. PUSHFRAME [kode] Menghasilkan entri kode unwind UWOP_PUSH_MACHFRAME. Jika kode opsional ditentukan, entri kode unwind diberikan pengubah 1. Jika tidak, pengubah adalah 0.
.ENDPROLOG Menandakan akhir deklarasi prolog. Harus terjadi dalam 255 byte pertama fungsi.

Berikut adalah prolog fungsi sampel dengan penggunaan yang tepat dari sebagian besar opcode:

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

Untuk informasi selengkapnya tentang contoh epilog, lihat Kode epilog di prolog x64 dan epilog.

Makro MASM

Untuk menyederhanakan penggunaan operasi semu Mentah, ada sekumpulan makro, yang didefinisikan dalam ksamd64.inc, yang dapat digunakan untuk membuat prolog prosedur umum dan epilog.

Makro Deskripsi
alloc_stack(n) Mengalokasikan bingkai tumpukan n byte (menggunakan sub rsp, n), dan memancarkan informasi unwind yang sesuai (.allocstack n)
save_reg reg, loc Menyimpan reg register nonvolatile pada tumpukan di loc offset RSP, dan memancarkan informasi unwind yang sesuai. (.savereg reg, loc)
reg push_reg Mendorong reg register nonvolatile pada tumpukan, dan memancarkan informasi unwind yang sesuai. (.pushreg reg)
reg rex_push_reg Menyimpan register nonvolatile pada tumpukan menggunakan pendorongan 2 byte, dan memancarkan informasi unwind yang sesuai (reg.pushreg). Gunakan makro ini jika pendorongan adalah instruksi pertama dalam fungsi, untuk memastikan bahwa fungsi dapat di-patching.
save_xmm128 reg, loc Menyimpan reg register XMM nonvolatile pada tumpukan di loc offset RSP, dan memancarkan informasi unwind yang sesuai (.savexmm128 reg, loc)
set_frame reg, offset Mengatur reg register bingkai menjadi RSP + offset (menggunakan mov, atau lea), dan memancarkan informasi unwind yang sesuai (.set_frame reg, offset)
push_eflags Mendorong eflag dengan pushfq instruksi, dan memancarkan informasi unwind yang sesuai (.alloc_stack 8)

Berikut adalah contoh prolog fungsi dengan penggunaan makro yang tepat:

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

Melepas penat definisi data dalam C

Berikut adalah deskripsi C tentang data unwind:

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))

Baca juga

Konvensi perangkat lunak x64