Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Gambaran umum penanganan pengecualian terstruktur dan konvensi dan perilaku penanganan pengecualian C++ pada x64. Untuk informasi umum tentang penanganan pengecualian, lihat Penanganan Pengecualian di Microsoft C++.
Lepaskan data untuk penanganan pengecualian, dukungan debugger
Beberapa struktur data diperlukan untuk penanganan pengecualian dan dukungan penelusuran kesalahan.
struktur RUNTIME_FUNCTION
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 awal fungsi |
| ULONG | Alamat akhir fungsi |
| ULONG | Melepas kelelahan alamat info |
Struktur RUNTIME_FUNCTION harus diselaraskan DWORD dalam memori. Semua alamat relatif terhadap gambar, yaitu merupakan offset 32-bit dari alamat awal dari 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 debugging kesalahan proses.
struktur UNWIND_INFO
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 | Penanda |
| UBYTE | Ukuran prolog |
| UBYTE | Jumlah kode unwind |
| UBYTE: 4 | Daftar Bingkai |
| UBYTE: 4 | Offset Frame Register (diskalakan) |
| USHORT * n | Array kode pembuka |
| variabel | Dapat berupa (1) atau (2) di bawah ini |
(1) Handler Pengecualian
| Ukuran | Nilai |
|---|---|
| ULONG | Alamat penangan pengecualian |
| variabel | Data handler khusus bahasa (opsional) |
(2) Informasi Pemulihan (Unwind) Berantai
| Ukuran | Nilai |
|---|---|
| ULONG | Alamat mulai fungsi |
| ULONG | Alamat akhir fungsi |
| ULONG | Informasi Unwind Alamat |
Struktur UNWIND_INFO harus diselaraskan DWORD dalam memori. Berikut arti setiap bidang:
Versi
Nomor versi dari data unwind adalah saat ini 1.
Pengaturan
Tiga bendera saat ini didefinisikan:
Tanda Deskripsi UNW_FLAG_EHANDLERFungsi ini memiliki handler pengecualian yang harus dipanggil saat mencari fungsi yang perlu memeriksa pengecualian. UNW_FLAG_UHANDLERFungsi ini memiliki handler penghentian yang harus dipanggil saat melepaskan pengecualian. UNW_FLAG_CHAININFOStruktur informasi unwind ini bukan yang utama untuk proses. Sebaliknya, entri info unwind berantai adalah konten entri RUNTIME_FUNCTION sebelumnya. Untuk informasi, lihat Struktur informasi unwind yang berantai. Jika flag ini diatur, maka flag UNW_FLAG_EHANDLER dan UNW_FLAG_UHANDLER harus dihapus. Selain itu, register frame dan bidang pengalokasian tumpukan tetap perlu memiliki nilai yang sama seperti dalam info unwind utama. Ukuran prolog
Panjang prolog fungsi dalam satuan byte.
Jumlah kode pengurang
Jumlah slot dalam array kode unwind. Beberapa kode unwind, contohnya UWOP_SAVE_NONVOL, memerlukan lebih dari satu slot dalam array.
Register frame
Jika bukan nol, maka fungsi akan menggunakan penunjuk kerangka (FP), dan bidang ini adalah nomor register nonvolatile yang digunakan sebagai penunjuk kerangka, menggunakan pengkodean yang sama untuk bidang info operasi node 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 mengarahkan register FP ke tengah alokasi stack lokal untuk frame stack dinamis, memungkinkan kepadatan kode yang lebih efisien melalui instruksi yang lebih ringkas. (Artinya, lebih banyak instruksi dapat menggunakan formulir offset bertanda tangan 8-bit.)
Unwind codes array
Sebuah 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 memiliki satu elemen lebih panjang dari yang ditunjukkan oleh jumlah kode unwind.
Alamat penangan 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 pengelola pengecualian khusus bahasa dari fungsi. Format data ini tidak ditentukan dan sepenuhnya ditentukan oleh handler pengecualian tertentu yang digunakan.
Informasi Pembongkaran Berantai
Jika penanda UNW_FLAG_CHAININFO diatur, maka struktur UNWIND_INFO diakhiri dengan tiga UWORD. UWORD ini mewakili informasi RUNTIME_FUNCTION untuk fungsi unwind berantai.
struktur UNWIND_CODE
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 dalam urutan menurun berdasarkan offset di prolog.
Offset dalam prolog
Offset (dari awal prolog) dari akhir instruksi yang melakukan operasi ini, ditambah 1 (artinya, 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 memori stack 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 menggunakan offset hanya boleh digunakan setelah register FP ditentukan dalam prolog.
Untuk semua opcode kecuali UWOP_SAVE_XMM128 dan UWOP_SAVE_XMM128_FAR, offset selalu kelipatan 8, karena semua nilai tumpukan yang relevan disimpan pada batas 8 byte (tumpukan itu sendiri selalu sejajar 16 byte). Untuk kode operasi yang mengambil offset pendek (kurang dari 512K), USHORT akhir dalam simpul untuk kode ini menyimpan offset yang dibagi dengan 8. Untuk kode operasi yang menggunakan offset panjang (512K <= offset < 4GB), dua node USHORT terakhir untuk kode ini berisi 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 simpulMasukkan register bilangan bulat nonvolatile, kurangi RSP sebesar 8. Info operasi adalah nomor register. Karena kendala pada epilog,
UWOP_PUSH_NONVOLkode unwind harus muncul terlebih dahulu di prolog dan secara sesuai, terakhir dalam array kode unwind. Urutan relatif ini berlaku untuk semua kode unwind lainnya kecualiUWOP_PUSH_MACHFRAME.UWOP_ALLOC_LARGE(1) 2 atau 3 simpulAlokasikan 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 belum diskalakan dicatat dalam dua slot berikutnya dalam format little-endian, memungkinkan alokasi hingga 4GB dikurangi 8 byte.
UWOP_ALLOC_SMALL(2) 1 simpulAlokasikan ruang kecil pada tumpukan. Ukuran alokasi adalah bidang informasi operasi * 8 + 8, sehingga dapat mengalokasikan dari 8 hingga 128 byte.
Kode unwind untuk alokasi tumpukan harus selalu menggunakan pengodean sesingkat mungkin:
Ukuran Alokasi Unwind Code 8 hingga 128 byte UWOP_ALLOC_SMALL136 hingga 512K-8 byte UWOP_ALLOC_LARGE, operation info = 0512K hingga 4G-8 byte UWOP_ALLOC_LARGE, info operasi = 1UWOP_SET_FPREG(3) 1 simpulBuat 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 offset memungkinkan penetapan penunjuk frame yang menunjuk ke tengah alokasi stack tetap, membantu kepadatan kode dengan memungkinkan lebih banyak akses menggunakan bentuk instruksi pendek. Bidang info operasi sudah dicadangkan dan tidak boleh digunakan.
UWOP_SAVE_NONVOL(4) 2 simpulSimpan register bilangan bulat nonvolatile pada tumpukan dengan menggunakan instruksi MOV, bukan instruksi PUSH. Kode ini terutama digunakan untuk shrink-wrapping, di mana register nonvolatile disimpan pada tumpukan di dalam posisi yang telah dialokasikan sebelumnya. Info operasi adalah nomor register. Offset stack yang diskalakan dengan faktor 8 dicatat di slot kode operasi unwind berikutnya, seperti yang dijelaskan dalam catatan sebelumnya.
UWOP_SAVE_NONVOL_FAR(5) 3 simpulSimpan register bilangan bulat nonvolatile pada stack dengan offset yang panjang, menggunakan MOV alih-alih PUSH. Kode ini terutama digunakan untuk pembungkusan shrink, di mana register nonvolatile disimpan ke dalam tumpukan dalam posisi yang sebelumnya sudah dialokasikan. Info operasi adalah nomor register. Offset tumpukan yang tidak diskalakan didaftarkan di dua slot kode operasi pemulihan berikutnya, seperti yang telah dijelaskan dalam catatan di atas tersebut.
UWOP_SAVE_XMM128(8) 2 simpulSimpan semua 128 bit register XMM nonvolatile pada tumpukan. Info operasi adalah nomor register. Offset tumpukan berskala kelipatan 16 dicatat di slot berikutnya.
UWOP_SAVE_XMM128_FAR(9) 3 simpulSimpan semua 128 bit register XMM nonvolatile di tumpukan dengan offset yang besar. Info operasi adalah nomor register. Offset tumpukan yang tidak diskalakan direkam di dua slot berikutnya.
UWOP_PUSH_MACHFRAME(10) 1 simpulDorong rangka mesin. Kode unwind ini digunakan untuk merekam efek interupsi atau pengecualian perangkat keras. Ada dua bentuk. Jika info operasi sama dengan 0, salah satu frame ini telah ditambahkan ke tumpukan:
Lokasi Nilai RSP+32 SS RSP+24 RSP lama RSP+16 EFLAGS RSP+8 Ilmu Komputer RSP RIP Jika info operasi sama dengan 1, maka salah satu bingkai ini telah dimasukkan:
Lokasi Nilai RSP+40 SS RSP+32 RSP lama RSP+24 EFLAGS RSP+16 Ilmu Komputer 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_MACHFRAMEmencatat simulasi tersebut, yang menunjukkan bahwa komputer secara konseptual telah melakukan operasi ini:Ambil alamat pengembalian RIP dari atas tumpukan ke dalam Temp
Tekan Tangkapan Layar
Gulirkan RSP lama
Instruksi PUSH EFLAGS
Dorong CS
Dorong Temp
Kode Kesalahan Push (jika info op sama dengan 1)
Operasi simulasi
UWOP_PUSH_MACHFRAMEmengurangi 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 flag UNW_FLAG_CHAININFO diatur, maka struktur informasi unwind adalah struktur sekunder, dan bidang alamat penangan pengecualian bersama/chained-info mengandung informasi utama unwind. Kode sampel ini mengambil informasi unwind utama, dengan asumsi bahwa unwindInfo adalah struktur yang memiliki penanda UNW_FLAG_CHAININFO yang disetel.
PRUNTIME_FUNCTION primaryUwindInfo = (PRUNTIME_FUNCTION)&(unwindInfo->UnwindCode[( unwindInfo->CountOfCodes + 1 ) & ~1]);
Informasi berantai berguna dalam dua situasi. Pertama, dapat digunakan untuk segmen kode yang tidak berdekatan. Dengan menggunakan informasi berantai, Anda dapat mengurangi ukuran informasi unwind yang diperlukan, karena Anda tidak perlu menduplikasi array kode unwind dari informasi unwind utama.
Anda juga dapat menggunakan informasi berantai untuk mengelompokkan penyimpanan register yang bersifat volatil. Pengkompilasi dapat menunda penyimpanan beberapa register volatil sampai setelah 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 yang tidak nol, di mana kode unwind dalam info berantai merefleksikan penyimpanan register yang tidak volatil. 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 UNW_FLAG_CHAININFO disetel dapat berisi entri RUNTIME_FUNCTION yang item UNWIND_INFO-nya juga memiliki UNW_FLAG_CHAININFO disetel, kadang-kadang disebut multiple shrink-wrapping. Akhirnya, pointer informasi unwind berantai mencapai item UNWIND_INFO di mana UNW_FLAG_CHAININFO telah dibersihkan. Item ini adalah item UNWIND_INFO utama, yang menunjuk ke titik masuk prosedur aktual.
Prosedur pembongkaran
Array kode unwind diurutkan dalam urutan menurun. 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:
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).
Jika tidak ada entri tabel fungsi yang ditemukan, maka berada dalam fungsi daun, dan RSP mengakses penunjuk pengembalian langsung. Penunjuk pengembalian di [RSP] disimpan dalam konteks yang diperbarui, RSP yang disimulasikan bertambah 8, dan langkah 1 diulang.
Jika entri tabel fungsi ditemukan, RIP dapat berada dalam tiga wilayah: a) dalam epilog, b) dalam pralog, atau c) dalam kode yang mungkin dicakup oleh penangan pengecualian.
Kasus a) Jika RIP berada dalam epilog, maka kontrol akan meninggalkan fungsi tersebut, tidak ada penangan pengecualian yang berhubungan dengan pengecualian ini untuk fungsi tersebut, dan efek dari epilog harus dilanjutkan untuk memastikan 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 akhir dari epilog yang sah, maka aliran kode tersebut termasuk 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 berada dalam prolog, maka kontrol belum masuk ke dalam fungsi, tidak ada pemroses pengecualian yang terkait dengan pengecualian ini untuk fungsi ini, dan efek prolog harus dibatalkan untuk mengembalikan konteks fungsi pemanggil. RIP berada dalam prolog jika jarak dari awal fungsi ke RIP kurang dari atau sama dengan ukuran prolog yang dikodekan dalam informasi 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 penangan pengecualian (UNW_FLAG_EHANDLER diatur), maka penangan spesifik 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.
Jika handler khusus bahasa mengembalikan status yang ditangani, maka eksekusi dilanjutkan menggunakan rekaman konteks asli.
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 tetap harus diikuti. Satu-satunya perbedaan adalah bahwa, saat membaca larik kode membuka kembali untuk membuka efek prolog, setelah akhir array tercapai, itu kemudian ditauntkan ke informasi unwind induk dan seluruh larik kode membuka kembali yang ditemukan di sana dibaca. Penghubungan ini berlanjut sampai mencapai info unwind yang tidak memiliki bendera UNW_CHAINED_INFO, dan kemudian menyelesaikan penelusuran 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 merupakan ukuran dari struktur info unwind yang berantai untuk prolog dengan panjang nol tanpa kode unwind.
Handler khusus bahasa
Alamat relatif pengolah khusus untuk bahasa ada di UNWIND_INFO ketika bendera UNW_FLAG_EHANDLER atau UNW_FLAG_UHANDLER diaktifkan. Seperti yang dijelaskan di bagian sebelumnya, handler khusus bahasa dipanggil sebagai bagian dari pencarian handler pengecualian atau sebagai bagian dari proses 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 terjadi (dalam kasus handler pengecualian) atau konteks "pembatalan" 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__try/__except 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 pointer ke entri fungsi RUNTIME_FUNCTION yang memuat alamat relatif basis gambar untuk fungsi dan informasi unwind dari 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/pembongkaran pengecualian sistem.
LanguageHandler menunjuk ke rutinitas penanganan yang spesifik untuk bahasa yang dipanggil.
HandlerData menunjuk ke data handler khusus bahasa untuk fungsi ini.
Fungsi pembantu pembongkaran 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 dasar
| Operasi Pseudo | Deskripsi |
|---|---|
| PROC FRAME [:ehandler] | Menyebabkan MASM menghasilkan entri tabel fungsi dalam .pdata dan informasi unwind dalam .xdata untuk penanganan pengecualian terstruktur dari perilaku unwind fungsi. Jika ehandler ada, proc ini dimasukkan dalam .xdata sebagai handler khusus bahasa. Ketika atribut FRAME digunakan, harus diikuti oleh direktif .ENDPROLOG. Jika fungsi adalah fungsi daun (seperti yang didefinisikan dalam Jenis Fungsi) atribut FRAME tidak diperlukan, begitu pula dengan sisa operasi pseudo ini. |
| .PUSHREG register | Menghasilkan entri kode unwind UWOP_PUSH_NONVOL untuk nomor register yang ditentukan dengan menggunakan offset saat ini dalam prolog. Hanya gunakan dengan register bilangan bulat tak-berubah. Untuk dorongan register volatil, gunakan . ALLOCSTACK 8, sebagai gantinya |
| . SETFRAME register, offset | Mengisi kolom register bingkai dan offset dalam informasi unwind menggunakan register dan offset yang telah 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. |
| .ALLOCSTACK Ukuran | Menghasilkan UWOP_ALLOC_SMALL atau UWOP_ALLOC_LARGE dengan ukuran yang ditentukan untuk offset saat ini dalam prolog. Operand ukuran harus merupakan kelipatan dari 8. |
| .SAVEREG register, offset | Menghasilkan entri kode unwind UWOP_SAVE_NONVOL atau UWOP_SAVE_NONVOL_FAR untuk register dan offset yang ditentukan dengan menggunakan offset prolog saat ini. MASM memilih pengodean yang paling efisien. offset harus positif, dan merupakan bilangan yang merupakan 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 ter-efisien. offset harus positif dan merupakan 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 diberi pengubah sebesar 1. Jika tidak, pengubah adalah 0. |
| . ENDPROLOG | Menandakan akhir deklarasi prolog. Harus ada 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 pseudo-operasi Mentah, ada sekumpulan makro, yang didefinisikan dalam ksamd64.inc, yang dapat digunakan untuk membuat prolog prosedur standar dan epilog.
| Makro | Deskripsi |
|---|---|
| alloc_stack(n) | Mengalokasikan bingkai stack sejumlah n byte (menggunakan sub rsp, n), dan menghasilkan informasi unwind yang sesuai (.allocstack n) |
| save_reg reg, loc | Menyimpan register reg nonvolatile pada tumpukan di offset RSP loc, dan menghasilkan informasi unwind yang sesuai. (.savereg reg, loc) |
| push_reg reg | Mendorong register nonvolatile reg pada tumpukan, dan mengeluarkan informasi pemulihan yang sesuai. (.pushreg reg) |
| rex_push_reg reg | Menyimpan register nonvolatile pada tumpukan menggunakan dorongan 2 byte, dan mengeluarkan informasi unwind yang sesuai (.pushreg reg). Gunakan makro ini jika push adalah instruksi pertama dalam fungsi, untuk memastikan bahwa fungsi bisa di-hot-patch. |
| save_xmm128 reg, loc | Menyimpan register XMM nonvolatile pada tumpukan di offset RSP di loc |
| set_frame reg, offset | Mengatur register bingkai reg menjadi RSP + offset (menggunakan mov, atau lea), dan mengeluarkan informasi pembatalan yang sesuai (.set_frame reg, offset) |
| push_eflags | Mendorong eflags dengan instruksi pushfq, dan menghasilkan informasi pembatalan 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
Membongkar 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))